1 // Written in the D programming language
2 
3 /++
4 
5 $(SCRIPT inhibitQuickIndex = 1;)
6 $(DIVC quickindex,
7 $(BOOKTABLE,
8 $(TR $(TH Category) $(TH Functions))
9 $(TR $(TD Types) $(TD
10     $(LREF Clock)
11     $(LREF SysTime)
12     $(LREF DosFileTime)
13 ))
14 $(TR $(TD Conversion) $(TD
15     $(LREF parseRFC822DateTime)
16     $(LREF DosFileTimeToSysTime)
17     $(LREF FILETIMEToStdTime)
18     $(LREF FILETIMEToSysTime)
19     $(LREF stdTimeToFILETIME)
20     $(LREF stdTimeToUnixTime)
21     $(LREF SYSTEMTIMEToSysTime)
22     $(LREF SysTimeToDosFileTime)
23     $(LREF SysTimeToFILETIME)
24     $(LREF SysTimeToSYSTEMTIME)
25     $(LREF unixTimeToStdTime)
26 ))
27 ))
28 
29     License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
30     Authors:   $(HTTP jmdavisprog.com, Jonathan M Davis)
31     Source:    $(PHOBOSSRC std/datetime/systime.d)
32 +/
33 module std.datetime.systime;
34 
35 version (OSX)
36     version = Darwin;
37 else version (iOS)
38     version = Darwin;
39 else version (TVOS)
40     version = Darwin;
41 else version (WatchOS)
42     version = Darwin;
43 
44 /// Get the current time as a $(LREF SysTime)
45 @safe unittest
46 {
47     import std.datetime.timezone : LocalTime;
48     SysTime today = Clock.currTime();
49     assert(today.timezone is LocalTime());
50 }
51 
52 /// Construct a $(LREF SysTime) from a ISO time string
53 @safe unittest
54 {
55     import std.datetime.date : DateTime;
56     import std.datetime.timezone : UTC;
57 
58     auto st = SysTime.fromISOExtString("2018-01-01T10:30:00Z");
59     assert(st == SysTime(DateTime(2018, 1, 1, 10, 30, 0), UTC()));
60 }
61 
62 /// Make a specific point in time in the New York timezone
63 @safe unittest
64 {
65     import core.time : hours;
66     import std.datetime.date : DateTime;
67     import std.datetime.timezone : SimpleTimeZone;
68 
69     auto ny = SysTime(
70         DateTime(2018, 1, 1, 10, 30, 0),
71         new immutable SimpleTimeZone(-5.hours, "America/New_York")
72     );
73 
74     // ISO standard time strings
75     assert(ny.toISOString() == "20180101T103000-05:00");
76     assert(ny.toISOExtString() == "2018-01-01T10:30:00-05:00");
77 }
78 
79 // Note: reconsider using specific imports below after
80 // https://issues.dlang.org/show_bug.cgi?id=17630 has been fixed
81 import core.time;// : ClockType, convert, dur, Duration, seconds, TimeException;
82 import std.datetime.date;// : _monthNames, AllowDayOverflow, CmpTimeUnits, Date,
83     //DateTime, DateTimeException, DayOfWeek, enforceValid, getDayOfWeek, maxDay,
84     //Month, splitUnitsFromHNSecs, TimeOfDay, validTimeUnits, yearIsLeapYear;
85 import std.datetime.timezone;// : LocalTime, SimpleTimeZone, TimeZone, UTC;
86 import std.exception : enforce;
87 import std.format : format;
88 import std.range.primitives;
89 import std.traits : isIntegral, isSigned, isSomeString, isNarrowString;
90 
version(Windows)91 version (Windows)
92 {
93     import core.stdc.time : time_t;
94     import core.sys.windows.winbase;
95     import core.sys.windows.winnt;
96     import core.sys.windows.winsock2;
97 }
version(Posix)98 else version (Posix)
99 {
100     import core.sys.posix.signal : timespec;
101     import core.sys.posix.sys.types : time_t;
102 }
103 
version(StdUnittest)104 version (StdUnittest)
105 {
106     import core.exception : AssertError;
107     import std.exception : assertThrown;
108 }
109 
110 
111 @safe unittest
112 {
113     initializeTests();
114 }
115 
version(unittest)116 version (unittest) private bool clockSupported(ClockType c)
117 {
118     // Skip unsupported clocks on older linux kernels, assume that only
119     // CLOCK_MONOTONIC and CLOCK_REALTIME exist, as that is the lowest
120     // common denominator supported by all versions of Linux pre-2.6.12.
121     version (Linux_Pre_2639)
122         return c == ClockType.normal || c == ClockType.precise;
123     else
124         return true;
125 }
126 
127 /++
128     Effectively a namespace to make it clear that the methods it contains are
129     getting the time from the system clock. It cannot be instantiated.
130  +/
131 final class Clock
132 {
133 public:
134 
135     /++
136         Returns the current time in the given time zone.
137 
138         Params:
139             clockType = The $(REF ClockType, core,time) indicates which system
140                         clock to use to get the current time. Very few programs
141                         need to use anything other than the default.
142             tz = The time zone for the SysTime that's returned.
143 
144         Throws:
145             $(REF DateTimeException,std,datetime,date) if it fails to get the
146             time.
147       +/
148     static SysTime currTime(ClockType clockType = ClockType.normal)(immutable TimeZone tz = LocalTime()) @safe
149     {
150         return SysTime(currStdTime!clockType, tz);
151     }
152 
153     @safe unittest
154     {
155         import std.format : format;
156         import core.time;
157         assert(currTime().timezone is LocalTime());
158         assert(currTime(UTC()).timezone is UTC());
159 
160         // core.stdc.time.time does not always use unix time on Windows systems.
161         // In particular, dmc does not use unix time. If we can guarantee that
162         // the MS runtime uses unix time, then we may be able run this test
163         // then, but for now, we're just not going to run this test on Windows.
version(Posix)164         version (Posix)
165         {
166             static import core.stdc.time;
167             static import std.math;
168             immutable unixTimeD = currTime().toUnixTime();
169             immutable unixTimeC = core.stdc.time.time(null);
170             assert(std.math.abs(unixTimeC - unixTimeD) <= 2);
171         }
172 
173         auto norm1 = Clock.currTime;
174         auto norm2 = Clock.currTime(UTC());
175         assert(norm1 <= norm2, format("%s %s", norm1, norm2));
176         assert(abs(norm1 - norm2) <= seconds(2));
177 
178         import std.meta : AliasSeq;
179         static foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
180         {{
181             static if (clockSupported(ct))
182             {
183                 auto value1 = Clock.currTime!ct;
184                 auto value2 = Clock.currTime!ct(UTC());
185                 assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
186                 assert(abs(value1 - value2) <= seconds(2), format("ClockType.%s", ct));
187             }
188         }}
189     }
190 
191 
192     /++
193         Returns the number of hnsecs since midnight, January 1st, 1 A.D. for the
194         current time.
195 
196         Params:
197             clockType = The $(REF ClockType, core,time) indicates which system
198                         clock to use to get the current time. Very few programs
199                         need to use anything other than the default.
200 
201         Throws:
202             $(REF DateTimeException,std,datetime,date) if it fails to get the
203             time.
204       +/
205     static @property long currStdTime(ClockType clockType = ClockType.normal)() @trusted
206     {
207         static if (clockType != ClockType.coarse &&
208                    clockType != ClockType.normal &&
209                    clockType != ClockType.precise &&
210                    clockType != ClockType.second)
211         {
212             static assert(0, format("ClockType.%s is not supported by Clock.currTime or Clock.currStdTime", clockType));
213         }
214 
version(Windows)215         version (Windows)
216         {
217             FILETIME fileTime;
218             GetSystemTimeAsFileTime(&fileTime);
219             immutable result = FILETIMEToStdTime(&fileTime);
220             static if (clockType == ClockType.second)
221             {
222                 // Ideally, this would use core.std.time.time, but the C runtime
223                 // has to be using unix time for that to work, and that's not
224                 // guaranteed on Windows. Digital Mars does not use unix time.
225                 // MS may or may not. If it does, then this can be made to use
226                 // core.stdc.time for MS, but for now, we'll leave it like this.
227                 return convert!("seconds", "hnsecs")(convert!("hnsecs", "seconds")(result));
228             }
229             else
230                 return result;
231         }
version(Posix)232         else version (Posix)
233         {
234             static import core.stdc.time;
235             enum hnsecsToUnixEpoch = unixTimeToStdTime(0);
236 
237             version (Darwin)
238             {
239                 static if (clockType == ClockType.second)
240                     return unixTimeToStdTime(core.stdc.time.time(null));
241                 else
242                 {
243                     import core.sys.posix.sys.time : gettimeofday, timeval;
244                     timeval tv = void;
245                     // Posix gettimeofday called with a valid timeval address
246                     // and a null second parameter doesn't fail.
247                     gettimeofday(&tv, null);
248                     return convert!("seconds", "hnsecs")(tv.tv_sec) +
249                            tv.tv_usec * 10 +
250                            hnsecsToUnixEpoch;
251                 }
252             }
253             else version (linux)
254             {
255                 static if (clockType == ClockType.second)
256                     return unixTimeToStdTime(core.stdc.time.time(null));
257                 else
258                 {
259                     import core.sys.linux.time : CLOCK_REALTIME_COARSE;
260                     import core.sys.posix.time : clock_gettime, CLOCK_REALTIME;
261                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_COARSE;
262                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
263                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
264                     else static assert(0, "Previous static if is wrong.");
265                     timespec ts = void;
266                     immutable error = clock_gettime(clockArg, &ts);
267                     // Posix clock_gettime called with a valid address and valid clock_id is only
268                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
269                     // is long or larger overflow won't happen before 292 billion years A.D.
270                     static if (ts.tv_sec.max < long.max)
271                     {
272                         if (error)
273                             throw new TimeException("Call to clock_gettime() failed");
274                     }
275                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
276                            ts.tv_nsec / 100 +
277                            hnsecsToUnixEpoch;
278                 }
279             }
280             else version (FreeBSD)
281             {
282                 import core.sys.freebsd.time : clock_gettime, CLOCK_REALTIME,
283                     CLOCK_REALTIME_FAST, CLOCK_REALTIME_PRECISE, CLOCK_SECOND;
284                 static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_FAST;
285                 else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
286                 else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE;
287                 else static if (clockType == ClockType.second)  alias clockArg = CLOCK_SECOND;
288                 else static assert(0, "Previous static if is wrong.");
289                 timespec ts = void;
290                 immutable error = clock_gettime(clockArg, &ts);
291                 // Posix clock_gettime called with a valid address and valid clock_id is only
292                 // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
293                 // is long or larger overflow won't happen before 292 billion years A.D.
294                 static if (ts.tv_sec.max < long.max)
295                 {
296                     if (error)
297                         throw new TimeException("Call to clock_gettime() failed");
298                 }
299                 return convert!("seconds", "hnsecs")(ts.tv_sec) +
300                        ts.tv_nsec / 100 +
301                        hnsecsToUnixEpoch;
302             }
303             else version (NetBSD)
304             {
305                 static if (clockType == ClockType.second)
306                     return unixTimeToStdTime(core.stdc.time.time(null));
307                 else
308                 {
309                     import core.sys.netbsd.time : clock_gettime, CLOCK_REALTIME;
310                     timespec ts = void;
311                     immutable error = clock_gettime(CLOCK_REALTIME, &ts);
312                     // Posix clock_gettime called with a valid address and valid clock_id is only
313                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
314                     // is long or larger overflow won't happen before 292 billion years A.D.
315                     static if (ts.tv_sec.max < long.max)
316                     {
317                         if (error)
318                             throw new TimeException("Call to clock_gettime() failed");
319                     }
320                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
321                            ts.tv_nsec / 100 +
322                            hnsecsToUnixEpoch;
323                 }
324             }
325             else version (OpenBSD)
326             {
327                 static if (clockType == ClockType.second)
328                     return unixTimeToStdTime(core.stdc.time.time(null));
329                 else
330                 {
331                     import core.sys.openbsd.time : clock_gettime, CLOCK_REALTIME;
332                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME;
333                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
334                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
335                     else static assert(0, "Previous static if is wrong.");
336                     timespec ts;
337                     if (clock_gettime(clockArg, &ts) != 0)
338                         throw new TimeException("Call to clock_gettime() failed");
339                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
340                            ts.tv_nsec / 100 +
341                            hnsecsToUnixEpoch;
342                 }
343             }
344             else version (DragonFlyBSD)
345             {
346                 import core.sys.dragonflybsd.time : clock_gettime, CLOCK_REALTIME,
347                     CLOCK_REALTIME_FAST, CLOCK_REALTIME_PRECISE, CLOCK_SECOND;
348                 static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_FAST;
349                 else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
350                 else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE;
351                 else static if (clockType == ClockType.second)  alias clockArg = CLOCK_SECOND;
352                 else static assert(0, "Previous static if is wrong.");
353                 timespec ts = void;
354                 immutable error = clock_gettime(clockArg, &ts);
355                 // Posix clock_gettime called with a valid address and valid clock_id is only
356                 // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
357                 // is long or larger overflow won't happen before 292 billion years A.D.
358                 static if (ts.tv_sec.max < long.max)
359                 {
360                     if (error)
361                         throw new TimeException("Call to clock_gettime() failed");
362                 }
363                 return convert!("seconds", "hnsecs")(ts.tv_sec) +
364                        ts.tv_nsec / 100 +
365                        hnsecsToUnixEpoch;
366             }
367             else version (Solaris)
368             {
369                 static if (clockType == ClockType.second)
370                     return unixTimeToStdTime(core.stdc.time.time(null));
371                 else
372                 {
373                     import core.sys.solaris.time : clock_gettime, CLOCK_REALTIME;
374                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME;
375                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
376                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
377                     else static assert(0, "Previous static if is wrong.");
378                     timespec ts = void;
379                     immutable error = clock_gettime(clockArg, &ts);
380                     // Posix clock_gettime called with a valid address and valid clock_id is only
381                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
382                     // is long or larger overflow won't happen before 292 billion years A.D.
383                     static if (ts.tv_sec.max < long.max)
384                     {
385                         if (error)
386                             throw new TimeException("Call to clock_gettime() failed");
387                     }
388                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
389                            ts.tv_nsec / 100 +
390                            hnsecsToUnixEpoch;
391                 }
392             }
393             else static assert(0, "Unsupported OS");
394         }
395         else static assert(0, "Unsupported OS");
396     }
397 
398     @safe unittest
399     {
400         import std.format : format;
401         import std.math.algebraic : abs;
402         import std.meta : AliasSeq;
403         enum limit = convert!("seconds", "hnsecs")(2);
404 
405         auto norm1 = Clock.currStdTime;
406         auto norm2 = Clock.currStdTime;
407         assert(norm1 <= norm2, format("%s %s", norm1, norm2));
408         assert(abs(norm1 - norm2) <= limit);
409 
410         static foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
411         {{
412             static if (clockSupported(ct))
413             {
414                 auto value1 = Clock.currStdTime!ct;
415                 auto value2 = Clock.currStdTime!ct;
416                 assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
417                 assert(abs(value1 - value2) <= limit);
418             }
419         }}
420     }
421 
422 
423 private:
424 
425     @disable this();
426 }
427 
428 /// Get the current time as a $(LREF SysTime)
429 @safe unittest
430 {
431     import std.datetime.timezone : LocalTime;
432     SysTime today = Clock.currTime();
433     assert(today.timezone is LocalTime());
434 }
435 
436 
437 /++
438     `SysTime` is the type used to get the current time from the
439     system or doing anything that involves time zones. Unlike
440     $(REF DateTime,std,datetime,date), the time zone is an integral part of
441     `SysTime` (though for local time applications, time zones can be ignored
442     and it will work, since it defaults to using the local time zone). It holds
443     its internal time in std time (hnsecs since midnight, January 1st, 1 A.D.
444     UTC), so it interfaces well with the system time. However, that means that,
445     unlike $(REF DateTime,std,datetime,date), it is not optimized for
446     calendar-based operations, and getting individual units from it such as
447     years or days is going to involve conversions and be less efficient.
448 
449     An $(I hnsec) (hecto-nanosecond) is 100 nanoseconds. There are 10,000,000 hnsecs in a second.
450 
451     For calendar-based operations that don't
452     care about time zones, then $(REF DateTime,std,datetime,date) would be
453     the type to use. For system time, use `SysTime`.
454 
455     $(LREF Clock.currTime) will return the current time as a `SysTime`.
456     To convert a `SysTime` to a $(REF Date,std,datetime,date) or
457     $(REF DateTime,std,datetime,date), simply cast it. To convert a
458     $(REF Date,std,datetime,date) or $(REF DateTime,std,datetime,date) to a
459     `SysTime`, use `SysTime`'s constructor, and pass in the intended time
460     zone with it (or don't pass in a $(REF TimeZone,std,datetime,timezone), and
461     the local time zone will be used). Be aware, however, that converting from a
462     $(REF DateTime,std,datetime,date) to a `SysTime` will not necessarily
463     be 100% accurate due to DST (one hour of the year doesn't exist and another
464     occurs twice). To not risk any conversion errors, keep times as
465     `SysTime`s. Aside from DST though, there shouldn't be any conversion
466     problems.
467 
468     For using time zones other than local time or UTC, use
469     $(REF PosixTimeZone,std,datetime,timezone) on Posix systems (or on Windows,
470     if providing the TZ Database files), and use
471     $(REF WindowsTimeZone,std,datetime,timezone) on Windows systems. The time in
472     `SysTime` is kept internally in hnsecs from midnight, January 1st, 1 A.D.
473     UTC. Conversion error cannot happen when changing the time zone of a
474     `SysTime`. $(REF LocalTime,std,datetime,timezone) is the
475     $(REF TimeZone,std,datetime,timezone) class which represents the local time,
476     and `UTC` is the $(REF TimeZone,std,datetime,timezone) class which
477     represents UTC. `SysTime` uses $(REF LocalTime,std,datetime,timezone) if
478     no $(REF TimeZone,std,datetime,timezone) is provided. For more details on
479     time zones, see the documentation for $(REF TimeZone,std,datetime,timezone),
480     $(REF PosixTimeZone,std,datetime,timezone), and
481     $(REF WindowsTimeZone,std,datetime,timezone).
482 
483     `SysTime`'s range is from approximately 29,000 B.C. to approximately
484     29,000 A.D.
485   +/
486 struct SysTime
487 {
488     import core.stdc.time : tm;
489     version (Posix) import core.sys.posix.sys.time : timeval;
490     import std.typecons : Rebindable;
491 
492 public:
493 
494     /++
495         Params:
496             dateTime = The $(REF DateTime,std,datetime,date) to use to set
497                        this $(LREF SysTime)'s internal std time. As
498                        $(REF DateTime,std,datetime,date) has no concept of
499                        time zone, tz is used as its time zone.
500             tz       = The $(REF TimeZone,std,datetime,timezone) to use for this
501                        $(LREF SysTime). If null,
502                        $(REF LocalTime,std,datetime,timezone) will be used. The
503                        given $(REF DateTime,std,datetime,date) is assumed to
504                        be in the given time zone.
505       +/
506     this(DateTime dateTime, immutable TimeZone tz = null) @safe nothrow
507     {
508         try
509             this(dateTime, Duration.zero, tz);
510         catch (Exception e)
511             assert(0, "SysTime's constructor threw when it shouldn't have.");
512     }
513 
514     @safe unittest
515     {
testSysTime516         static void test(DateTime dt, immutable TimeZone tz, long expected)
517         {
518             auto sysTime = SysTime(dt, tz);
519             assert(sysTime._stdTime == expected);
520             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given DateTime: %s", dt));
521         }
522 
523         test(DateTime.init, UTC(), 0);
524         test(DateTime(1, 1, 1, 12, 30, 33), UTC(), 450_330_000_000L);
525         test(DateTime(0, 12, 31, 12, 30, 33), UTC(), -413_670_000_000L);
526         test(DateTime(1, 1, 1, 0, 0, 0), UTC(), 0);
527         test(DateTime(1, 1, 1, 0, 0, 1), UTC(), 10_000_000L);
528         test(DateTime(0, 12, 31, 23, 59, 59), UTC(), -10_000_000L);
529 
530         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(-60)), 36_000_000_000L);
531         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(Duration.zero), 0);
532         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(60)), -36_000_000_000L);
533 
534         static void testScope(scope ref DateTime dt) @safe
535         {
536             auto st = SysTime(dt);
537         }
538     }
539 
540     /++
541         Params:
542             dateTime = The $(REF DateTime,std,datetime,date) to use to set
543                        this $(LREF SysTime)'s internal std time. As
544                        $(REF DateTime,std,datetime,date) has no concept of
545                        time zone, tz is used as its time zone.
546             fracSecs = The fractional seconds portion of the time.
547             tz       = The $(REF TimeZone,std,datetime,timezone) to use for this
548                        $(LREF SysTime). If null,
549                        $(REF LocalTime,std,datetime,timezone) will be used. The
550                        given $(REF DateTime,std,datetime,date) is assumed to
551                        be in the given time zone.
552 
553         Throws:
554             $(REF DateTimeException,std,datetime,date) if `fracSecs` is negative or if it's
555             greater than or equal to one second.
556       +/
557     this(DateTime dateTime, Duration fracSecs, immutable TimeZone tz = null) @safe
558     {
559         enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
560         enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
561         auto nonNullTZ = tz is null ? LocalTime() : tz;
562 
563         immutable dateDiff = dateTime.date - Date.init;
564         immutable todDiff = dateTime.timeOfDay - TimeOfDay.init;
565 
566         immutable adjustedTime = dateDiff + todDiff + fracSecs;
567         immutable standardTime = nonNullTZ.tzToUTC(adjustedTime.total!"hnsecs");
568 
569         this(standardTime, nonNullTZ);
570     }
571 
572     @safe unittest
573     {
574         import core.time;
575         static void test(DateTime dt, Duration fracSecs, immutable TimeZone tz, long expected)
576         {
577             auto sysTime = SysTime(dt, fracSecs, tz);
578             assert(sysTime._stdTime == expected);
579             assert(sysTime._timezone is (tz is null ? LocalTime() : tz),
580                    format("Given DateTime: %s, Given Duration: %s", dt, fracSecs));
581         }
582 
583         test(DateTime.init, Duration.zero, UTC(), 0);
584         test(DateTime(1, 1, 1, 12, 30, 33), Duration.zero, UTC(), 450_330_000_000L);
585         test(DateTime(0, 12, 31, 12, 30, 33), Duration.zero, UTC(), -413_670_000_000L);
586         test(DateTime(1, 1, 1, 0, 0, 0), msecs(1), UTC(), 10_000L);
587         test(DateTime(0, 12, 31, 23, 59, 59), msecs(999), UTC(), -10_000L);
588 
589         test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC(), -1);
590         test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC(), -9_999_999);
591         test(DateTime(0, 12, 31, 23, 59, 59), Duration.zero, UTC(), -10_000_000);
592 
593         assertThrown!DateTimeException(SysTime(DateTime.init, hnsecs(-1), UTC()));
594         assertThrown!DateTimeException(SysTime(DateTime.init, seconds(1), UTC()));
595 
596         static void testScope(scope ref DateTime dt, scope ref Duration d) @safe
597         {
598             auto st = SysTime(dt, d);
599         }
600     }
601 
602     /++
603         Params:
604             date = The $(REF Date,std,datetime,date) to use to set this
605                    $(LREF SysTime)'s internal std time. As
606                    $(REF Date,std,datetime,date) has no concept of time zone, tz
607                    is used as its time zone.
608             tz   = The $(REF TimeZone,std,datetime,timezone) to use for this
609                    $(LREF SysTime). If null,
610                    $(REF LocalTime,std,datetime,timezone) will be used. The
611                    given $(REF Date,std,datetime,date) is assumed to be in the
612                    given time zone.
613       +/
614     this(Date date, immutable TimeZone tz = null) @safe nothrow
615     {
616         _timezone = tz is null ? LocalTime() : tz;
617 
618         try
619         {
620             immutable adjustedTime = (date - Date(1, 1, 1)).total!"hnsecs";
621             immutable standardTime = _timezone.tzToUTC(adjustedTime);
622 
623             this(standardTime, _timezone);
624         }
625         catch (Exception e)
626             assert(0, "Date's constructor through when it shouldn't have.");
627     }
628 
629     @safe unittest
630     {
testSysTime631         static void test(Date d, immutable TimeZone tz, long expected)
632         {
633             auto sysTime = SysTime(d, tz);
634             assert(sysTime._stdTime == expected);
635             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given Date: %s", d));
636         }
637 
638         test(Date.init, UTC(), 0);
639         test(Date(1, 1, 1), UTC(), 0);
640         test(Date(1, 1, 2), UTC(), 864000000000);
641         test(Date(0, 12, 31), UTC(), -864000000000);
642 
testScopeSysTime643         static void testScope(scope ref Date d) @safe
644         {
645             auto st = SysTime(d);
646         }
647     }
648 
649     /++
650         Note:
651             Whereas the other constructors take in the given date/time, assume
652             that it's in the given time zone, and convert it to hnsecs in UTC
653             since midnight, January 1st, 1 A.D. UTC - i.e. std time - this
654             constructor takes a std time, which is specifically already in UTC,
655             so no conversion takes place. Of course, the various getter
656             properties and functions will use the given time zone's conversion
657             function to convert the results to that time zone, but no conversion
658             of the arguments to this constructor takes place.
659 
660         Params:
661             stdTime = The number of hnsecs since midnight, January 1st, 1 A.D.
662                       UTC.
663             tz      = The $(REF TimeZone,std,datetime,timezone) to use for this
664                       $(LREF SysTime). If null,
665                       $(REF LocalTime,std,datetime,timezone) will be used.
666       +/
667     this(long stdTime, immutable TimeZone tz = null) @safe pure nothrow
668     {
669         _stdTime = stdTime;
670         _timezone = tz is null ? LocalTime() : tz;
671     }
672 
673     @safe unittest
674     {
testSysTime675         static void test(long stdTime, immutable TimeZone tz)
676         {
677             auto sysTime = SysTime(stdTime, tz);
678             assert(sysTime._stdTime == stdTime);
679             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given stdTime: %s", stdTime));
680         }
681 
foreachSysTime682         foreach (stdTime; [-1234567890L, -250, 0, 250, 1235657390L])
683         {
684             foreach (tz; testTZs)
685                 test(stdTime, tz);
686         }
687     }
688 
689 
690     /++
691         Params:
692             rhs = The $(LREF SysTime) to assign to this one.
693 
694         Returns: The `this` of this `SysTime`.
695       +/
696     ref SysTime opAssign()(auto ref const(SysTime) rhs) return @safe pure nothrow scope
697     {
698         _stdTime = rhs._stdTime;
699         _timezone = rhs._timezone;
700         return this;
701     }
702 
703     @safe unittest
704     {
705         SysTime st;
706         st = SysTime(DateTime(2012, 12, 21, 1, 2, 3), UTC());
707         assert(st == SysTime(DateTime(2012, 12, 21, 1, 2, 3), UTC()));
708 
709         const other = SysTime(DateTime(19, 1, 7, 13, 14, 15), LocalTime());
710         st = other;
711         assert(st == other);
712 
713         static void testScope(scope ref SysTime left, const scope SysTime right) @safe
714         {
715             left = right;
716         }
717     }
718 
719 
720     /++
721         Checks for equality between this $(LREF SysTime) and the given
722         $(LREF SysTime).
723 
724         Note that the time zone is ignored. Only the internal
725         std times (which are in UTC) are compared.
726      +/
727     bool opEquals()(auto ref const(SysTime) rhs) @safe const pure nothrow scope
728     {
729         return _stdTime == rhs._stdTime;
730     }
731 
732     @safe unittest
733     {
734         import std.range : chain;
735 
736         assert(SysTime(DateTime.init, UTC()) == SysTime(0, UTC()));
737         assert(SysTime(DateTime.init, UTC()) == SysTime(0));
738         assert(SysTime(Date.init, UTC()) == SysTime(0));
739         assert(SysTime(0) == SysTime(0));
740 
741         static void test(DateTime dt, immutable TimeZone tz1, immutable TimeZone tz2)
742         {
743             auto st1 = SysTime(dt);
744             st1.timezone = tz1;
745 
746             auto st2 = SysTime(dt);
747             st2.timezone = tz2;
748 
749             assert(st1 == st2);
750         }
751 
752         foreach (tz1; testTZs)
753         {
754             foreach (tz2; testTZs)
755             {
756                 foreach (dt; chain(testDateTimesBC, testDateTimesAD))
757                     test(dt, tz1, tz2);
758             }
759         }
760 
761         auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
762         const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
763         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
764         assert(st == st);
765         assert(st == cst);
766         assert(st == ist);
767         assert(cst == st);
768         assert(cst == cst);
769         assert(cst == ist);
770         assert(ist == st);
771         assert(ist == cst);
772         assert(ist == ist);
773 
774         static void testScope(scope ref SysTime left, const scope SysTime right) @safe
775         {
776             assert(left == right);
777             assert(right == left);
778         }
779     }
780 
781 
782     /++
783         Compares this $(LREF SysTime) with the given $(LREF SysTime).
784 
785         Time zone is irrelevant when comparing $(LREF SysTime)s.
786 
787         Returns:
788             $(BOOKTABLE,
789             $(TR $(TD this &lt; rhs) $(TD &lt; 0))
790             $(TR $(TD this == rhs) $(TD 0))
791             $(TR $(TD this &gt; rhs) $(TD &gt; 0))
792             )
793      +/
794     int opCmp()(auto ref const(SysTime) rhs) @safe const pure nothrow scope
795     {
796         if (_stdTime < rhs._stdTime)
797             return -1;
798         if (_stdTime > rhs._stdTime)
799             return 1;
800         return 0;
801     }
802 
803     @safe unittest
804     {
805         import std.algorithm.iteration : map;
806         import std.array : array;
807         import std.range : chain;
808 
809         assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0, UTC())) == 0);
810         assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0)) == 0);
811         assert(SysTime(Date.init, UTC()).opCmp(SysTime(0)) == 0);
812         assert(SysTime(0).opCmp(SysTime(0)) == 0);
813 
814         static void testEqual(SysTime st, immutable TimeZone tz1, immutable TimeZone tz2)
815         {
816             auto st1 = st;
817             st1.timezone = tz1;
818 
819             auto st2 = st;
820             st2.timezone = tz2;
821 
822             assert(st1.opCmp(st2) == 0);
823         }
824 
825         auto sts = array(map!SysTime(chain(testDateTimesBC, testDateTimesAD)));
826 
827         foreach (st; sts)
828         {
829             foreach (tz1; testTZs)
830             {
831                 foreach (tz2; testTZs)
832                     testEqual(st, tz1, tz2);
833             }
834         }
835 
836         static void testCmp(SysTime st1, immutable TimeZone tz1, SysTime st2, immutable TimeZone tz2)
837         {
838             st1.timezone = tz1;
839             st2.timezone = tz2;
840             assert(st1.opCmp(st2) < 0);
841             assert(st2.opCmp(st1) > 0);
842         }
843 
844         foreach (si, st1; sts)
845         {
846             foreach (st2; sts[si + 1 .. $])
847             {
848                 foreach (tz1; testTZs)
849                 {
850                     foreach (tz2; testTZs)
851                         testCmp(st1, tz1, st2, tz2);
852                 }
853             }
854         }
855 
856         auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
857         const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
858         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
859         assert(st.opCmp(st) == 0);
860         assert(st.opCmp(cst) == 0);
861         assert(st.opCmp(ist) == 0);
862         assert(cst.opCmp(st) == 0);
863         assert(cst.opCmp(cst) == 0);
864         assert(cst.opCmp(ist) == 0);
865         assert(ist.opCmp(st) == 0);
866         assert(ist.opCmp(cst) == 0);
867         assert(ist.opCmp(ist) == 0);
868 
869         static void testScope(scope ref SysTime left, const scope SysTime right) @safe
870         {
871             assert(left < right);
872             assert(right > left);
873         }
874     }
875 
876 
877     /++
878         Returns: A hash of the $(LREF SysTime).
879      +/
880     size_t toHash() const @nogc pure nothrow @safe scope
881     {
882         static if (is(size_t == ulong))
883             return _stdTime;
884         else
885         {
886             // MurmurHash2
887             enum ulong m = 0xc6a4a7935bd1e995UL;
888             enum ulong n = m * 16;
889             enum uint r = 47;
890 
891             ulong k = _stdTime;
892             k *= m;
893             k ^= k >> r;
894             k *= m;
895 
896             ulong h = n;
897             h ^= k;
898             h *= m;
899 
900             return cast(size_t) h;
901         }
902     }
903 
904     @safe unittest
905     {
906         assert(SysTime(0).toHash == SysTime(0).toHash);
907         assert(SysTime(DateTime(2000, 1, 1)).toHash == SysTime(DateTime(2000, 1, 1)).toHash);
908         assert(SysTime(DateTime(2000, 1, 1)).toHash != SysTime(DateTime(2000, 1, 2)).toHash);
909 
910         // test that timezones aren't taken into account
911         assert(SysTime(0, LocalTime()).toHash == SysTime(0, LocalTime()).toHash);
912         assert(SysTime(0, LocalTime()).toHash == SysTime(0, UTC()).toHash);
913         assert(SysTime(DateTime(2000, 1, 1), LocalTime()).toHash == SysTime(DateTime(2000, 1, 1), LocalTime()).toHash);
914         immutable zone = new SimpleTimeZone(dur!"minutes"(60));
915         assert(SysTime(DateTime(2000, 1, 1, 1), zone).toHash == SysTime(DateTime(2000, 1, 1), UTC()).toHash);
916         assert(SysTime(DateTime(2000, 1, 1), zone).toHash != SysTime(DateTime(2000, 1, 1), UTC()).toHash);
917 
918         static void testScope(scope ref SysTime st) @safe
919         {
920             auto result = st.toHash();
921         }
922     }
923 
924 
925     /++
926         Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
927         are B.C.
928      +/
929     @property short year() @safe const nothrow scope
930     {
931         return (cast(Date) this).year;
932     }
933 
934     @safe unittest
935     {
936         import std.range : chain;
937         static void test(SysTime sysTime, long expected)
938         {
939             assert(sysTime.year == expected, format("Value given: %s", sysTime));
940         }
941 
942         test(SysTime(0, UTC()), 1);
943         test(SysTime(1, UTC()), 1);
944         test(SysTime(-1, UTC()), 0);
945 
946         foreach (year; chain(testYearsBC, testYearsAD))
947         {
948             foreach (md; testMonthDays)
949             {
950                 foreach (tod; testTODs)
951                 {
952                     auto dt = DateTime(Date(year, md.month, md.day), tod);
953                     foreach (tz; testTZs)
954                     {
955                         foreach (fs; testFracSecs)
956                             test(SysTime(dt, fs, tz), year);
957                     }
958                 }
959             }
960         }
961 
962         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
963         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
964         assert(cst.year == 1999);
965         assert(ist.year == 1999);
966 
967         static void testScope(scope ref SysTime st) @safe
968         {
969             auto result = st.year;
970         }
971     }
972 
973     /++
974         Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
975         are B.C.
976 
977         Params:
978             year = The year to set this $(LREF SysTime)'s year to.
979 
980         Throws:
981             $(REF DateTimeException,std,datetime,date) if the new year is not
982             a leap year and the resulting date would be on February 29th.
983      +/
984     @property void year(int year) @safe scope
985     {
986         auto hnsecs = adjTime;
987         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
988 
989         if (hnsecs < 0)
990         {
991             hnsecs += convert!("hours", "hnsecs")(24);
992             --days;
993         }
994 
995         auto date = Date(cast(int) days);
996         date.year = year;
997 
998         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
999         adjTime = newDaysHNSecs + hnsecs;
1000     }
1001 
1002     ///
1003     @safe unittest
1004     {
1005         import std.datetime.date : DateTime;
1006 
1007         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).year == 1999);
1008         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).year == 2010);
1009         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).year == -7);
1010     }
1011 
1012     @safe unittest
1013     {
1014         import std.range : chain;
1015 
1016         static void test(SysTime st, int year, SysTime expected)
1017         {
1018             st.year = year;
1019             assert(st == expected);
1020         }
1021 
1022         foreach (st; chain(testSysTimesBC, testSysTimesAD))
1023         {
1024             auto dt = cast(DateTime) st;
1025 
1026             foreach (year; chain(testYearsBC, testYearsAD))
1027             {
1028                 auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
1029                                  st.fracSecs,
1030                                  st.timezone);
1031                 test(st, year, e);
1032             }
1033         }
1034 
1035         foreach (fs; testFracSecs)
1036         {
1037             foreach (tz; testTZs)
1038             {
1039                 foreach (tod; testTODs)
1040                 {
1041                     test(SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz), 2000,
1042                          SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz));
1043                     test(SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz), 1999,
1044                          SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz));
1045                 }
1046 
1047                 foreach (tod; testTODsThrown)
1048                 {
1049                     auto st = SysTime(DateTime(Date(2000, 2, 29), tod), fs, tz);
1050                     assertThrown!DateTimeException(st.year = 1999);
1051                 }
1052             }
1053         }
1054 
1055         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1056         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1057         static assert(!__traits(compiles, cst.year = 7));
1058         static assert(!__traits(compiles, ist.year = 7));
1059 
1060         static void testScope(scope ref SysTime st) @safe
1061         {
1062             st.year = 42;
1063         }
1064     }
1065 
1066     /++
1067         Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
1068 
1069         Throws:
1070             $(REF DateTimeException,std,datetime,date) if `isAD` is true.
1071      +/
1072     @property ushort yearBC() @safe const scope
1073     {
1074         return (cast(Date) this).yearBC;
1075     }
1076 
1077     ///
1078     @safe unittest
1079     {
1080         import std.datetime.date : DateTime;
1081 
1082         assert(SysTime(DateTime(0, 1, 1, 12, 30, 33)).yearBC == 1);
1083         assert(SysTime(DateTime(-1, 1, 1, 10, 7, 2)).yearBC == 2);
1084         assert(SysTime(DateTime(-100, 1, 1, 4, 59, 0)).yearBC == 101);
1085     }
1086 
1087     @safe unittest
1088     {
1089         import std.exception : assertNotThrown;
1090         foreach (st; testSysTimesBC)
1091         {
1092             auto msg = format("SysTime: %s", st);
1093             assertNotThrown!DateTimeException(st.yearBC, msg);
1094             assert(st.yearBC == (st.year * -1) + 1, msg);
1095         }
1096 
1097         foreach (st; [testSysTimesAD[0], testSysTimesAD[$/2], testSysTimesAD[$-1]])
1098             assertThrown!DateTimeException(st.yearBC, format("SysTime: %s", st));
1099 
1100         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1101         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1102         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1103         st.year = 12;
1104         assert(st.year == 12);
1105         static assert(!__traits(compiles, cst.year = 12));
1106         static assert(!__traits(compiles, ist.year = 12));
1107 
1108         static void testScope(scope ref SysTime st) @safe
1109         {
1110             auto result = st.yearBC;
1111         }
1112     }
1113 
1114 
1115     /++
1116         Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
1117 
1118         Params:
1119             year = The year B.C. to set this $(LREF SysTime)'s year to.
1120 
1121         Throws:
1122             $(REF DateTimeException,std,datetime,date) if a non-positive value
1123             is given.
1124      +/
1125     @property void yearBC(int year) @safe scope
1126     {
1127         auto hnsecs = adjTime;
1128         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1129 
1130         if (hnsecs < 0)
1131         {
1132             hnsecs += convert!("hours", "hnsecs")(24);
1133             --days;
1134         }
1135 
1136         auto date = Date(cast(int) days);
1137         date.yearBC = year;
1138 
1139         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1140         adjTime = newDaysHNSecs + hnsecs;
1141     }
1142 
1143     @safe unittest
1144     {
1145         auto st = SysTime(DateTime(2010, 1, 1, 7, 30, 0));
1146         st.yearBC = 1;
1147         assert(st == SysTime(DateTime(0, 1, 1, 7, 30, 0)));
1148 
1149         st.yearBC = 10;
1150         assert(st == SysTime(DateTime(-9, 1, 1, 7, 30, 0)));
1151     }
1152 
1153     @safe unittest
1154     {
1155         import std.range : chain;
1156         static void test(SysTime st, int year, SysTime expected)
1157         {
1158             st.yearBC = year;
1159             assert(st == expected, format("SysTime: %s", st));
1160         }
1161 
1162         foreach (st; chain(testSysTimesBC, testSysTimesAD))
1163         {
1164             auto dt = cast(DateTime) st;
1165 
1166             foreach (year; testYearsBC)
1167             {
1168                 auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
1169                                  st.fracSecs,
1170                                  st.timezone);
1171                 test(st, (year * -1) + 1, e);
1172             }
1173         }
1174 
1175         foreach (st; [testSysTimesBC[0], testSysTimesBC[$ - 1], testSysTimesAD[0], testSysTimesAD[$ - 1]])
1176         {
1177             foreach (year; testYearsBC)
1178                 assertThrown!DateTimeException(st.yearBC = year);
1179         }
1180 
1181         foreach (fs; testFracSecs)
1182         {
1183             foreach (tz; testTZs)
1184             {
1185                 foreach (tod; testTODs)
1186                 {
1187                     test(SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz), 2001,
1188                          SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz));
1189                     test(SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz), 2000,
1190                          SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz));
1191                 }
1192 
1193                 foreach (tod; testTODsThrown)
1194                 {
1195                     auto st = SysTime(DateTime(Date(-2000, 2, 29), tod), fs, tz);
1196                     assertThrown!DateTimeException(st.year = -1999);
1197                 }
1198             }
1199         }
1200 
1201         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1202         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1203         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1204         st.yearBC = 12;
1205         assert(st.yearBC == 12);
1206         static assert(!__traits(compiles, cst.yearBC = 12));
1207         static assert(!__traits(compiles, ist.yearBC = 12));
1208 
1209         static void testScope(scope ref SysTime st) @safe
1210         {
1211             st.yearBC = 42;
1212         }
1213     }
1214 
1215 
1216     /++
1217         Month of a Gregorian Year.
1218      +/
1219     @property Month month() @safe const nothrow scope
1220     {
1221         return (cast(Date) this).month;
1222     }
1223 
1224     ///
1225     @safe unittest
1226     {
1227         import std.datetime.date : DateTime;
1228 
1229         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).month == 7);
1230         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).month == 10);
1231         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).month == 4);
1232     }
1233 
1234     @safe unittest
1235     {
1236         import std.range : chain;
1237 
1238         static void test(SysTime sysTime, Month expected)
1239         {
1240             assert(sysTime.month == expected, format("Value given: %s", sysTime));
1241         }
1242 
1243         test(SysTime(0, UTC()), Month.jan);
1244         test(SysTime(1, UTC()), Month.jan);
1245         test(SysTime(-1, UTC()), Month.dec);
1246 
1247         foreach (year; chain(testYearsBC, testYearsAD))
1248         {
1249             foreach (md; testMonthDays)
1250             {
1251                 foreach (tod; testTODs)
1252                 {
1253                     auto dt = DateTime(Date(year, md.month, md.day), tod);
1254                     foreach (fs; testFracSecs)
1255                     {
1256                         foreach (tz; testTZs)
1257                             test(SysTime(dt, fs, tz), md.month);
1258                     }
1259                 }
1260             }
1261         }
1262 
1263         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1264         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1265         assert(cst.month == 7);
1266         assert(ist.month == 7);
1267 
1268         static void testScope(scope ref SysTime st) @safe
1269         {
1270             auto result = st.month;
1271         }
1272     }
1273 
1274 
1275     /++
1276         Month of a Gregorian Year.
1277 
1278         Params:
1279             month = The month to set this $(LREF SysTime)'s month to.
1280 
1281         Throws:
1282             $(REF DateTimeException,std,datetime,date) if the given month is
1283             not a valid month.
1284      +/
1285     @property void month(Month month) @safe scope
1286     {
1287         auto hnsecs = adjTime;
1288         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1289 
1290         if (hnsecs < 0)
1291         {
1292             hnsecs += convert!("hours", "hnsecs")(24);
1293             --days;
1294         }
1295 
1296         auto date = Date(cast(int) days);
1297         date.month = month;
1298 
1299         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1300         adjTime = newDaysHNSecs + hnsecs;
1301     }
1302 
1303     @safe unittest
1304     {
1305         import std.algorithm.iteration : filter;
1306         import std.range : chain;
1307 
1308         static void test(SysTime st, Month month, SysTime expected)
1309         {
1310             st.month = cast(Month) month;
1311             assert(st == expected);
1312         }
1313 
1314         foreach (st; chain(testSysTimesBC, testSysTimesAD))
1315         {
1316             auto dt = cast(DateTime) st;
1317 
1318             foreach (md; testMonthDays)
1319             {
1320                 if (st.day > maxDay(dt.year, md.month))
1321                     continue;
1322                 auto e = SysTime(DateTime(dt.year, md.month, dt.day, dt.hour, dt.minute, dt.second),
1323                                  st.fracSecs,
1324                                  st.timezone);
1325                 test(st, md.month, e);
1326             }
1327         }
1328 
1329         foreach (fs; testFracSecs)
1330         {
1331             foreach (tz; testTZs)
1332             {
1333                 foreach (tod; testTODs)
1334                 {
1335                     foreach (year; filter!((a){return yearIsLeapYear(a);}) (chain(testYearsBC, testYearsAD)))
1336                     {
1337                         test(SysTime(DateTime(Date(year, 1, 29), tod), fs, tz),
1338                              Month.feb,
1339                              SysTime(DateTime(Date(year, 2, 29), tod), fs, tz));
1340                     }
1341 
1342                     foreach (year; chain(testYearsBC, testYearsAD))
1343                     {
1344                         test(SysTime(DateTime(Date(year, 1, 28), tod), fs, tz),
1345                              Month.feb,
1346                              SysTime(DateTime(Date(year, 2, 28), tod), fs, tz));
1347                         test(SysTime(DateTime(Date(year, 7, 30), tod), fs, tz),
1348                              Month.jun,
1349                              SysTime(DateTime(Date(year, 6, 30), tod), fs, tz));
1350                     }
1351                 }
1352             }
1353         }
1354 
1355         foreach (fs; [testFracSecs[0], testFracSecs[$-1]])
1356         {
1357             foreach (tz; testTZs)
1358             {
1359                 foreach (tod; testTODsThrown)
1360                 {
1361                     foreach (year; [testYearsBC[$-3], testYearsBC[$-2],
1362                                     testYearsBC[$-2], testYearsAD[0],
1363                                     testYearsAD[$-2], testYearsAD[$-1]])
1364                     {
1365                         auto day = yearIsLeapYear(year) ? 30 : 29;
1366                         auto st1 = SysTime(DateTime(Date(year, 1, day), tod), fs, tz);
1367                         assertThrown!DateTimeException(st1.month = Month.feb);
1368 
1369                         auto st2 = SysTime(DateTime(Date(year, 7, 31), tod), fs, tz);
1370                         assertThrown!DateTimeException(st2.month = Month.jun);
1371                     }
1372                 }
1373             }
1374         }
1375 
1376         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1377         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1378         static assert(!__traits(compiles, cst.month = Month.dec));
1379         static assert(!__traits(compiles, ist.month = Month.dec));
1380 
1381         static void testScope(scope ref SysTime st) @safe
1382         {
1383             st.month = Month.dec;
1384         }
1385     }
1386 
1387     /++
1388         Day of a Gregorian Month.
1389      +/
1390     @property ubyte day() @safe const nothrow scope
1391     {
1392         return (cast(Date) this).day;
1393     }
1394 
1395     ///
1396     @safe unittest
1397     {
1398         import std.datetime.date : DateTime;
1399 
1400         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).day == 6);
1401         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).day == 4);
1402         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).day == 5);
1403     }
1404 
1405     @safe unittest
1406     {
1407         import std.range : chain;
1408 
1409         static void test(SysTime sysTime, int expected)
1410         {
1411             assert(sysTime.day == expected, format("Value given: %s", sysTime));
1412         }
1413 
1414         test(SysTime(0, UTC()), 1);
1415         test(SysTime(1, UTC()), 1);
1416         test(SysTime(-1, UTC()), 31);
1417 
1418         foreach (year; chain(testYearsBC, testYearsAD))
1419         {
1420             foreach (md; testMonthDays)
1421             {
1422                 foreach (tod; testTODs)
1423                 {
1424                     auto dt = DateTime(Date(year, md.month, md.day), tod);
1425 
1426                     foreach (tz; testTZs)
1427                     {
1428                         foreach (fs; testFracSecs)
1429                             test(SysTime(dt, fs, tz), md.day);
1430                     }
1431                 }
1432             }
1433         }
1434 
1435         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1436         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1437          assert(cst.day == 6);
1438         assert(ist.day == 6);
1439 
1440         static void testScope(scope ref SysTime st) @safe
1441         {
1442             auto result = st.day;
1443         }
1444     }
1445 
1446 
1447     /++
1448         Day of a Gregorian Month.
1449 
1450         Params:
1451             day = The day of the month to set this $(LREF SysTime)'s day to.
1452 
1453         Throws:
1454             $(REF DateTimeException,std,datetime,date) if the given day is not
1455             a valid day of the current month.
1456      +/
1457     @property void day(int day) @safe scope
1458     {
1459         auto hnsecs = adjTime;
1460         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1461 
1462         if (hnsecs < 0)
1463         {
1464             hnsecs += convert!("hours", "hnsecs")(24);
1465             --days;
1466         }
1467 
1468         auto date = Date(cast(int) days);
1469         date.day = day;
1470 
1471         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1472         adjTime = newDaysHNSecs + hnsecs;
1473     }
1474 
1475     @safe unittest
1476     {
1477         import std.range : chain;
1478         import std.traits : EnumMembers;
1479 
1480         foreach (day; chain(testDays))
1481         {
1482             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1483             {
1484                 auto dt = cast(DateTime) st;
1485 
1486                 if (day > maxDay(dt.year, dt.month))
1487                     continue;
1488                 auto expected = SysTime(DateTime(dt.year, dt.month, day, dt.hour, dt.minute, dt.second),
1489                                         st.fracSecs,
1490                                         st.timezone);
1491                 st.day = day;
1492                 assert(st == expected, format("[%s] [%s]", st, expected));
1493             }
1494         }
1495 
1496         foreach (tz; testTZs)
1497         {
1498             foreach (tod; testTODs)
1499             {
1500                 foreach (fs; testFracSecs)
1501                 {
1502                     foreach (year; chain(testYearsBC, testYearsAD))
1503                     {
1504                         foreach (month; EnumMembers!Month)
1505                         {
1506                             auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz);
1507                             immutable max = maxDay(year, month);
1508                             auto expected = SysTime(DateTime(Date(year, month, max), tod), fs, tz);
1509 
1510                             st.day = max;
1511                             assert(st == expected, format("[%s] [%s]", st, expected));
1512                         }
1513                     }
1514                 }
1515             }
1516         }
1517 
1518         foreach (tz; testTZs)
1519         {
1520             foreach (tod; testTODsThrown)
1521             {
1522                 foreach (fs; [testFracSecs[0], testFracSecs[$-1]])
1523                 {
1524                     foreach (year; [testYearsBC[$-3], testYearsBC[$-2],
1525                                     testYearsBC[$-2], testYearsAD[0],
1526                                     testYearsAD[$-2], testYearsAD[$-1]])
1527                     {
1528                         foreach (month; EnumMembers!Month)
1529                         {
1530                             auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz);
1531                             immutable max = maxDay(year, month);
1532 
1533                             assertThrown!DateTimeException(st.day = max + 1);
1534                         }
1535                     }
1536                 }
1537             }
1538         }
1539 
1540         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1541         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1542         static assert(!__traits(compiles, cst.day = 27));
1543         static assert(!__traits(compiles, ist.day = 27));
1544 
1545         static void testScope(scope ref SysTime st) @safe
1546         {
1547             st.day = 12;
1548         }
1549     }
1550 
1551 
1552     /++
1553         Hours past midnight.
1554      +/
1555     @property ubyte hour() @safe const nothrow scope
1556     {
1557         auto hnsecs = adjTime;
1558         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1559 
1560         if (hnsecs < 0)
1561         {
1562             hnsecs += convert!("hours", "hnsecs")(24);
1563             --days;
1564         }
1565 
1566         return cast(ubyte) getUnitsFromHNSecs!"hours"(hnsecs);
1567     }
1568 
1569     @safe unittest
1570     {
1571         import std.range : chain;
1572 
1573         static void test(SysTime sysTime, int expected)
1574         {
1575             assert(sysTime.hour == expected, format("Value given: %s", sysTime));
1576         }
1577 
1578         test(SysTime(0, UTC()), 0);
1579         test(SysTime(1, UTC()), 0);
1580         test(SysTime(-1, UTC()), 23);
1581 
1582         foreach (tz; testTZs)
1583         {
1584             foreach (year; chain(testYearsBC, testYearsAD))
1585             {
1586                 foreach (md; testMonthDays)
1587                 {
1588                     foreach (hour; testHours)
1589                     {
1590                         foreach (minute; testMinSecs)
1591                         {
1592                             foreach (second; testMinSecs)
1593                             {
1594                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1595                                 foreach (fs; testFracSecs)
1596                                     test(SysTime(dt, fs, tz), hour);
1597                             }
1598                         }
1599                     }
1600                 }
1601             }
1602         }
1603 
1604         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1605         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1606         assert(cst.hour == 12);
1607         assert(ist.hour == 12);
1608 
1609         static void testScope(scope ref SysTime st) @safe
1610         {
1611             auto result = st.hour;
1612         }
1613     }
1614 
1615 
1616     /++
1617         Hours past midnight.
1618 
1619         Params:
1620             hour = The hours to set this $(LREF SysTime)'s hour to.
1621 
1622         Throws:
1623             $(REF DateTimeException,std,datetime,date) if the given hour are
1624             not a valid hour of the day.
1625      +/
1626     @property void hour(int hour) @safe scope
1627     {
1628         enforceValid!"hours"(hour);
1629 
1630         auto hnsecs = adjTime;
1631         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1632         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1633         immutable negative = hnsecs < 0;
1634 
1635         if (negative)
1636             hnsecs += convert!("hours", "hnsecs")(24);
1637 
1638         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1639         hnsecs += convert!("hours", "hnsecs")(hour);
1640 
1641         if (negative)
1642             hnsecs -= convert!("hours", "hnsecs")(24);
1643 
1644         adjTime = daysHNSecs + hnsecs;
1645     }
1646 
1647     @safe unittest
1648     {
1649         import std.range : chain;
1650 
1651         foreach (hour; chain(testHours))
1652         {
1653             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1654             {
1655                 auto dt = cast(DateTime) st;
1656                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, hour, dt.minute, dt.second),
1657                                         st.fracSecs,
1658                                         st.timezone);
1659                 st.hour = hour;
1660                 assert(st == expected, format("[%s] [%s]", st, expected));
1661             }
1662         }
1663 
1664         auto st = testSysTimesAD[0];
1665         assertThrown!DateTimeException(st.hour = -1);
1666         assertThrown!DateTimeException(st.hour = 60);
1667 
1668         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1669         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1670         static assert(!__traits(compiles, cst.hour = 27));
1671         static assert(!__traits(compiles, ist.hour = 27));
1672 
1673         static void testScope(scope ref SysTime st) @safe
1674         {
1675             st.hour = 12;
1676         }
1677     }
1678 
1679 
1680     /++
1681         Minutes past the current hour.
1682      +/
1683     @property ubyte minute() @safe const nothrow scope
1684     {
1685         auto hnsecs = adjTime;
1686         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1687 
1688         if (hnsecs < 0)
1689         {
1690             hnsecs += convert!("hours", "hnsecs")(24);
1691             --days;
1692         }
1693 
1694         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1695 
1696         return cast(ubyte) getUnitsFromHNSecs!"minutes"(hnsecs);
1697     }
1698 
1699     @safe unittest
1700     {
1701         import std.range : chain;
1702 
1703         static void test(SysTime sysTime, int expected)
1704         {
1705             assert(sysTime.minute == expected, format("Value given: %s", sysTime));
1706         }
1707 
1708         test(SysTime(0, UTC()), 0);
1709         test(SysTime(1, UTC()), 0);
1710         test(SysTime(-1, UTC()), 59);
1711 
1712         foreach (tz; testTZs)
1713         {
1714             foreach (year; chain(testYearsBC, testYearsAD))
1715             {
1716                 foreach (md; testMonthDays)
1717                 {
1718                     foreach (hour; testHours)
1719                     {
1720                         foreach (minute; testMinSecs)
1721                         {
1722                             foreach (second; testMinSecs)
1723                             {
1724                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1725                                 foreach (fs; testFracSecs)
1726                                     test(SysTime(dt, fs, tz), minute);
1727                             }
1728                         }
1729                     }
1730                 }
1731             }
1732         }
1733 
1734         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1735         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1736         assert(cst.minute == 30);
1737         assert(ist.minute == 30);
1738 
1739         static void testScope(scope ref SysTime st) @safe
1740         {
1741             auto result = st.minute;
1742         }
1743     }
1744 
1745 
1746     /++
1747         Minutes past the current hour.
1748 
1749         Params:
1750             minute = The minute to set this $(LREF SysTime)'s minute to.
1751 
1752         Throws:
1753             $(REF DateTimeException,std,datetime,date) if the given minute are
1754             not a valid minute of an hour.
1755      +/
1756     @property void minute(int minute) @safe scope
1757     {
1758         enforceValid!"minutes"(minute);
1759 
1760         auto hnsecs = adjTime;
1761         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1762         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1763         immutable negative = hnsecs < 0;
1764 
1765         if (negative)
1766             hnsecs += convert!("hours", "hnsecs")(24);
1767 
1768         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
1769         hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs);
1770 
1771         hnsecs += convert!("hours", "hnsecs")(hour);
1772         hnsecs += convert!("minutes", "hnsecs")(minute);
1773 
1774         if (negative)
1775             hnsecs -= convert!("hours", "hnsecs")(24);
1776 
1777         adjTime = daysHNSecs + hnsecs;
1778     }
1779 
1780     @safe unittest
1781     {
1782         import std.range : chain;
1783 
1784         foreach (minute; testMinSecs)
1785         {
1786             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1787             {
1788                 auto dt = cast(DateTime) st;
1789                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, minute, dt.second),
1790                                         st.fracSecs,
1791                                         st.timezone);
1792                 st.minute = minute;
1793                 assert(st == expected, format("[%s] [%s]", st, expected));
1794             }
1795         }
1796 
1797         auto st = testSysTimesAD[0];
1798         assertThrown!DateTimeException(st.minute = -1);
1799         assertThrown!DateTimeException(st.minute = 60);
1800 
1801         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1802         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1803         static assert(!__traits(compiles, cst.minute = 27));
1804         static assert(!__traits(compiles, ist.minute = 27));
1805 
1806         static void testScope(scope ref SysTime st) @safe
1807         {
1808             st.minute = 12;
1809         }
1810     }
1811 
1812 
1813     /++
1814         Seconds past the current minute.
1815      +/
1816     @property ubyte second() @safe const nothrow scope
1817     {
1818         auto hnsecs = adjTime;
1819         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1820 
1821         if (hnsecs < 0)
1822         {
1823             hnsecs += convert!("hours", "hnsecs")(24);
1824             --days;
1825         }
1826 
1827         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1828         hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs);
1829 
1830         return cast(ubyte) getUnitsFromHNSecs!"seconds"(hnsecs);
1831     }
1832 
1833     @safe unittest
1834     {
1835         import std.range : chain;
1836 
1837         static void test(SysTime sysTime, int expected)
1838         {
1839             assert(sysTime.second == expected, format("Value given: %s", sysTime));
1840         }
1841 
1842         test(SysTime(0, UTC()), 0);
1843         test(SysTime(1, UTC()), 0);
1844         test(SysTime(-1, UTC()), 59);
1845 
1846         foreach (tz; testTZs)
1847         {
1848             foreach (year; chain(testYearsBC, testYearsAD))
1849             {
1850                 foreach (md; testMonthDays)
1851                 {
1852                     foreach (hour; testHours)
1853                     {
1854                         foreach (minute; testMinSecs)
1855                         {
1856                             foreach (second; testMinSecs)
1857                             {
1858                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1859                                 foreach (fs; testFracSecs)
1860                                     test(SysTime(dt, fs, tz), second);
1861                             }
1862                         }
1863                     }
1864                 }
1865             }
1866         }
1867 
1868         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1869         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1870         assert(cst.second == 33);
1871         assert(ist.second == 33);
1872 
1873         static void testScope(scope ref SysTime st) @safe
1874         {
1875             auto result = st.second;
1876         }
1877     }
1878 
1879 
1880     /++
1881         Seconds past the current minute.
1882 
1883         Params:
1884             second = The second to set this $(LREF SysTime)'s second to.
1885 
1886         Throws:
1887             $(REF DateTimeException,std,datetime,date) if the given second are
1888             not a valid second of a minute.
1889      +/
1890     @property void second(int second) @safe scope
1891     {
1892         enforceValid!"seconds"(second);
1893 
1894         auto hnsecs = adjTime;
1895         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1896         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1897         immutable negative = hnsecs < 0;
1898 
1899         if (negative)
1900             hnsecs += convert!("hours", "hnsecs")(24);
1901 
1902         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
1903         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
1904         hnsecs = removeUnitsFromHNSecs!"seconds"(hnsecs);
1905 
1906         hnsecs += convert!("hours", "hnsecs")(hour);
1907         hnsecs += convert!("minutes", "hnsecs")(minute);
1908         hnsecs += convert!("seconds", "hnsecs")(second);
1909 
1910         if (negative)
1911             hnsecs -= convert!("hours", "hnsecs")(24);
1912 
1913         adjTime = daysHNSecs + hnsecs;
1914     }
1915 
1916     @safe unittest
1917     {
1918         import std.range : chain;
1919 
1920         foreach (second; testMinSecs)
1921         {
1922             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1923             {
1924                 auto dt = cast(DateTime) st;
1925                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, second),
1926                                         st.fracSecs,
1927                                         st.timezone);
1928                 st.second = second;
1929                 assert(st == expected, format("[%s] [%s]", st, expected));
1930             }
1931         }
1932 
1933         auto st = testSysTimesAD[0];
1934         assertThrown!DateTimeException(st.second = -1);
1935         assertThrown!DateTimeException(st.second = 60);
1936 
1937         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1938         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1939         static assert(!__traits(compiles, cst.seconds = 27));
1940         static assert(!__traits(compiles, ist.seconds = 27));
1941 
1942         static void testScope(scope ref SysTime st) @safe
1943         {
1944             st.second = 12;
1945         }
1946     }
1947 
1948 
1949     /++
1950         Fractional seconds past the second (i.e. the portion of a
1951         $(LREF SysTime) which is less than a second).
1952      +/
1953     @property Duration fracSecs() @safe const nothrow scope
1954     {
1955         auto hnsecs = removeUnitsFromHNSecs!"days"(adjTime);
1956 
1957         if (hnsecs < 0)
1958             hnsecs += convert!("hours", "hnsecs")(24);
1959 
1960         return dur!"hnsecs"(removeUnitsFromHNSecs!"seconds"(hnsecs));
1961     }
1962 
1963     ///
1964     @safe unittest
1965     {
1966         import core.time : msecs, usecs, hnsecs, nsecs;
1967         import std.datetime.date : DateTime;
1968 
1969         auto dt = DateTime(1982, 4, 1, 20, 59, 22);
1970         assert(SysTime(dt, msecs(213)).fracSecs == msecs(213));
1971         assert(SysTime(dt, usecs(5202)).fracSecs == usecs(5202));
1972         assert(SysTime(dt, hnsecs(1234567)).fracSecs == hnsecs(1234567));
1973 
1974         // SysTime and Duration both have a precision of hnsecs (100 ns),
1975         // so nsecs are going to be truncated.
1976         assert(SysTime(dt, nsecs(123456789)).fracSecs == nsecs(123456700));
1977     }
1978 
1979     @safe unittest
1980     {
1981         import std.range : chain;
1982         import core.time;
1983 
1984         assert(SysTime(0, UTC()).fracSecs == Duration.zero);
1985         assert(SysTime(1, UTC()).fracSecs == hnsecs(1));
1986         assert(SysTime(-1, UTC()).fracSecs == hnsecs(9_999_999));
1987 
1988         foreach (tz; testTZs)
1989         {
1990             foreach (year; chain(testYearsBC, testYearsAD))
1991             {
1992                 foreach (md; testMonthDays)
1993                 {
1994                     foreach (hour; testHours)
1995                     {
1996                         foreach (minute; testMinSecs)
1997                         {
1998                             foreach (second; testMinSecs)
1999                             {
2000                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
2001                                 foreach (fs; testFracSecs)
2002                                     assert(SysTime(dt, fs, tz).fracSecs == fs);
2003                             }
2004                         }
2005                     }
2006                 }
2007             }
2008         }
2009 
2010         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2011         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2012         assert(cst.fracSecs == Duration.zero);
2013         assert(ist.fracSecs == Duration.zero);
2014 
2015         static void testScope(scope ref SysTime st) @safe
2016         {
2017             auto result = st.fracSecs;
2018         }
2019     }
2020 
2021 
2022     /++
2023         Fractional seconds past the second (i.e. the portion of a
2024         $(LREF SysTime) which is less than a second).
2025 
2026         Params:
2027             fracSecs = The duration to set this $(LREF SysTime)'s fractional
2028                        seconds to.
2029 
2030         Throws:
2031             $(REF DateTimeException,std,datetime,date) if the given duration
2032             is negative or if it's greater than or equal to one second.
2033      +/
2034     @property void fracSecs(Duration fracSecs) @safe scope
2035     {
2036         enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
2037         enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
2038 
2039         auto oldHNSecs = adjTime;
2040         auto days = splitUnitsFromHNSecs!"days"(oldHNSecs);
2041         immutable daysHNSecs = convert!("days", "hnsecs")(days);
2042         immutable negative = oldHNSecs < 0;
2043 
2044         if (negative)
2045             oldHNSecs += convert!("hours", "hnsecs")(24);
2046 
2047         immutable seconds = splitUnitsFromHNSecs!"seconds"(oldHNSecs);
2048         immutable secondsHNSecs = convert!("seconds", "hnsecs")(seconds);
2049         auto newHNSecs = fracSecs.total!"hnsecs" + secondsHNSecs;
2050 
2051         if (negative)
2052             newHNSecs -= convert!("hours", "hnsecs")(24);
2053 
2054         adjTime = daysHNSecs + newHNSecs;
2055     }
2056 
2057     ///
2058     @safe unittest
2059     {
2060         import core.time : Duration, msecs, hnsecs, nsecs;
2061         import std.datetime.date : DateTime;
2062 
2063         auto st = SysTime(DateTime(1982, 4, 1, 20, 59, 22));
2064         assert(st.fracSecs == Duration.zero);
2065 
2066         st.fracSecs = msecs(213);
2067         assert(st.fracSecs == msecs(213));
2068 
2069         st.fracSecs = hnsecs(1234567);
2070         assert(st.fracSecs == hnsecs(1234567));
2071 
2072         // SysTime has a precision of hnsecs (100 ns), so nsecs are
2073         // going to be truncated.
2074         st.fracSecs = nsecs(123456789);
2075         assert(st.fracSecs == hnsecs(1234567));
2076     }
2077 
2078     @safe unittest
2079     {
2080         import std.range : chain;
2081         import core.time;
2082 
2083         foreach (fracSec; testFracSecs)
2084         {
2085             foreach (st; chain(testSysTimesBC, testSysTimesAD))
2086             {
2087                 auto dt = cast(DateTime) st;
2088                 auto expected = SysTime(dt, fracSec, st.timezone);
2089                 st.fracSecs = fracSec;
2090                 assert(st == expected, format("[%s] [%s]", st, expected));
2091             }
2092         }
2093 
2094         auto st = testSysTimesAD[0];
2095         assertThrown!DateTimeException(st.fracSecs = hnsecs(-1));
2096         assertThrown!DateTimeException(st.fracSecs = seconds(1));
2097 
2098         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2099         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2100         static assert(!__traits(compiles, cst.fracSecs = msecs(7)));
2101         static assert(!__traits(compiles, ist.fracSecs = msecs(7)));
2102 
2103         static void testScope(scope ref SysTime st) @safe
2104         {
2105             st.fracSecs = Duration.zero;
2106         }
2107     }
2108 
2109 
2110     /++
2111         The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the
2112         internal representation of $(LREF SysTime).
2113      +/
2114     @property long stdTime() @safe const pure nothrow scope @nogc
2115     {
2116         return _stdTime;
2117     }
2118 
2119     @safe unittest
2120     {
2121         import core.time;
2122         assert(SysTime(0).stdTime == 0);
2123         assert(SysTime(1).stdTime == 1);
2124         assert(SysTime(-1).stdTime == -1);
2125         assert(SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC()).stdTime == 330_000_502L);
2126         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC()).stdTime == 621_355_968_000_000_000L);
2127 
2128         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2129         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2130         assert(cst.stdTime > 0);
2131         assert(ist.stdTime > 0);
2132 
2133         static void testScope(scope ref SysTime st) @safe
2134         {
2135             auto result = st.stdTime;
2136         }
2137     }
2138 
2139 
2140     /++
2141         The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the
2142         internal representation of $(LREF SysTime).
2143 
2144         Params:
2145             stdTime = The number of hnsecs since January 1st, 1 A.D. UTC.
2146      +/
2147     @property void stdTime(long stdTime) @safe pure nothrow scope
2148     {
2149         _stdTime = stdTime;
2150     }
2151 
2152     @safe unittest
2153     {
2154         import core.time;
2155         static void test(long stdTime, SysTime expected, size_t line = __LINE__)
2156         {
2157             auto st = SysTime(0, UTC());
2158             st.stdTime = stdTime;
2159             assert(st == expected);
2160         }
2161 
2162         test(0, SysTime(Date(1, 1, 1), UTC()));
2163         test(1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()));
2164         test(-1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()));
2165         test(330_000_502L, SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC()));
2166         test(621_355_968_000_000_000L, SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC()));
2167 
2168         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2169         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2170         static assert(!__traits(compiles, cst.stdTime = 27));
2171         static assert(!__traits(compiles, ist.stdTime = 27));
2172 
2173         static void testScope(scope ref SysTime st) @safe
2174         {
2175             st.stdTime = 42;
2176         }
2177     }
2178 
2179 
2180     /++
2181         The current time zone of this $(LREF SysTime). Its internal time is
2182         always kept in UTC, so there are no conversion issues between time zones
2183         due to DST. Functions which return all or part of the time - such as
2184         hours - adjust the time to this $(LREF SysTime)'s time zone before
2185         returning.
2186       +/
2187     @property immutable(TimeZone) timezone() @safe const pure nothrow scope
2188     {
2189         return _timezone;
2190     }
2191 
2192     @safe unittest
2193     {
2194         assert(SysTime.init.timezone is InitTimeZone());
2195         assert(SysTime(DateTime.init, UTC()).timezone is UTC());
2196 
2197         static void testScope(scope ref SysTime st) @safe
2198         {
2199             auto result = st.timezone;
2200         }
2201     }
2202 
2203 
2204     /++
2205         The current time zone of this $(LREF SysTime). It's internal time is
2206         always kept in UTC, so there are no conversion issues between time zones
2207         due to DST. Functions which return all or part of the time - such as
2208         hours - adjust the time to this $(LREF SysTime)'s time zone before
2209         returning.
2210 
2211         Params:
2212             timezone = The $(REF _TimeZone,std,datetime,_timezone) to set this
2213                        $(LREF SysTime)'s time zone to.
2214       +/
2215     @property void timezone(immutable TimeZone timezone) @safe pure nothrow scope
2216     {
2217         if (timezone is null)
2218             _timezone = LocalTime();
2219         else
2220             _timezone = timezone;
2221     }
2222 
2223     @safe unittest
2224     {
2225         SysTime st;
2226         st.timezone = null;
2227         assert(st.timezone is LocalTime());
2228         st.timezone = UTC();
2229         assert(st.timezone is UTC());
2230 
2231         static void testScope(scope ref SysTime st) @safe
2232         {
2233             st.timezone = UTC();
2234         }
2235     }
2236 
2237 
2238     /++
2239         Returns whether DST is in effect for this $(LREF SysTime).
2240       +/
2241     @property bool dstInEffect() @safe const nothrow scope
2242     {
2243         return _timezone.dstInEffect(_stdTime);
2244     }
2245 
2246     // This function's full unit testing is done in the time zone classes, but
2247     // this verifies that SysTime.init works correctly, since historically, it
2248     // has segfaulted due to a null _timezone.
2249     @safe unittest
2250     {
2251         assert(!SysTime.init.dstInEffect);
2252 
2253         static void testScope(scope ref SysTime st) @safe
2254         {
2255             auto result = st.dstInEffect;
2256         }
2257     }
2258 
2259 
2260     /++
2261         Returns what the offset from UTC is for this $(LREF SysTime).
2262         It includes the DST offset in effect at that time (if any).
2263       +/
2264     @property Duration utcOffset() @safe const nothrow scope
2265     {
2266         return _timezone.utcOffsetAt(_stdTime);
2267     }
2268 
2269     // This function's full unit testing is done in the time zone classes, but
2270     // this verifies that SysTime.init works correctly, since historically, it
2271     // has segfaulted due to a null _timezone.
2272     @safe unittest
2273     {
2274         assert(SysTime.init.utcOffset == Duration.zero);
2275 
2276         static void testScope(scope ref SysTime st) @safe
2277         {
2278             auto result = st.utcOffset;
2279         }
2280     }
2281 
2282 
2283     /++
2284         Returns a $(LREF SysTime) with the same std time as this one, but with
2285         $(REF LocalTime,std,datetime,timezone) as its time zone.
2286       +/
2287     SysTime toLocalTime() @safe const pure nothrow scope
2288     {
2289         return SysTime(_stdTime, LocalTime());
2290     }
2291 
2292     @safe unittest
2293     {
2294         import core.time;
2295         {
2296             auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2297             assert(sysTime == sysTime.toLocalTime());
2298             assert(sysTime._stdTime == sysTime.toLocalTime()._stdTime);
2299             assert(sysTime.toLocalTime().timezone is LocalTime());
2300             assert(sysTime.toLocalTime().timezone is sysTime.timezone);
2301             assert(sysTime.toLocalTime().timezone !is UTC());
2302         }
2303 
2304         {
2305             auto stz = new immutable SimpleTimeZone(dur!"minutes"(-3 * 60));
2306             auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27), stz);
2307             assert(sysTime == sysTime.toLocalTime());
2308             assert(sysTime._stdTime == sysTime.toLocalTime()._stdTime);
2309             assert(sysTime.toLocalTime().timezone is LocalTime());
2310             assert(sysTime.toLocalTime().timezone !is UTC());
2311             assert(sysTime.toLocalTime().timezone !is stz);
2312         }
2313 
2314         static void testScope(scope ref SysTime st) @safe
2315         {
2316             auto result = st.toLocalTime();
2317         }
2318     }
2319 
2320 
2321     /++
2322         Returns a $(LREF SysTime) with the same std time as this one, but with
2323         `UTC` as its time zone.
2324       +/
2325     SysTime toUTC() @safe const pure nothrow scope
2326     {
2327         return SysTime(_stdTime, UTC());
2328     }
2329 
2330     @safe unittest
2331     {
2332         import core.time;
2333         auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2334         assert(sysTime == sysTime.toUTC());
2335         assert(sysTime._stdTime == sysTime.toUTC()._stdTime);
2336         assert(sysTime.toUTC().timezone is UTC());
2337         assert(sysTime.toUTC().timezone !is LocalTime());
2338         assert(sysTime.toUTC().timezone !is sysTime.timezone);
2339 
2340         static void testScope(scope ref SysTime st) @safe
2341         {
2342             auto result = st.toUTC();
2343         }
2344     }
2345 
2346 
2347     /++
2348         Returns a $(LREF SysTime) with the same std time as this one, but with
2349         given time zone as its time zone.
2350       +/
2351     SysTime toOtherTZ(immutable TimeZone tz) @safe const pure nothrow scope
2352     {
2353         if (tz is null)
2354             return SysTime(_stdTime, LocalTime());
2355         else
2356             return SysTime(_stdTime, tz);
2357     }
2358 
2359     @safe unittest
2360     {
2361         import core.time;
2362         auto stz = new immutable SimpleTimeZone(dur!"minutes"(11 * 60));
2363         auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2364         assert(sysTime == sysTime.toOtherTZ(stz));
2365         assert(sysTime._stdTime == sysTime.toOtherTZ(stz)._stdTime);
2366         assert(sysTime.toOtherTZ(stz).timezone is stz);
2367         assert(sysTime.toOtherTZ(stz).timezone !is LocalTime());
2368         assert(sysTime.toOtherTZ(stz).timezone !is UTC());
2369         assert(sysTime.toOtherTZ(null).timezone is LocalTime());
2370 
2371         static void testScope(scope ref SysTime st) @safe
2372         {
2373             auto result = st.toOtherTZ(null);
2374         }
2375     }
2376 
2377 
2378     /++
2379         Converts this $(LREF SysTime) to unix time (i.e. seconds from midnight,
2380         January 1st, 1970 in UTC).
2381 
2382         The C standard does not specify the representation of time_t, so it is
2383         implementation defined. On POSIX systems, unix time is equivalent to
2384         time_t, but that's not necessarily true on other systems (e.g. it is
2385         not true for the Digital Mars C runtime). So, be careful when using unix
2386         time with C functions on non-POSIX systems.
2387 
2388         By default, the return type is time_t (which is normally an alias for
2389         int on 32-bit systems and long on 64-bit systems), but if a different
2390         size is required than either int or long can be passed as a template
2391         argument to get the desired size.
2392 
2393         If the return type is int, and the result can't fit in an int, then the
2394         closest value that can be held in 32 bits will be used (so `int.max`
2395         if it goes over and `int.min` if it goes under). However, no attempt
2396         is made to deal with integer overflow if the return type is long.
2397 
2398         Params:
2399             T = The return type (int or long). It defaults to time_t, which is
2400                 normally 32 bits on a 32-bit system and 64 bits on a 64-bit
2401                 system.
2402 
2403         Returns:
2404             A signed integer representing the unix time which is equivalent to
2405             this SysTime.
2406       +/
2407     T toUnixTime(T = time_t)() @safe const pure nothrow scope
2408         if (is(T == int) || is(T == long))
2409     {
2410         return stdTimeToUnixTime!T(_stdTime);
2411     }
2412 
2413     ///
2414     @safe unittest
2415     {
2416         import core.time : hours;
2417         import std.datetime.date : DateTime;
2418         import std.datetime.timezone : SimpleTimeZone, UTC;
2419 
2420         assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0);
2421 
2422         auto pst = new immutable SimpleTimeZone(hours(-8));
2423         assert(SysTime(DateTime(1970, 1, 1), pst).toUnixTime() == 28800);
2424 
2425         auto utc = SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC());
2426         assert(utc.toUnixTime() == 1_198_311_285);
2427 
2428         auto ca = SysTime(DateTime(2007, 12, 22, 8, 14, 45), pst);
2429         assert(ca.toUnixTime() == 1_198_340_085);
2430 
2431         static void testScope(scope ref SysTime st) @safe
2432         {
2433             auto result = st.toUnixTime();
2434         }
2435     }
2436 
2437     @safe unittest
2438     {
2439         import std.meta : AliasSeq;
2440         import core.time;
2441         assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0);
2442         static foreach (units; ["hnsecs", "usecs", "msecs"])
2443             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), dur!units(1), UTC()).toUnixTime() == 0);
2444         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toUnixTime() == 1);
2445         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toUnixTime() == 0);
2446         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toUnixTime() == 0);
2447         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toUnixTime() == 0);
2448         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toUnixTime() == -1);
2449     }
2450 
2451 
2452     /++
2453         Converts from unix time (i.e. seconds from midnight, January 1st, 1970
2454         in UTC) to a $(LREF SysTime).
2455 
2456         The C standard does not specify the representation of time_t, so it is
2457         implementation defined. On POSIX systems, unix time is equivalent to
2458         time_t, but that's not necessarily true on other systems (e.g. it is
2459         not true for the Digital Mars C runtime). So, be careful when using unix
2460         time with C functions on non-POSIX systems.
2461 
2462         Params:
2463             unixTime = Seconds from midnight, January 1st, 1970 in UTC.
2464             tz = The time zone for the SysTime that's returned.
2465       +/
2466     static SysTime fromUnixTime(long unixTime, immutable TimeZone tz = LocalTime()) @safe pure nothrow
2467     {
2468         return SysTime(unixTimeToStdTime(unixTime), tz);
2469     }
2470 
2471     ///
2472     @safe unittest
2473     {
2474         import core.time : hours;
2475         import std.datetime.date : DateTime;
2476         import std.datetime.timezone : SimpleTimeZone, UTC;
2477 
2478         assert(SysTime.fromUnixTime(0) ==
2479                SysTime(DateTime(1970, 1, 1), UTC()));
2480 
2481         auto pst = new immutable SimpleTimeZone(hours(-8));
2482         assert(SysTime.fromUnixTime(28800) ==
2483                SysTime(DateTime(1970, 1, 1), pst));
2484 
2485         auto st1 = SysTime.fromUnixTime(1_198_311_285, UTC());
2486         assert(st1 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC()));
2487         assert(st1.timezone is UTC());
2488         assert(st1 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst));
2489 
2490         auto st2 = SysTime.fromUnixTime(1_198_311_285, pst);
2491         assert(st2 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC()));
2492         assert(st2.timezone is pst);
2493         assert(st2 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst));
2494     }
2495 
2496     @safe unittest
2497     {
2498         import core.time;
2499         assert(SysTime.fromUnixTime(0) == SysTime(DateTime(1970, 1, 1), UTC()));
2500         assert(SysTime.fromUnixTime(1) == SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()));
2501         assert(SysTime.fromUnixTime(-1) == SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()));
2502 
2503         auto st = SysTime.fromUnixTime(0);
2504         auto dt = cast(DateTime) st;
2505         assert(dt <= DateTime(1970, 2, 1) && dt >= DateTime(1969, 12, 31));
2506         assert(st.timezone is LocalTime());
2507 
2508         auto aest = new immutable SimpleTimeZone(hours(10));
2509         assert(SysTime.fromUnixTime(-36000) == SysTime(DateTime(1970, 1, 1), aest));
2510     }
2511 
2512 
2513     /++
2514         Returns a `timeval` which represents this $(LREF SysTime).
2515 
2516         Note that like all conversions in std.datetime, this is a truncating
2517         conversion.
2518 
2519         If `timeval.tv_sec` is int, and the result can't fit in an int, then
2520         the closest value that can be held in 32 bits will be used for
2521         `tv_sec`. (so `int.max` if it goes over and `int.min` if it
2522         goes under).
2523       +/
2524     timeval toTimeVal() @safe const pure nothrow scope
2525     {
2526         immutable tv_sec = toUnixTime!(typeof(timeval.tv_sec))();
2527         immutable fracHNSecs = removeUnitsFromHNSecs!"seconds"(_stdTime - 621_355_968_000_000_000L);
2528         immutable tv_usec = cast(typeof(timeval.tv_usec))convert!("hnsecs", "usecs")(fracHNSecs);
2529         return timeval(tv_sec, tv_usec);
2530     }
2531 
2532     @safe unittest
2533     {
2534         import core.time;
2535         assert(SysTime(DateTime(1970, 1, 1), UTC()).toTimeVal() == timeval(0, 0));
2536         assert(SysTime(DateTime(1970, 1, 1), hnsecs(9), UTC()).toTimeVal() == timeval(0, 0));
2537         assert(SysTime(DateTime(1970, 1, 1), hnsecs(10), UTC()).toTimeVal() == timeval(0, 1));
2538         assert(SysTime(DateTime(1970, 1, 1), usecs(7), UTC()).toTimeVal() == timeval(0, 7));
2539 
2540         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toTimeVal() == timeval(1, 0));
2541         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(9), UTC()).toTimeVal() == timeval(1, 0));
2542         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(10), UTC()).toTimeVal() == timeval(1, 1));
2543         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), usecs(7), UTC()).toTimeVal() == timeval(1, 7));
2544 
2545         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toTimeVal() == timeval(0, 0));
2546         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_990), UTC()).toTimeVal() == timeval(0, -1));
2547 
2548         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toTimeVal() == timeval(0, -1));
2549         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999), UTC()).toTimeVal() == timeval(0, -999_001));
2550         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toTimeVal() == timeval(0, -1000));
2551         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toTimeVal() == timeval(-1, 0));
2552         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 58), usecs(17), UTC()).toTimeVal() == timeval(-1, -999_983));
2553 
2554         static void testScope(scope ref SysTime st) @safe
2555         {
2556             auto result = st.toTimeVal();
2557         }
2558     }
2559 
2560 
2561     version (StdDdoc)
2562     {
2563         version (Windows) private struct timespec {}
2564         /++
2565             Returns a `timespec` which represents this $(LREF SysTime).
2566 
2567             $(BLUE This function is Posix-Only.)
2568           +/
2569         timespec toTimeSpec() @safe const pure nothrow scope;
2570     }
2571     else version (Posix)
2572     {
2573         timespec toTimeSpec() @safe const pure nothrow scope
2574         {
2575             immutable tv_sec = toUnixTime!(typeof(timespec.tv_sec))();
2576             immutable fracHNSecs = removeUnitsFromHNSecs!"seconds"(_stdTime - 621_355_968_000_000_000L);
2577             immutable tv_nsec = cast(typeof(timespec.tv_nsec))convert!("hnsecs", "nsecs")(fracHNSecs);
2578             return timespec(tv_sec, tv_nsec);
2579         }
2580 
2581         @safe unittest
2582         {
2583             import core.time;
2584             assert(SysTime(DateTime(1970, 1, 1), UTC()).toTimeSpec() == timespec(0, 0));
2585             assert(SysTime(DateTime(1970, 1, 1), hnsecs(9), UTC()).toTimeSpec() == timespec(0, 900));
2586             assert(SysTime(DateTime(1970, 1, 1), hnsecs(10), UTC()).toTimeSpec() == timespec(0, 1000));
2587             assert(SysTime(DateTime(1970, 1, 1), usecs(7), UTC()).toTimeSpec() == timespec(0, 7000));
2588 
2589             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toTimeSpec() == timespec(1, 0));
2590             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(9), UTC()).toTimeSpec() == timespec(1, 900));
2591             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(10), UTC()).toTimeSpec() == timespec(1, 1000));
2592             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), usecs(7), UTC()).toTimeSpec() == timespec(1, 7000));
2593 
2594             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toTimeSpec() ==
2595                    timespec(0, -100));
2596             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_990), UTC()).toTimeSpec() ==
2597                    timespec(0, -1000));
2598 
2599             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toTimeSpec() ==
2600                    timespec(0, -1_000));
2601             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999), UTC()).toTimeSpec() ==
2602                    timespec(0, -999_001_000));
2603             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toTimeSpec() ==
2604                    timespec(0, -1_000_000));
2605             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toTimeSpec() ==
2606                    timespec(-1, 0));
2607             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 58), usecs(17), UTC()).toTimeSpec() ==
2608                    timespec(-1, -999_983_000));
2609 
2610             static void testScope(scope ref SysTime st) @safe
2611             {
2612                 auto result = st.toTimeSpec();
2613             }
2614         }
2615     }
2616 
2617     /++
2618         Returns a `tm` which represents this $(LREF SysTime).
2619       +/
2620     tm toTM() @safe const nothrow scope
2621     {
2622         auto dateTime = cast(DateTime) this;
2623         tm timeInfo;
2624 
2625         timeInfo.tm_sec = dateTime.second;
2626         timeInfo.tm_min = dateTime.minute;
2627         timeInfo.tm_hour = dateTime.hour;
2628         timeInfo.tm_mday = dateTime.day;
2629         timeInfo.tm_mon = dateTime.month - 1;
2630         timeInfo.tm_year = dateTime.year - 1900;
2631         timeInfo.tm_wday = dateTime.dayOfWeek;
2632         timeInfo.tm_yday = dateTime.dayOfYear - 1;
2633         timeInfo.tm_isdst = _timezone.dstInEffect(_stdTime);
2634 
2635         version (Posix)
2636         {
2637             import std.utf : toUTFz;
2638             timeInfo.tm_gmtoff = cast(int) convert!("hnsecs", "seconds")(adjTime - _stdTime);
2639             auto zone = timeInfo.tm_isdst ? _timezone.dstName : _timezone.stdName;
2640             timeInfo.tm_zone = zone.toUTFz!(char*)();
2641         }
2642 
2643         return timeInfo;
2644     }
2645 
2646     @system unittest
2647     {
2648         import std.conv : to;
2649         import core.time;
2650 
2651         version (Posix)
2652         {
2653             import std.datetime.timezone : clearTZEnvVar, setTZEnvVar;
2654             setTZEnvVar("America/Los_Angeles");
2655             scope(exit) clearTZEnvVar();
2656         }
2657 
2658         {
2659             auto timeInfo = SysTime(DateTime(1970, 1, 1)).toTM();
2660 
2661             assert(timeInfo.tm_sec == 0);
2662             assert(timeInfo.tm_min == 0);
2663             assert(timeInfo.tm_hour == 0);
2664             assert(timeInfo.tm_mday == 1);
2665             assert(timeInfo.tm_mon == 0);
2666             assert(timeInfo.tm_year == 70);
2667             assert(timeInfo.tm_wday == 4);
2668             assert(timeInfo.tm_yday == 0);
2669 
2670             version (Posix)
2671                 assert(timeInfo.tm_isdst == 0);
2672             else version (Windows)
2673                 assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
2674 
2675             version (Posix)
2676             {
2677                 assert(timeInfo.tm_gmtoff == -8 * 60 * 60);
2678                 assert(to!string(timeInfo.tm_zone) == "PST");
2679             }
2680         }
2681 
2682         {
2683             auto timeInfo = SysTime(DateTime(2010, 7, 4, 12, 15, 7), hnsecs(15)).toTM();
2684 
2685             assert(timeInfo.tm_sec == 7);
2686             assert(timeInfo.tm_min == 15);
2687             assert(timeInfo.tm_hour == 12);
2688             assert(timeInfo.tm_mday == 4);
2689             assert(timeInfo.tm_mon == 6);
2690             assert(timeInfo.tm_year == 110);
2691             assert(timeInfo.tm_wday == 0);
2692             assert(timeInfo.tm_yday == 184);
2693 
2694             version (Posix)
2695                 assert(timeInfo.tm_isdst == 1);
2696             else version (Windows)
2697                 assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
2698 
2699             version (Posix)
2700             {
2701                 assert(timeInfo.tm_gmtoff == -7 * 60 * 60);
2702                 assert(to!string(timeInfo.tm_zone) == "PDT");
2703             }
2704         }
2705 
2706         // This is more to verify that SysTime.init.toTM() doesn't segfault and
2707         // does something sane rather than that the value is anything
2708         // particularly useful.
2709         {
2710             auto timeInfo = SysTime.init.toTM();
2711 
2712             assert(timeInfo.tm_sec == 0);
2713             assert(timeInfo.tm_min == 0);
2714             assert(timeInfo.tm_hour == 0);
2715             assert(timeInfo.tm_mday == 1);
2716             assert(timeInfo.tm_mon == 0);
2717             assert(timeInfo.tm_year == -1899);
2718             assert(timeInfo.tm_wday == 1);
2719             assert(timeInfo.tm_yday == 0);
2720             assert(timeInfo.tm_isdst == 0);
2721 
2722             version (Posix)
2723             {
2724                 assert(timeInfo.tm_gmtoff == 0);
2725                 assert(to!string(timeInfo.tm_zone) == "SysTime.init's timezone");
2726             }
2727         }
2728 
2729         static void testScope(scope ref SysTime st) @safe
2730         {
2731             auto result = st.toTM();
2732         }
2733     }
2734 
2735 
2736     /++
2737         Adds the given number of years or months to this $(LREF SysTime). A
2738         negative number will subtract.
2739 
2740         Note that if day overflow is allowed, and the date with the adjusted
2741         year/month overflows the number of days in the new month, then the month
2742         will be incremented by one, and the day set to the number of days
2743         overflowed. (e.g. if the day were 31 and the new month were June, then
2744         the month would be incremented to July, and the new day would be 1). If
2745         day overflow is not allowed, then the day will be set to the last valid
2746         day in the month (e.g. June 31st would become June 30th).
2747 
2748         Params:
2749             units         = The type of units to add ("years" or "months").
2750             value         = The number of months or years to add to this
2751                             $(LREF SysTime).
2752             allowOverflow = Whether the days should be allowed to overflow,
2753                             causing the month to increment.
2754       +/
2755     ref SysTime add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow scope
2756         if (units == "years" || units == "months")
2757     {
2758         auto hnsecs = adjTime;
2759         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
2760 
2761         if (hnsecs < 0)
2762         {
2763             hnsecs += convert!("hours", "hnsecs")(24);
2764             --days;
2765         }
2766 
2767         auto date = Date(cast(int) days);
2768         date.add!units(value, allowOverflow);
2769         days = date.dayOfGregorianCal - 1;
2770 
2771         if (days < 0)
2772         {
2773             hnsecs -= convert!("hours", "hnsecs")(24);
2774             ++days;
2775         }
2776 
2777         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
2778 
2779         adjTime = newDaysHNSecs + hnsecs;
2780 
2781         return this;
2782     }
2783 
2784     @safe unittest
2785     {
2786         auto st1 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
2787         st1.add!"months"(11);
2788         assert(st1 == SysTime(DateTime(2010, 12, 1, 12, 30, 33)));
2789 
2790         auto st2 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
2791         st2.add!"months"(-11);
2792         assert(st2 == SysTime(DateTime(2009, 2, 1, 12, 30, 33)));
2793 
2794         auto st3 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
2795         st3.add!"years"(1);
2796         assert(st3 == SysTime(DateTime(2001, 3, 1, 12, 30, 33)));
2797 
2798         auto st4 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
2799         st4.add!"years"(1, AllowDayOverflow.no);
2800         assert(st4 == SysTime(DateTime(2001, 2, 28, 12, 30, 33)));
2801     }
2802 
2803     // Test add!"years"() with AllowDayOverflow.yes
2804     @safe unittest
2805     {
2806         import core.time;
2807         // Test A.D.
2808         {
2809             auto sysTime = SysTime(Date(1999, 7, 6));
2810             sysTime.add!"years"(7);
2811             assert(sysTime == SysTime(Date(2006, 7, 6)));
2812             sysTime.add!"years"(-9);
2813             assert(sysTime == SysTime(Date(1997, 7, 6)));
2814         }
2815 
2816         {
2817             auto sysTime = SysTime(Date(1999, 2, 28));
2818             sysTime.add!"years"(1);
2819             assert(sysTime == SysTime(Date(2000, 2, 28)));
2820         }
2821 
2822         {
2823             auto sysTime = SysTime(Date(2000, 2, 29));
2824             sysTime.add!"years"(-1);
2825             assert(sysTime == SysTime(Date(1999, 3, 1)));
2826         }
2827 
2828         {
2829             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234));
2830             sysTime.add!"years"(7);
2831             assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234)));
2832             sysTime.add!"years"(-9);
2833             assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234)));
2834         }
2835 
2836         {
2837             auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207));
2838             sysTime.add!"years"(1);
2839             assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207)));
2840         }
2841 
2842         {
2843             auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207));
2844             sysTime.add!"years"(-1);
2845             assert(sysTime == SysTime(DateTime(1999, 3, 1, 0, 7, 2), usecs(1207)));
2846         }
2847 
2848         // Test B.C.
2849         {
2850             auto sysTime = SysTime(Date(-1999, 7, 6));
2851             sysTime.add!"years"(-7);
2852             assert(sysTime == SysTime(Date(-2006, 7, 6)));
2853             sysTime.add!"years"(9);
2854             assert(sysTime == SysTime(Date(-1997, 7, 6)));
2855         }
2856 
2857         {
2858             auto sysTime = SysTime(Date(-1999, 2, 28));
2859             sysTime.add!"years"(-1);
2860             assert(sysTime == SysTime(Date(-2000, 2, 28)));
2861         }
2862 
2863         {
2864             auto sysTime = SysTime(Date(-2000, 2, 29));
2865             sysTime.add!"years"(1);
2866             assert(sysTime == SysTime(Date(-1999, 3, 1)));
2867         }
2868 
2869         {
2870             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234));
2871             sysTime.add!"years"(-7);
2872             assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234)));
2873             sysTime.add!"years"(9);
2874             assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234)));
2875         }
2876 
2877         {
2878             auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3));
2879             sysTime.add!"years"(-1);
2880             assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3)));
2881         }
2882 
2883         {
2884             auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3));
2885             sysTime.add!"years"(1);
2886             assert(sysTime == SysTime(DateTime(-1999, 3, 1, 3, 3, 3), hnsecs(3)));
2887         }
2888 
2889         // Test Both
2890         {
2891             auto sysTime = SysTime(Date(4, 7, 6));
2892             sysTime.add!"years"(-5);
2893             assert(sysTime == SysTime(Date(-1, 7, 6)));
2894             sysTime.add!"years"(5);
2895             assert(sysTime == SysTime(Date(4, 7, 6)));
2896         }
2897 
2898         {
2899             auto sysTime = SysTime(Date(-4, 7, 6));
2900             sysTime.add!"years"(5);
2901             assert(sysTime == SysTime(Date(1, 7, 6)));
2902             sysTime.add!"years"(-5);
2903             assert(sysTime == SysTime(Date(-4, 7, 6)));
2904         }
2905 
2906         {
2907             auto sysTime = SysTime(Date(4, 7, 6));
2908             sysTime.add!"years"(-8);
2909             assert(sysTime == SysTime(Date(-4, 7, 6)));
2910             sysTime.add!"years"(8);
2911             assert(sysTime == SysTime(Date(4, 7, 6)));
2912         }
2913 
2914         {
2915             auto sysTime = SysTime(Date(-4, 7, 6));
2916             sysTime.add!"years"(8);
2917             assert(sysTime == SysTime(Date(4, 7, 6)));
2918             sysTime.add!"years"(-8);
2919             assert(sysTime == SysTime(Date(-4, 7, 6)));
2920         }
2921 
2922         {
2923             auto sysTime = SysTime(Date(-4, 2, 29));
2924             sysTime.add!"years"(5);
2925             assert(sysTime == SysTime(Date(1, 3, 1)));
2926         }
2927 
2928         {
2929             auto sysTime = SysTime(Date(4, 2, 29));
2930             sysTime.add!"years"(-5);
2931             assert(sysTime == SysTime(Date(-1, 3, 1)));
2932         }
2933 
2934         {
2935             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
2936             sysTime.add!"years"(-1);
2937             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2938             sysTime.add!"years"(1);
2939             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2940         }
2941 
2942         {
2943             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2944             sysTime.add!"years"(-1);
2945             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2946             sysTime.add!"years"(1);
2947             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2948         }
2949 
2950         {
2951             auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0));
2952             sysTime.add!"years"(1);
2953             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2954             sysTime.add!"years"(-1);
2955             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2956         }
2957 
2958         {
2959             auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2960             sysTime.add!"years"(1);
2961             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2962             sysTime.add!"years"(-1);
2963             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2964         }
2965 
2966         {
2967             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
2968             sysTime.add!"years"(-5);
2969             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
2970             sysTime.add!"years"(5);
2971             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
2972         }
2973 
2974         {
2975             auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329));
2976             sysTime.add!"years"(5);
2977             assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329)));
2978             sysTime.add!"years"(-5);
2979             assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)));
2980         }
2981 
2982         {
2983             auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555));
2984             sysTime.add!"years"(5);
2985             assert(sysTime == SysTime(DateTime(1, 3, 1, 5, 5, 5), msecs(555)));
2986         }
2987 
2988         {
2989             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
2990             sysTime.add!"years"(-5);
2991             assert(sysTime == SysTime(DateTime(-1, 3, 1, 5, 5, 5), msecs(555)));
2992         }
2993 
2994         {
2995             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
2996             sysTime.add!"years"(-5).add!"years"(7);
2997             assert(sysTime == SysTime(DateTime(6, 3, 1, 5, 5, 5), msecs(555)));
2998         }
2999 
3000         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3001         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3002         static assert(!__traits(compiles, cst.add!"years"(4)));
3003         static assert(!__traits(compiles, ist.add!"years"(4)));
3004 
3005         static void testScope(scope ref SysTime st) @safe
3006         {
3007             auto result = st.add!"years"(42);
3008         }
3009     }
3010 
3011     // Test add!"years"() with AllowDayOverflow.no
3012     @safe unittest
3013     {
3014         import core.time;
3015         // Test A.D.
3016         {
3017             auto sysTime = SysTime(Date(1999, 7, 6));
3018             sysTime.add!"years"(7, AllowDayOverflow.no);
3019             assert(sysTime == SysTime(Date(2006, 7, 6)));
3020             sysTime.add!"years"(-9, AllowDayOverflow.no);
3021             assert(sysTime == SysTime(Date(1997, 7, 6)));
3022         }
3023 
3024         {
3025             auto sysTime = SysTime(Date(1999, 2, 28));
3026             sysTime.add!"years"(1, AllowDayOverflow.no);
3027             assert(sysTime == SysTime(Date(2000, 2, 28)));
3028         }
3029 
3030         {
3031             auto sysTime = SysTime(Date(2000, 2, 29));
3032             sysTime.add!"years"(-1, AllowDayOverflow.no);
3033             assert(sysTime == SysTime(Date(1999, 2, 28)));
3034         }
3035 
3036         {
3037             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234));
3038             sysTime.add!"years"(7, AllowDayOverflow.no);
3039             assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234)));
3040             sysTime.add!"years"(-9, AllowDayOverflow.no);
3041             assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234)));
3042         }
3043 
3044         {
3045             auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207));
3046             sysTime.add!"years"(1, AllowDayOverflow.no);
3047             assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207)));
3048         }
3049 
3050         {
3051             auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207));
3052             sysTime.add!"years"(-1, AllowDayOverflow.no);
3053             assert(sysTime == SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207)));
3054         }
3055 
3056         // Test B.C.
3057         {
3058             auto sysTime = SysTime(Date(-1999, 7, 6));
3059             sysTime.add!"years"(-7, AllowDayOverflow.no);
3060             assert(sysTime == SysTime(Date(-2006, 7, 6)));
3061             sysTime.add!"years"(9, AllowDayOverflow.no);
3062             assert(sysTime == SysTime(Date(-1997, 7, 6)));
3063         }
3064 
3065         {
3066             auto sysTime = SysTime(Date(-1999, 2, 28));
3067             sysTime.add!"years"(-1, AllowDayOverflow.no);
3068             assert(sysTime == SysTime(Date(-2000, 2, 28)));
3069         }
3070 
3071         {
3072             auto sysTime = SysTime(Date(-2000, 2, 29));
3073             sysTime.add!"years"(1, AllowDayOverflow.no);
3074             assert(sysTime == SysTime(Date(-1999, 2, 28)));
3075         }
3076 
3077         {
3078             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234));
3079             sysTime.add!"years"(-7, AllowDayOverflow.no);
3080             assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234)));
3081             sysTime.add!"years"(9, AllowDayOverflow.no);
3082             assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234)));
3083         }
3084 
3085         {
3086             auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3));
3087             sysTime.add!"years"(-1, AllowDayOverflow.no);
3088             assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3)));
3089         }
3090 
3091         {
3092             auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3));
3093             sysTime.add!"years"(1, AllowDayOverflow.no);
3094             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3)));
3095         }
3096 
3097         // Test Both
3098         {
3099             auto sysTime = SysTime(Date(4, 7, 6));
3100             sysTime.add!"years"(-5, AllowDayOverflow.no);
3101             assert(sysTime == SysTime(Date(-1, 7, 6)));
3102             sysTime.add!"years"(5, AllowDayOverflow.no);
3103             assert(sysTime == SysTime(Date(4, 7, 6)));
3104         }
3105 
3106         {
3107             auto sysTime = SysTime(Date(-4, 7, 6));
3108             sysTime.add!"years"(5, AllowDayOverflow.no);
3109             assert(sysTime == SysTime(Date(1, 7, 6)));
3110             sysTime.add!"years"(-5, AllowDayOverflow.no);
3111             assert(sysTime == SysTime(Date(-4, 7, 6)));
3112         }
3113 
3114         {
3115             auto sysTime = SysTime(Date(4, 7, 6));
3116             sysTime.add!"years"(-8, AllowDayOverflow.no);
3117             assert(sysTime == SysTime(Date(-4, 7, 6)));
3118             sysTime.add!"years"(8, AllowDayOverflow.no);
3119             assert(sysTime == SysTime(Date(4, 7, 6)));
3120         }
3121 
3122         {
3123             auto sysTime = SysTime(Date(-4, 7, 6));
3124             sysTime.add!"years"(8, AllowDayOverflow.no);
3125             assert(sysTime == SysTime(Date(4, 7, 6)));
3126             sysTime.add!"years"(-8, AllowDayOverflow.no);
3127             assert(sysTime == SysTime(Date(-4, 7, 6)));
3128         }
3129 
3130         {
3131             auto sysTime = SysTime(Date(-4, 2, 29));
3132             sysTime.add!"years"(5, AllowDayOverflow.no);
3133             assert(sysTime == SysTime(Date(1, 2, 28)));
3134         }
3135 
3136         {
3137             auto sysTime = SysTime(Date(4, 2, 29));
3138             sysTime.add!"years"(-5, AllowDayOverflow.no);
3139             assert(sysTime == SysTime(Date(-1, 2, 28)));
3140         }
3141 
3142         {
3143             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3144             sysTime.add!"years"(-1, AllowDayOverflow.no);
3145             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
3146             sysTime.add!"years"(1, AllowDayOverflow.no);
3147             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3148         }
3149 
3150         {
3151             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3152             sysTime.add!"years"(-1, AllowDayOverflow.no);
3153             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3154             sysTime.add!"years"(1, AllowDayOverflow.no);
3155             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3156         }
3157 
3158         {
3159             auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0));
3160             sysTime.add!"years"(1, AllowDayOverflow.no);
3161             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3162             sysTime.add!"years"(-1, AllowDayOverflow.no);
3163             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
3164         }
3165 
3166         {
3167             auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3168             sysTime.add!"years"(1, AllowDayOverflow.no);
3169             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3170             sysTime.add!"years"(-1, AllowDayOverflow.no);
3171             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3172         }
3173 
3174         {
3175             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
3176             sysTime.add!"years"(-5);
3177             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
3178             sysTime.add!"years"(5);
3179             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
3180         }
3181 
3182         {
3183             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
3184             sysTime.add!"years"(-5, AllowDayOverflow.no);
3185             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
3186             sysTime.add!"years"(5, AllowDayOverflow.no);
3187             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
3188         }
3189 
3190         {
3191             auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329));
3192             sysTime.add!"years"(5, AllowDayOverflow.no);
3193             assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329)));
3194             sysTime.add!"years"(-5, AllowDayOverflow.no);
3195             assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)));
3196         }
3197 
3198         {
3199             auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555));
3200             sysTime.add!"years"(5, AllowDayOverflow.no);
3201             assert(sysTime == SysTime(DateTime(1, 2, 28, 5, 5, 5), msecs(555)));
3202         }
3203 
3204         {
3205             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
3206             sysTime.add!"years"(-5, AllowDayOverflow.no);
3207             assert(sysTime == SysTime(DateTime(-1, 2, 28, 5, 5, 5), msecs(555)));
3208         }
3209 
3210         {
3211             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
3212             sysTime.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no);
3213             assert(sysTime == SysTime(DateTime(6, 2, 28, 5, 5, 5), msecs(555)));
3214         }
3215     }
3216 
3217     // Test add!"months"() with AllowDayOverflow.yes
3218     @safe unittest
3219     {
3220         import core.time;
3221         // Test A.D.
3222         {
3223             auto sysTime = SysTime(Date(1999, 7, 6));
3224             sysTime.add!"months"(3);
3225             assert(sysTime == SysTime(Date(1999, 10, 6)));
3226             sysTime.add!"months"(-4);
3227             assert(sysTime == SysTime(Date(1999, 6, 6)));
3228         }
3229 
3230         {
3231             auto sysTime = SysTime(Date(1999, 7, 6));
3232             sysTime.add!"months"(6);
3233             assert(sysTime == SysTime(Date(2000, 1, 6)));
3234             sysTime.add!"months"(-6);
3235             assert(sysTime == SysTime(Date(1999, 7, 6)));
3236         }
3237 
3238         {
3239             auto sysTime = SysTime(Date(1999, 7, 6));
3240             sysTime.add!"months"(27);
3241             assert(sysTime == SysTime(Date(2001, 10, 6)));
3242             sysTime.add!"months"(-28);
3243             assert(sysTime == SysTime(Date(1999, 6, 6)));
3244         }
3245 
3246         {
3247             auto sysTime = SysTime(Date(1999, 5, 31));
3248             sysTime.add!"months"(1);
3249             assert(sysTime == SysTime(Date(1999, 7, 1)));
3250         }
3251 
3252         {
3253             auto sysTime = SysTime(Date(1999, 5, 31));
3254             sysTime.add!"months"(-1);
3255             assert(sysTime == SysTime(Date(1999, 5, 1)));
3256         }
3257 
3258         {
3259             auto sysTime = SysTime(Date(1999, 2, 28));
3260             sysTime.add!"months"(12);
3261             assert(sysTime == SysTime(Date(2000, 2, 28)));
3262         }
3263 
3264         {
3265             auto sysTime = SysTime(Date(2000, 2, 29));
3266             sysTime.add!"months"(12);
3267             assert(sysTime == SysTime(Date(2001, 3, 1)));
3268         }
3269 
3270         {
3271             auto sysTime = SysTime(Date(1999, 7, 31));
3272             sysTime.add!"months"(1);
3273             assert(sysTime == SysTime(Date(1999, 8, 31)));
3274             sysTime.add!"months"(1);
3275             assert(sysTime == SysTime(Date(1999, 10, 1)));
3276         }
3277 
3278         {
3279             auto sysTime = SysTime(Date(1998, 8, 31));
3280             sysTime.add!"months"(13);
3281             assert(sysTime == SysTime(Date(1999, 10, 1)));
3282             sysTime.add!"months"(-13);
3283             assert(sysTime == SysTime(Date(1998, 9, 1)));
3284         }
3285 
3286         {
3287             auto sysTime = SysTime(Date(1997, 12, 31));
3288             sysTime.add!"months"(13);
3289             assert(sysTime == SysTime(Date(1999, 1, 31)));
3290             sysTime.add!"months"(-13);
3291             assert(sysTime == SysTime(Date(1997, 12, 31)));
3292         }
3293 
3294         {
3295             auto sysTime = SysTime(Date(1997, 12, 31));
3296             sysTime.add!"months"(14);
3297             assert(sysTime == SysTime(Date(1999, 3, 3)));
3298             sysTime.add!"months"(-14);
3299             assert(sysTime == SysTime(Date(1998, 1, 3)));
3300         }
3301 
3302         {
3303             auto sysTime = SysTime(Date(1998, 12, 31));
3304             sysTime.add!"months"(14);
3305             assert(sysTime == SysTime(Date(2000, 3, 2)));
3306             sysTime.add!"months"(-14);
3307             assert(sysTime == SysTime(Date(1999, 1, 2)));
3308         }
3309 
3310         {
3311             auto sysTime = SysTime(Date(1999, 12, 31));
3312             sysTime.add!"months"(14);
3313             assert(sysTime == SysTime(Date(2001, 3, 3)));
3314             sysTime.add!"months"(-14);
3315             assert(sysTime == SysTime(Date(2000, 1, 3)));
3316         }
3317 
3318         {
3319             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
3320             sysTime.add!"months"(3);
3321             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
3322             sysTime.add!"months"(-4);
3323             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
3324         }
3325 
3326         {
3327             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
3328             sysTime.add!"months"(14);
3329             assert(sysTime == SysTime(DateTime(2000, 3, 2, 7, 7, 7), hnsecs(422202)));
3330             sysTime.add!"months"(-14);
3331             assert(sysTime == SysTime(DateTime(1999, 1, 2, 7, 7, 7), hnsecs(422202)));
3332         }
3333 
3334         {
3335             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
3336             sysTime.add!"months"(14);
3337             assert(sysTime == SysTime(DateTime(2001, 3, 3, 7, 7, 7), hnsecs(422202)));
3338             sysTime.add!"months"(-14);
3339             assert(sysTime == SysTime(DateTime(2000, 1, 3, 7, 7, 7), hnsecs(422202)));
3340         }
3341 
3342         // Test B.C.
3343         {
3344             auto sysTime = SysTime(Date(-1999, 7, 6));
3345             sysTime.add!"months"(3);
3346             assert(sysTime == SysTime(Date(-1999, 10, 6)));
3347             sysTime.add!"months"(-4);
3348             assert(sysTime == SysTime(Date(-1999, 6, 6)));
3349         }
3350 
3351         {
3352             auto sysTime = SysTime(Date(-1999, 7, 6));
3353             sysTime.add!"months"(6);
3354             assert(sysTime == SysTime(Date(-1998, 1, 6)));
3355             sysTime.add!"months"(-6);
3356             assert(sysTime == SysTime(Date(-1999, 7, 6)));
3357         }
3358 
3359         {
3360             auto sysTime = SysTime(Date(-1999, 7, 6));
3361             sysTime.add!"months"(-27);
3362             assert(sysTime == SysTime(Date(-2001, 4, 6)));
3363             sysTime.add!"months"(28);
3364             assert(sysTime == SysTime(Date(-1999, 8, 6)));
3365         }
3366 
3367         {
3368             auto sysTime = SysTime(Date(-1999, 5, 31));
3369             sysTime.add!"months"(1);
3370             assert(sysTime == SysTime(Date(-1999, 7, 1)));
3371         }
3372 
3373         {
3374             auto sysTime = SysTime(Date(-1999, 5, 31));
3375             sysTime.add!"months"(-1);
3376             assert(sysTime == SysTime(Date(-1999, 5, 1)));
3377         }
3378 
3379         {
3380             auto sysTime = SysTime(Date(-1999, 2, 28));
3381             sysTime.add!"months"(-12);
3382             assert(sysTime == SysTime(Date(-2000, 2, 28)));
3383         }
3384 
3385         {
3386             auto sysTime = SysTime(Date(-2000, 2, 29));
3387             sysTime.add!"months"(-12);
3388             assert(sysTime == SysTime(Date(-2001, 3, 1)));
3389         }
3390 
3391         {
3392             auto sysTime = SysTime(Date(-1999, 7, 31));
3393             sysTime.add!"months"(1);
3394             assert(sysTime == SysTime(Date(-1999, 8, 31)));
3395             sysTime.add!"months"(1);
3396             assert(sysTime == SysTime(Date(-1999, 10, 1)));
3397         }
3398 
3399         {
3400             auto sysTime = SysTime(Date(-1998, 8, 31));
3401             sysTime.add!"months"(13);
3402             assert(sysTime == SysTime(Date(-1997, 10, 1)));
3403             sysTime.add!"months"(-13);
3404             assert(sysTime == SysTime(Date(-1998, 9, 1)));
3405         }
3406 
3407         {
3408             auto sysTime = SysTime(Date(-1997, 12, 31));
3409             sysTime.add!"months"(13);
3410             assert(sysTime == SysTime(Date(-1995, 1, 31)));
3411             sysTime.add!"months"(-13);
3412             assert(sysTime == SysTime(Date(-1997, 12, 31)));
3413         }
3414 
3415         {
3416             auto sysTime = SysTime(Date(-1997, 12, 31));
3417             sysTime.add!"months"(14);
3418             assert(sysTime == SysTime(Date(-1995, 3, 3)));
3419             sysTime.add!"months"(-14);
3420             assert(sysTime == SysTime(Date(-1996, 1, 3)));
3421         }
3422 
3423         {
3424             auto sysTime = SysTime(Date(-2002, 12, 31));
3425             sysTime.add!"months"(14);
3426             assert(sysTime == SysTime(Date(-2000, 3, 2)));
3427             sysTime.add!"months"(-14);
3428             assert(sysTime == SysTime(Date(-2001, 1, 2)));
3429         }
3430 
3431         {
3432             auto sysTime = SysTime(Date(-2001, 12, 31));
3433             sysTime.add!"months"(14);
3434             assert(sysTime == SysTime(Date(-1999, 3, 3)));
3435             sysTime.add!"months"(-14);
3436             assert(sysTime == SysTime(Date(-2000, 1, 3)));
3437         }
3438 
3439         {
3440             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
3441             sysTime.add!"months"(3);
3442             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
3443             sysTime.add!"months"(-4);
3444             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
3445         }
3446 
3447         {
3448             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
3449             sysTime.add!"months"(14);
3450             assert(sysTime == SysTime(DateTime(-2000, 3, 2, 7, 7, 7), hnsecs(422202)));
3451             sysTime.add!"months"(-14);
3452             assert(sysTime == SysTime(DateTime(-2001, 1, 2, 7, 7, 7), hnsecs(422202)));
3453         }
3454 
3455         {
3456             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
3457             sysTime.add!"months"(14);
3458             assert(sysTime == SysTime(DateTime(-1999, 3, 3, 7, 7, 7), hnsecs(422202)));
3459             sysTime.add!"months"(-14);
3460             assert(sysTime == SysTime(DateTime(-2000, 1, 3, 7, 7, 7), hnsecs(422202)));
3461         }
3462 
3463         // Test Both
3464         {
3465             auto sysTime = SysTime(Date(1, 1, 1));
3466             sysTime.add!"months"(-1);
3467             assert(sysTime == SysTime(Date(0, 12, 1)));
3468             sysTime.add!"months"(1);
3469             assert(sysTime == SysTime(Date(1, 1, 1)));
3470         }
3471 
3472         {
3473             auto sysTime = SysTime(Date(4, 1, 1));
3474             sysTime.add!"months"(-48);
3475             assert(sysTime == SysTime(Date(0, 1, 1)));
3476             sysTime.add!"months"(48);
3477             assert(sysTime == SysTime(Date(4, 1, 1)));
3478         }
3479 
3480         {
3481             auto sysTime = SysTime(Date(4, 3, 31));
3482             sysTime.add!"months"(-49);
3483             assert(sysTime == SysTime(Date(0, 3, 2)));
3484             sysTime.add!"months"(49);
3485             assert(sysTime == SysTime(Date(4, 4, 2)));
3486         }
3487 
3488         {
3489             auto sysTime = SysTime(Date(4, 3, 31));
3490             sysTime.add!"months"(-85);
3491             assert(sysTime == SysTime(Date(-3, 3, 3)));
3492             sysTime.add!"months"(85);
3493             assert(sysTime == SysTime(Date(4, 4, 3)));
3494         }
3495 
3496         {
3497             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3498             sysTime.add!"months"(-1);
3499             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3500             sysTime.add!"months"(1);
3501             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3502         }
3503 
3504         {
3505             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3506             sysTime.add!"months"(-1);
3507             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3508             sysTime.add!"months"(1);
3509             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3510         }
3511 
3512         {
3513             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
3514             sysTime.add!"months"(1);
3515             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3516             sysTime.add!"months"(-1);
3517             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3518         }
3519 
3520         {
3521             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
3522             sysTime.add!"months"(1);
3523             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3524             sysTime.add!"months"(-1);
3525             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3526         }
3527 
3528         {
3529             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
3530             sysTime.add!"months"(-1);
3531             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17)));
3532             sysTime.add!"months"(1);
3533             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
3534         }
3535 
3536         {
3537             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
3538             sysTime.add!"months"(-85);
3539             assert(sysTime == SysTime(DateTime(-3, 3, 3, 12, 11, 10), msecs(9)));
3540             sysTime.add!"months"(85);
3541             assert(sysTime == SysTime(DateTime(4, 4, 3, 12, 11, 10), msecs(9)));
3542         }
3543 
3544         {
3545             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3546             sysTime.add!"months"(85);
3547             assert(sysTime == SysTime(DateTime(4, 5, 1, 12, 11, 10), msecs(9)));
3548             sysTime.add!"months"(-85);
3549             assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9)));
3550         }
3551 
3552         {
3553             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3554             sysTime.add!"months"(85).add!"months"(-83);
3555             assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), msecs(9)));
3556         }
3557 
3558         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3559         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3560         static assert(!__traits(compiles, cst.add!"months"(4)));
3561         static assert(!__traits(compiles, ist.add!"months"(4)));
3562 
3563         static void testScope(scope ref SysTime st) @safe
3564         {
3565             auto result = st.add!"months"(42);
3566         }
3567     }
3568 
3569     // Test add!"months"() with AllowDayOverflow.no
3570     @safe unittest
3571     {
3572         import core.time;
3573         // Test A.D.
3574         {
3575             auto sysTime = SysTime(Date(1999, 7, 6));
3576             sysTime.add!"months"(3, AllowDayOverflow.no);
3577             assert(sysTime == SysTime(Date(1999, 10, 6)));
3578             sysTime.add!"months"(-4, AllowDayOverflow.no);
3579             assert(sysTime == SysTime(Date(1999, 6, 6)));
3580         }
3581 
3582         {
3583             auto sysTime = SysTime(Date(1999, 7, 6));
3584             sysTime.add!"months"(6, AllowDayOverflow.no);
3585             assert(sysTime == SysTime(Date(2000, 1, 6)));
3586             sysTime.add!"months"(-6, AllowDayOverflow.no);
3587             assert(sysTime == SysTime(Date(1999, 7, 6)));
3588         }
3589 
3590         {
3591             auto sysTime = SysTime(Date(1999, 7, 6));
3592             sysTime.add!"months"(27, AllowDayOverflow.no);
3593             assert(sysTime == SysTime(Date(2001, 10, 6)));
3594             sysTime.add!"months"(-28, AllowDayOverflow.no);
3595             assert(sysTime == SysTime(Date(1999, 6, 6)));
3596         }
3597 
3598         {
3599             auto sysTime = SysTime(Date(1999, 5, 31));
3600             sysTime.add!"months"(1, AllowDayOverflow.no);
3601             assert(sysTime == SysTime(Date(1999, 6, 30)));
3602         }
3603 
3604         {
3605             auto sysTime = SysTime(Date(1999, 5, 31));
3606             sysTime.add!"months"(-1, AllowDayOverflow.no);
3607             assert(sysTime == SysTime(Date(1999, 4, 30)));
3608         }
3609 
3610         {
3611             auto sysTime = SysTime(Date(1999, 2, 28));
3612             sysTime.add!"months"(12, AllowDayOverflow.no);
3613             assert(sysTime == SysTime(Date(2000, 2, 28)));
3614         }
3615 
3616         {
3617             auto sysTime = SysTime(Date(2000, 2, 29));
3618             sysTime.add!"months"(12, AllowDayOverflow.no);
3619             assert(sysTime == SysTime(Date(2001, 2, 28)));
3620         }
3621 
3622         {
3623             auto sysTime = SysTime(Date(1999, 7, 31));
3624             sysTime.add!"months"(1, AllowDayOverflow.no);
3625             assert(sysTime == SysTime(Date(1999, 8, 31)));
3626             sysTime.add!"months"(1, AllowDayOverflow.no);
3627             assert(sysTime == SysTime(Date(1999, 9, 30)));
3628         }
3629 
3630         {
3631             auto sysTime = SysTime(Date(1998, 8, 31));
3632             sysTime.add!"months"(13, AllowDayOverflow.no);
3633             assert(sysTime == SysTime(Date(1999, 9, 30)));
3634             sysTime.add!"months"(-13, AllowDayOverflow.no);
3635             assert(sysTime == SysTime(Date(1998, 8, 30)));
3636         }
3637 
3638         {
3639             auto sysTime = SysTime(Date(1997, 12, 31));
3640             sysTime.add!"months"(13, AllowDayOverflow.no);
3641             assert(sysTime == SysTime(Date(1999, 1, 31)));
3642             sysTime.add!"months"(-13, AllowDayOverflow.no);
3643             assert(sysTime == SysTime(Date(1997, 12, 31)));
3644         }
3645 
3646         {
3647             auto sysTime = SysTime(Date(1997, 12, 31));
3648             sysTime.add!"months"(14, AllowDayOverflow.no);
3649             assert(sysTime == SysTime(Date(1999, 2, 28)));
3650             sysTime.add!"months"(-14, AllowDayOverflow.no);
3651             assert(sysTime == SysTime(Date(1997, 12, 28)));
3652         }
3653 
3654         {
3655             auto sysTime = SysTime(Date(1998, 12, 31));
3656             sysTime.add!"months"(14, AllowDayOverflow.no);
3657             assert(sysTime == SysTime(Date(2000, 2, 29)));
3658             sysTime.add!"months"(-14, AllowDayOverflow.no);
3659             assert(sysTime == SysTime(Date(1998, 12, 29)));
3660         }
3661 
3662         {
3663             auto sysTime = SysTime(Date(1999, 12, 31));
3664             sysTime.add!"months"(14, AllowDayOverflow.no);
3665             assert(sysTime == SysTime(Date(2001, 2, 28)));
3666             sysTime.add!"months"(-14, AllowDayOverflow.no);
3667             assert(sysTime == SysTime(Date(1999, 12, 28)));
3668         }
3669 
3670         {
3671             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
3672             sysTime.add!"months"(3, AllowDayOverflow.no);
3673             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
3674             sysTime.add!"months"(-4, AllowDayOverflow.no);
3675             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
3676         }
3677 
3678         {
3679             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
3680             sysTime.add!"months"(14, AllowDayOverflow.no);
3681             assert(sysTime == SysTime(DateTime(2000, 2, 29, 7, 7, 7), hnsecs(422202)));
3682             sysTime.add!"months"(-14, AllowDayOverflow.no);
3683             assert(sysTime == SysTime(DateTime(1998, 12, 29, 7, 7, 7), hnsecs(422202)));
3684         }
3685 
3686         {
3687             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
3688             sysTime.add!"months"(14, AllowDayOverflow.no);
3689             assert(sysTime == SysTime(DateTime(2001, 2, 28, 7, 7, 7), hnsecs(422202)));
3690             sysTime.add!"months"(-14, AllowDayOverflow.no);
3691             assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202)));
3692         }
3693 
3694         // Test B.C.
3695         {
3696             auto sysTime = SysTime(Date(-1999, 7, 6));
3697             sysTime.add!"months"(3, AllowDayOverflow.no);
3698             assert(sysTime == SysTime(Date(-1999, 10, 6)));
3699             sysTime.add!"months"(-4, AllowDayOverflow.no);
3700             assert(sysTime == SysTime(Date(-1999, 6, 6)));
3701         }
3702 
3703         {
3704             auto sysTime = SysTime(Date(-1999, 7, 6));
3705             sysTime.add!"months"(6, AllowDayOverflow.no);
3706             assert(sysTime == SysTime(Date(-1998, 1, 6)));
3707             sysTime.add!"months"(-6, AllowDayOverflow.no);
3708             assert(sysTime == SysTime(Date(-1999, 7, 6)));
3709         }
3710 
3711         {
3712             auto sysTime = SysTime(Date(-1999, 7, 6));
3713             sysTime.add!"months"(-27, AllowDayOverflow.no);
3714             assert(sysTime == SysTime(Date(-2001, 4, 6)));
3715             sysTime.add!"months"(28, AllowDayOverflow.no);
3716             assert(sysTime == SysTime(Date(-1999, 8, 6)));
3717         }
3718 
3719         {
3720             auto sysTime = SysTime(Date(-1999, 5, 31));
3721             sysTime.add!"months"(1, AllowDayOverflow.no);
3722             assert(sysTime == SysTime(Date(-1999, 6, 30)));
3723         }
3724 
3725         {
3726             auto sysTime = SysTime(Date(-1999, 5, 31));
3727             sysTime.add!"months"(-1, AllowDayOverflow.no);
3728             assert(sysTime == SysTime(Date(-1999, 4, 30)));
3729         }
3730 
3731         {
3732             auto sysTime = SysTime(Date(-1999, 2, 28));
3733             sysTime.add!"months"(-12, AllowDayOverflow.no);
3734             assert(sysTime == SysTime(Date(-2000, 2, 28)));
3735         }
3736 
3737         {
3738             auto sysTime = SysTime(Date(-2000, 2, 29));
3739             sysTime.add!"months"(-12, AllowDayOverflow.no);
3740             assert(sysTime == SysTime(Date(-2001, 2, 28)));
3741         }
3742 
3743         {
3744             auto sysTime = SysTime(Date(-1999, 7, 31));
3745             sysTime.add!"months"(1, AllowDayOverflow.no);
3746             assert(sysTime == SysTime(Date(-1999, 8, 31)));
3747             sysTime.add!"months"(1, AllowDayOverflow.no);
3748             assert(sysTime == SysTime(Date(-1999, 9, 30)));
3749         }
3750 
3751         {
3752             auto sysTime = SysTime(Date(-1998, 8, 31));
3753             sysTime.add!"months"(13, AllowDayOverflow.no);
3754             assert(sysTime == SysTime(Date(-1997, 9, 30)));
3755             sysTime.add!"months"(-13, AllowDayOverflow.no);
3756             assert(sysTime == SysTime(Date(-1998, 8, 30)));
3757         }
3758 
3759         {
3760             auto sysTime = SysTime(Date(-1997, 12, 31));
3761             sysTime.add!"months"(13, AllowDayOverflow.no);
3762             assert(sysTime == SysTime(Date(-1995, 1, 31)));
3763             sysTime.add!"months"(-13, AllowDayOverflow.no);
3764             assert(sysTime == SysTime(Date(-1997, 12, 31)));
3765         }
3766 
3767         {
3768             auto sysTime = SysTime(Date(-1997, 12, 31));
3769             sysTime.add!"months"(14, AllowDayOverflow.no);
3770             assert(sysTime == SysTime(Date(-1995, 2, 28)));
3771             sysTime.add!"months"(-14, AllowDayOverflow.no);
3772             assert(sysTime == SysTime(Date(-1997, 12, 28)));
3773         }
3774 
3775         {
3776             auto sysTime = SysTime(Date(-2002, 12, 31));
3777             sysTime.add!"months"(14, AllowDayOverflow.no);
3778             assert(sysTime == SysTime(Date(-2000, 2, 29)));
3779             sysTime.add!"months"(-14, AllowDayOverflow.no);
3780             assert(sysTime == SysTime(Date(-2002, 12, 29)));
3781         }
3782 
3783         {
3784             auto sysTime = SysTime(Date(-2001, 12, 31));
3785             sysTime.add!"months"(14, AllowDayOverflow.no);
3786             assert(sysTime == SysTime(Date(-1999, 2, 28)));
3787             sysTime.add!"months"(-14, AllowDayOverflow.no);
3788             assert(sysTime == SysTime(Date(-2001, 12, 28)));
3789         }
3790 
3791         {
3792             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
3793             sysTime.add!"months"(3, AllowDayOverflow.no);
3794             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
3795             sysTime.add!"months"(-4, AllowDayOverflow.no);
3796             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
3797         }
3798 
3799         {
3800             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
3801             sysTime.add!"months"(14, AllowDayOverflow.no);
3802             assert(sysTime == SysTime(DateTime(-2000, 2, 29, 7, 7, 7), hnsecs(422202)));
3803             sysTime.add!"months"(-14, AllowDayOverflow.no);
3804             assert(sysTime == SysTime(DateTime(-2002, 12, 29, 7, 7, 7), hnsecs(422202)));
3805         }
3806 
3807         {
3808             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
3809             sysTime.add!"months"(14, AllowDayOverflow.no);
3810             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 7, 7), hnsecs(422202)));
3811             sysTime.add!"months"(-14, AllowDayOverflow.no);
3812             assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202)));
3813         }
3814 
3815         // Test Both
3816         {
3817             auto sysTime = SysTime(Date(1, 1, 1));
3818             sysTime.add!"months"(-1, AllowDayOverflow.no);
3819             assert(sysTime == SysTime(Date(0, 12, 1)));
3820             sysTime.add!"months"(1, AllowDayOverflow.no);
3821             assert(sysTime == SysTime(Date(1, 1, 1)));
3822         }
3823 
3824         {
3825             auto sysTime = SysTime(Date(4, 1, 1));
3826             sysTime.add!"months"(-48, AllowDayOverflow.no);
3827             assert(sysTime == SysTime(Date(0, 1, 1)));
3828             sysTime.add!"months"(48, AllowDayOverflow.no);
3829             assert(sysTime == SysTime(Date(4, 1, 1)));
3830         }
3831 
3832         {
3833             auto sysTime = SysTime(Date(4, 3, 31));
3834             sysTime.add!"months"(-49, AllowDayOverflow.no);
3835             assert(sysTime == SysTime(Date(0, 2, 29)));
3836             sysTime.add!"months"(49, AllowDayOverflow.no);
3837             assert(sysTime == SysTime(Date(4, 3, 29)));
3838         }
3839 
3840         {
3841             auto sysTime = SysTime(Date(4, 3, 31));
3842             sysTime.add!"months"(-85, AllowDayOverflow.no);
3843             assert(sysTime == SysTime(Date(-3, 2, 28)));
3844             sysTime.add!"months"(85, AllowDayOverflow.no);
3845             assert(sysTime == SysTime(Date(4, 3, 28)));
3846         }
3847 
3848         {
3849             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3850             sysTime.add!"months"(-1, AllowDayOverflow.no);
3851             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3852             sysTime.add!"months"(1, AllowDayOverflow.no);
3853             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3854         }
3855 
3856         {
3857             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3858             sysTime.add!"months"(-1, AllowDayOverflow.no);
3859             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3860             sysTime.add!"months"(1, AllowDayOverflow.no);
3861             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3862         }
3863 
3864         {
3865             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
3866             sysTime.add!"months"(1, AllowDayOverflow.no);
3867             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3868             sysTime.add!"months"(-1, AllowDayOverflow.no);
3869             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3870         }
3871 
3872         {
3873             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
3874             sysTime.add!"months"(1, AllowDayOverflow.no);
3875             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3876             sysTime.add!"months"(-1, AllowDayOverflow.no);
3877             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3878         }
3879 
3880         {
3881             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
3882             sysTime.add!"months"(-1, AllowDayOverflow.no);
3883             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17)));
3884             sysTime.add!"months"(1, AllowDayOverflow.no);
3885             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
3886         }
3887 
3888         {
3889             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
3890             sysTime.add!"months"(-85, AllowDayOverflow.no);
3891             assert(sysTime == SysTime(DateTime(-3, 2, 28, 12, 11, 10), msecs(9)));
3892             sysTime.add!"months"(85, AllowDayOverflow.no);
3893             assert(sysTime == SysTime(DateTime(4, 3, 28, 12, 11, 10), msecs(9)));
3894         }
3895 
3896         {
3897             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3898             sysTime.add!"months"(85, AllowDayOverflow.no);
3899             assert(sysTime == SysTime(DateTime(4, 4, 30, 12, 11, 10), msecs(9)));
3900             sysTime.add!"months"(-85, AllowDayOverflow.no);
3901             assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9)));
3902         }
3903 
3904         {
3905             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3906             sysTime.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no);
3907             assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9)));
3908         }
3909     }
3910 
3911 
3912     /++
3913         Adds the given number of years or months to this $(LREF SysTime). A
3914         negative number will subtract.
3915 
3916         The difference between rolling and adding is that rolling does not
3917         affect larger units. Rolling a $(LREF SysTime) 12 months
3918         gets the exact same $(LREF SysTime). However, the days can still be
3919         affected due to the differing number of days in each month.
3920 
3921         Because there are no units larger than years, there is no difference
3922         between adding and rolling years.
3923 
3924         Params:
3925             units         = The type of units to add ("years" or "months").
3926             value         = The number of months or years to add to this
3927                             $(LREF SysTime).
3928             allowOverflow = Whether the days should be allowed to overflow,
3929                             causing the month to increment.
3930       +/
3931     ref SysTime roll(string units)
3932                     (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow scope
3933     if (units == "years")
3934     {
3935         return add!"years"(value, allowOverflow);
3936     }
3937 
3938     ///
3939     @safe unittest
3940     {
3941         import std.datetime.date : AllowDayOverflow, DateTime;
3942 
3943         auto st1 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
3944         st1.roll!"months"(1);
3945         assert(st1 == SysTime(DateTime(2010, 2, 1, 12, 33, 33)));
3946 
3947         auto st2 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
3948         st2.roll!"months"(-1);
3949         assert(st2 == SysTime(DateTime(2010, 12, 1, 12, 33, 33)));
3950 
3951         auto st3 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
3952         st3.roll!"months"(1);
3953         assert(st3 == SysTime(DateTime(1999, 3, 1, 12, 33, 33)));
3954 
3955         auto st4 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
3956         st4.roll!"months"(1, AllowDayOverflow.no);
3957         assert(st4 == SysTime(DateTime(1999, 2, 28, 12, 33, 33)));
3958 
3959         auto st5 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
3960         st5.roll!"years"(1);
3961         assert(st5 == SysTime(DateTime(2001, 3, 1, 12, 30, 33)));
3962 
3963         auto st6 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
3964         st6.roll!"years"(1, AllowDayOverflow.no);
3965         assert(st6 == SysTime(DateTime(2001, 2, 28, 12, 30, 33)));
3966     }
3967 
3968     @safe unittest
3969     {
3970         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3971         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3972         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3973         st.roll!"years"(4);
3974         static assert(!__traits(compiles, cst.roll!"years"(4)));
3975         static assert(!__traits(compiles, ist.roll!"years"(4)));
3976 
3977         static void testScope(scope ref SysTime st) @safe
3978         {
3979             auto result = st.roll!"years"(42);
3980         }
3981     }
3982 
3983 
3984     // Shares documentation with "years" overload.
3985     ref SysTime roll(string units)
3986                     (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow scope
3987     if (units == "months")
3988     {
3989         auto hnsecs = adjTime;
3990         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
3991 
3992         if (hnsecs < 0)
3993         {
3994             hnsecs += convert!("hours", "hnsecs")(24);
3995             --days;
3996         }
3997 
3998         auto date = Date(cast(int) days);
3999         date.roll!"months"(value, allowOverflow);
4000         days = date.dayOfGregorianCal - 1;
4001 
4002         if (days < 0)
4003         {
4004             hnsecs -= convert!("hours", "hnsecs")(24);
4005             ++days;
4006         }
4007 
4008         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
4009         adjTime = newDaysHNSecs + hnsecs;
4010         return this;
4011     }
4012 
4013     // Test roll!"months"() with AllowDayOverflow.yes
4014     @safe unittest
4015     {
4016         import core.time;
4017         // Test A.D.
4018         {
4019             auto sysTime = SysTime(Date(1999, 7, 6));
4020             sysTime.roll!"months"(3);
4021             assert(sysTime == SysTime(Date(1999, 10, 6)));
4022             sysTime.roll!"months"(-4);
4023             assert(sysTime == SysTime(Date(1999, 6, 6)));
4024         }
4025 
4026         {
4027             auto sysTime = SysTime(Date(1999, 7, 6));
4028             sysTime.roll!"months"(6);
4029             assert(sysTime == SysTime(Date(1999, 1, 6)));
4030             sysTime.roll!"months"(-6);
4031             assert(sysTime == SysTime(Date(1999, 7, 6)));
4032         }
4033 
4034         {
4035             auto sysTime = SysTime(Date(1999, 7, 6));
4036             sysTime.roll!"months"(27);
4037             assert(sysTime == SysTime(Date(1999, 10, 6)));
4038             sysTime.roll!"months"(-28);
4039             assert(sysTime == SysTime(Date(1999, 6, 6)));
4040         }
4041 
4042         {
4043             auto sysTime = SysTime(Date(1999, 5, 31));
4044             sysTime.roll!"months"(1);
4045             assert(sysTime == SysTime(Date(1999, 7, 1)));
4046         }
4047 
4048         {
4049             auto sysTime = SysTime(Date(1999, 5, 31));
4050             sysTime.roll!"months"(-1);
4051             assert(sysTime == SysTime(Date(1999, 5, 1)));
4052         }
4053 
4054         {
4055             auto sysTime = SysTime(Date(1999, 2, 28));
4056             sysTime.roll!"months"(12);
4057             assert(sysTime == SysTime(Date(1999, 2, 28)));
4058         }
4059 
4060         {
4061             auto sysTime = SysTime(Date(2000, 2, 29));
4062             sysTime.roll!"months"(12);
4063             assert(sysTime == SysTime(Date(2000, 2, 29)));
4064         }
4065 
4066         {
4067             auto sysTime = SysTime(Date(1999, 7, 31));
4068             sysTime.roll!"months"(1);
4069             assert(sysTime == SysTime(Date(1999, 8, 31)));
4070             sysTime.roll!"months"(1);
4071             assert(sysTime == SysTime(Date(1999, 10, 1)));
4072         }
4073 
4074         {
4075             auto sysTime = SysTime(Date(1998, 8, 31));
4076             sysTime.roll!"months"(13);
4077             assert(sysTime == SysTime(Date(1998, 10, 1)));
4078             sysTime.roll!"months"(-13);
4079             assert(sysTime == SysTime(Date(1998, 9, 1)));
4080         }
4081 
4082         {
4083             auto sysTime = SysTime(Date(1997, 12, 31));
4084             sysTime.roll!"months"(13);
4085             assert(sysTime == SysTime(Date(1997, 1, 31)));
4086             sysTime.roll!"months"(-13);
4087             assert(sysTime == SysTime(Date(1997, 12, 31)));
4088         }
4089 
4090         {
4091             auto sysTime = SysTime(Date(1997, 12, 31));
4092             sysTime.roll!"months"(14);
4093             assert(sysTime == SysTime(Date(1997, 3, 3)));
4094             sysTime.roll!"months"(-14);
4095             assert(sysTime == SysTime(Date(1997, 1, 3)));
4096         }
4097 
4098         {
4099             auto sysTime = SysTime(Date(1998, 12, 31));
4100             sysTime.roll!"months"(14);
4101             assert(sysTime == SysTime(Date(1998, 3, 3)));
4102             sysTime.roll!"months"(-14);
4103             assert(sysTime == SysTime(Date(1998, 1, 3)));
4104         }
4105 
4106         {
4107             auto sysTime = SysTime(Date(1999, 12, 31));
4108             sysTime.roll!"months"(14);
4109             assert(sysTime == SysTime(Date(1999, 3, 3)));
4110             sysTime.roll!"months"(-14);
4111             assert(sysTime == SysTime(Date(1999, 1, 3)));
4112         }
4113 
4114         {
4115             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
4116             sysTime.roll!"months"(3);
4117             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
4118             sysTime.roll!"months"(-4);
4119             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
4120         }
4121 
4122         {
4123             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
4124             sysTime.roll!"months"(14);
4125             assert(sysTime == SysTime(DateTime(1998, 3, 3, 7, 7, 7), hnsecs(422202)));
4126             sysTime.roll!"months"(-14);
4127             assert(sysTime == SysTime(DateTime(1998, 1, 3, 7, 7, 7), hnsecs(422202)));
4128         }
4129 
4130         {
4131             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
4132             sysTime.roll!"months"(14);
4133             assert(sysTime == SysTime(DateTime(1999, 3, 3, 7, 7, 7), hnsecs(422202)));
4134             sysTime.roll!"months"(-14);
4135             assert(sysTime == SysTime(DateTime(1999, 1, 3, 7, 7, 7), hnsecs(422202)));
4136         }
4137 
4138         // Test B.C.
4139         {
4140             auto sysTime = SysTime(Date(-1999, 7, 6));
4141             sysTime.roll!"months"(3);
4142             assert(sysTime == SysTime(Date(-1999, 10, 6)));
4143             sysTime.roll!"months"(-4);
4144             assert(sysTime == SysTime(Date(-1999, 6, 6)));
4145         }
4146 
4147         {
4148             auto sysTime = SysTime(Date(-1999, 7, 6));
4149             sysTime.roll!"months"(6);
4150             assert(sysTime == SysTime(Date(-1999, 1, 6)));
4151             sysTime.roll!"months"(-6);
4152             assert(sysTime == SysTime(Date(-1999, 7, 6)));
4153         }
4154 
4155         {
4156             auto sysTime = SysTime(Date(-1999, 7, 6));
4157             sysTime.roll!"months"(-27);
4158             assert(sysTime == SysTime(Date(-1999, 4, 6)));
4159             sysTime.roll!"months"(28);
4160             assert(sysTime == SysTime(Date(-1999, 8, 6)));
4161         }
4162 
4163         {
4164             auto sysTime = SysTime(Date(-1999, 5, 31));
4165             sysTime.roll!"months"(1);
4166             assert(sysTime == SysTime(Date(-1999, 7, 1)));
4167         }
4168 
4169         {
4170             auto sysTime = SysTime(Date(-1999, 5, 31));
4171             sysTime.roll!"months"(-1);
4172             assert(sysTime == SysTime(Date(-1999, 5, 1)));
4173         }
4174 
4175         {
4176             auto sysTime = SysTime(Date(-1999, 2, 28));
4177             sysTime.roll!"months"(-12);
4178             assert(sysTime == SysTime(Date(-1999, 2, 28)));
4179         }
4180 
4181         {
4182             auto sysTime = SysTime(Date(-2000, 2, 29));
4183             sysTime.roll!"months"(-12);
4184             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4185         }
4186 
4187         {
4188             auto sysTime = SysTime(Date(-1999, 7, 31));
4189             sysTime.roll!"months"(1);
4190             assert(sysTime == SysTime(Date(-1999, 8, 31)));
4191             sysTime.roll!"months"(1);
4192             assert(sysTime == SysTime(Date(-1999, 10, 1)));
4193         }
4194 
4195         {
4196             auto sysTime = SysTime(Date(-1998, 8, 31));
4197             sysTime.roll!"months"(13);
4198             assert(sysTime == SysTime(Date(-1998, 10, 1)));
4199             sysTime.roll!"months"(-13);
4200             assert(sysTime == SysTime(Date(-1998, 9, 1)));
4201         }
4202 
4203         {
4204             auto sysTime = SysTime(Date(-1997, 12, 31));
4205             sysTime.roll!"months"(13);
4206             assert(sysTime == SysTime(Date(-1997, 1, 31)));
4207             sysTime.roll!"months"(-13);
4208             assert(sysTime == SysTime(Date(-1997, 12, 31)));
4209         }
4210 
4211         {
4212             auto sysTime = SysTime(Date(-1997, 12, 31));
4213             sysTime.roll!"months"(14);
4214             assert(sysTime == SysTime(Date(-1997, 3, 3)));
4215             sysTime.roll!"months"(-14);
4216             assert(sysTime == SysTime(Date(-1997, 1, 3)));
4217         }
4218 
4219         {
4220             auto sysTime = SysTime(Date(-2002, 12, 31));
4221             sysTime.roll!"months"(14);
4222             assert(sysTime == SysTime(Date(-2002, 3, 3)));
4223             sysTime.roll!"months"(-14);
4224             assert(sysTime == SysTime(Date(-2002, 1, 3)));
4225         }
4226 
4227         {
4228             auto sysTime = SysTime(Date(-2001, 12, 31));
4229             sysTime.roll!"months"(14);
4230             assert(sysTime == SysTime(Date(-2001, 3, 3)));
4231             sysTime.roll!"months"(-14);
4232             assert(sysTime == SysTime(Date(-2001, 1, 3)));
4233         }
4234 
4235         {
4236             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
4237             sysTime.roll!"months"(-1);
4238             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0)));
4239             sysTime.roll!"months"(1);
4240             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
4241         }
4242 
4243         {
4244             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
4245             sysTime.roll!"months"(-1);
4246             assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4247             sysTime.roll!"months"(1);
4248             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4249         }
4250 
4251         {
4252             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
4253             sysTime.roll!"months"(1);
4254             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
4255             sysTime.roll!"months"(-1);
4256             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
4257         }
4258 
4259         {
4260             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
4261             sysTime.roll!"months"(1);
4262             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4263             sysTime.roll!"months"(-1);
4264             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4265         }
4266 
4267         {
4268             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), hnsecs(5007));
4269             sysTime.roll!"months"(3);
4270             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), hnsecs(5007)));
4271             sysTime.roll!"months"(-4);
4272             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), hnsecs(5007)));
4273         }
4274 
4275         {
4276             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
4277             sysTime.roll!"months"(14);
4278             assert(sysTime == SysTime(DateTime(-2002, 3, 3, 7, 7, 7), hnsecs(422202)));
4279             sysTime.roll!"months"(-14);
4280             assert(sysTime == SysTime(DateTime(-2002, 1, 3, 7, 7, 7), hnsecs(422202)));
4281         }
4282 
4283         {
4284             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
4285             sysTime.roll!"months"(14);
4286             assert(sysTime == SysTime(DateTime(-2001, 3, 3, 7, 7, 7), hnsecs(422202)));
4287             sysTime.roll!"months"(-14);
4288             assert(sysTime == SysTime(DateTime(-2001, 1, 3, 7, 7, 7), hnsecs(422202)));
4289         }
4290 
4291         // Test Both
4292         {
4293             auto sysTime = SysTime(Date(1, 1, 1));
4294             sysTime.roll!"months"(-1);
4295             assert(sysTime == SysTime(Date(1, 12, 1)));
4296             sysTime.roll!"months"(1);
4297             assert(sysTime == SysTime(Date(1, 1, 1)));
4298         }
4299 
4300         {
4301             auto sysTime = SysTime(Date(4, 1, 1));
4302             sysTime.roll!"months"(-48);
4303             assert(sysTime == SysTime(Date(4, 1, 1)));
4304             sysTime.roll!"months"(48);
4305             assert(sysTime == SysTime(Date(4, 1, 1)));
4306         }
4307 
4308         {
4309             auto sysTime = SysTime(Date(4, 3, 31));
4310             sysTime.roll!"months"(-49);
4311             assert(sysTime == SysTime(Date(4, 3, 2)));
4312             sysTime.roll!"months"(49);
4313             assert(sysTime == SysTime(Date(4, 4, 2)));
4314         }
4315 
4316         {
4317             auto sysTime = SysTime(Date(4, 3, 31));
4318             sysTime.roll!"months"(-85);
4319             assert(sysTime == SysTime(Date(4, 3, 2)));
4320             sysTime.roll!"months"(85);
4321             assert(sysTime == SysTime(Date(4, 4, 2)));
4322         }
4323 
4324         {
4325             auto sysTime = SysTime(Date(-1, 1, 1));
4326             sysTime.roll!"months"(-1);
4327             assert(sysTime == SysTime(Date(-1, 12, 1)));
4328             sysTime.roll!"months"(1);
4329             assert(sysTime == SysTime(Date(-1, 1, 1)));
4330         }
4331 
4332         {
4333             auto sysTime = SysTime(Date(-4, 1, 1));
4334             sysTime.roll!"months"(-48);
4335             assert(sysTime == SysTime(Date(-4, 1, 1)));
4336             sysTime.roll!"months"(48);
4337             assert(sysTime == SysTime(Date(-4, 1, 1)));
4338         }
4339 
4340         {
4341             auto sysTime = SysTime(Date(-4, 3, 31));
4342             sysTime.roll!"months"(-49);
4343             assert(sysTime == SysTime(Date(-4, 3, 2)));
4344             sysTime.roll!"months"(49);
4345             assert(sysTime == SysTime(Date(-4, 4, 2)));
4346         }
4347 
4348         {
4349             auto sysTime = SysTime(Date(-4, 3, 31));
4350             sysTime.roll!"months"(-85);
4351             assert(sysTime == SysTime(Date(-4, 3, 2)));
4352             sysTime.roll!"months"(85);
4353             assert(sysTime == SysTime(Date(-4, 4, 2)));
4354         }
4355 
4356         {
4357             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
4358             sysTime.roll!"months"(-1);
4359             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17)));
4360             sysTime.roll!"months"(1);
4361             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
4362         }
4363 
4364         {
4365             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
4366             sysTime.roll!"months"(-85);
4367             assert(sysTime == SysTime(DateTime(4, 3, 2, 12, 11, 10), msecs(9)));
4368             sysTime.roll!"months"(85);
4369             assert(sysTime == SysTime(DateTime(4, 4, 2, 12, 11, 10), msecs(9)));
4370         }
4371 
4372         {
4373             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4374             sysTime.roll!"months"(85);
4375             assert(sysTime == SysTime(DateTime(-3, 5, 1, 12, 11, 10), msecs(9)));
4376             sysTime.roll!"months"(-85);
4377             assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9)));
4378         }
4379 
4380         {
4381             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4382             sysTime.roll!"months"(85).roll!"months"(-83);
4383             assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), msecs(9)));
4384         }
4385 
4386         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4387         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4388         static assert(!__traits(compiles, cst.roll!"months"(4)));
4389         static assert(!__traits(compiles, ist.roll!"months"(4)));
4390 
4391         static void testScope(scope ref SysTime st) @safe
4392         {
4393             auto result = st.roll!"months"(42);
4394         }
4395     }
4396 
4397     // Test roll!"months"() with AllowDayOverflow.no
4398     @safe unittest
4399     {
4400         import core.time;
4401         // Test A.D.
4402         {
4403             auto sysTime = SysTime(Date(1999, 7, 6));
4404             sysTime.roll!"months"(3, AllowDayOverflow.no);
4405             assert(sysTime == SysTime(Date(1999, 10, 6)));
4406             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4407             assert(sysTime == SysTime(Date(1999, 6, 6)));
4408         }
4409 
4410         {
4411             auto sysTime = SysTime(Date(1999, 7, 6));
4412             sysTime.roll!"months"(6, AllowDayOverflow.no);
4413             assert(sysTime == SysTime(Date(1999, 1, 6)));
4414             sysTime.roll!"months"(-6, AllowDayOverflow.no);
4415             assert(sysTime == SysTime(Date(1999, 7, 6)));
4416         }
4417 
4418         {
4419             auto sysTime = SysTime(Date(1999, 7, 6));
4420             sysTime.roll!"months"(27, AllowDayOverflow.no);
4421             assert(sysTime == SysTime(Date(1999, 10, 6)));
4422             sysTime.roll!"months"(-28, AllowDayOverflow.no);
4423             assert(sysTime == SysTime(Date(1999, 6, 6)));
4424         }
4425 
4426         {
4427             auto sysTime = SysTime(Date(1999, 5, 31));
4428             sysTime.roll!"months"(1, AllowDayOverflow.no);
4429             assert(sysTime == SysTime(Date(1999, 6, 30)));
4430         }
4431 
4432         {
4433             auto sysTime = SysTime(Date(1999, 5, 31));
4434             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4435             assert(sysTime == SysTime(Date(1999, 4, 30)));
4436         }
4437 
4438         {
4439             auto sysTime = SysTime(Date(1999, 2, 28));
4440             sysTime.roll!"months"(12, AllowDayOverflow.no);
4441             assert(sysTime == SysTime(Date(1999, 2, 28)));
4442         }
4443 
4444         {
4445             auto sysTime = SysTime(Date(2000, 2, 29));
4446             sysTime.roll!"months"(12, AllowDayOverflow.no);
4447             assert(sysTime == SysTime(Date(2000, 2, 29)));
4448         }
4449 
4450         {
4451             auto sysTime = SysTime(Date(1999, 7, 31));
4452             sysTime.roll!"months"(1, AllowDayOverflow.no);
4453             assert(sysTime == SysTime(Date(1999, 8, 31)));
4454             sysTime.roll!"months"(1, AllowDayOverflow.no);
4455             assert(sysTime == SysTime(Date(1999, 9, 30)));
4456         }
4457 
4458         {
4459             auto sysTime = SysTime(Date(1998, 8, 31));
4460             sysTime.roll!"months"(13, AllowDayOverflow.no);
4461             assert(sysTime == SysTime(Date(1998, 9, 30)));
4462             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4463             assert(sysTime == SysTime(Date(1998, 8, 30)));
4464         }
4465 
4466         {
4467             auto sysTime = SysTime(Date(1997, 12, 31));
4468             sysTime.roll!"months"(13, AllowDayOverflow.no);
4469             assert(sysTime == SysTime(Date(1997, 1, 31)));
4470             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4471             assert(sysTime == SysTime(Date(1997, 12, 31)));
4472         }
4473 
4474         {
4475             auto sysTime = SysTime(Date(1997, 12, 31));
4476             sysTime.roll!"months"(14, AllowDayOverflow.no);
4477             assert(sysTime == SysTime(Date(1997, 2, 28)));
4478             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4479             assert(sysTime == SysTime(Date(1997, 12, 28)));
4480         }
4481 
4482         {
4483             auto sysTime = SysTime(Date(1998, 12, 31));
4484             sysTime.roll!"months"(14, AllowDayOverflow.no);
4485             assert(sysTime == SysTime(Date(1998, 2, 28)));
4486             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4487             assert(sysTime == SysTime(Date(1998, 12, 28)));
4488         }
4489 
4490         {
4491             auto sysTime = SysTime(Date(1999, 12, 31));
4492             sysTime.roll!"months"(14, AllowDayOverflow.no);
4493             assert(sysTime == SysTime(Date(1999, 2, 28)));
4494             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4495             assert(sysTime == SysTime(Date(1999, 12, 28)));
4496         }
4497 
4498         {
4499             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
4500             sysTime.roll!"months"(3, AllowDayOverflow.no);
4501             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
4502             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4503             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
4504         }
4505 
4506         {
4507             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
4508             sysTime.roll!"months"(14, AllowDayOverflow.no);
4509             assert(sysTime == SysTime(DateTime(1998, 2, 28, 7, 7, 7), hnsecs(422202)));
4510             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4511             assert(sysTime == SysTime(DateTime(1998, 12, 28, 7, 7, 7), hnsecs(422202)));
4512         }
4513 
4514         {
4515             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
4516             sysTime.roll!"months"(14, AllowDayOverflow.no);
4517             assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 7, 7), hnsecs(422202)));
4518             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4519             assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202)));
4520         }
4521 
4522         // Test B.C.
4523         {
4524             auto sysTime = SysTime(Date(-1999, 7, 6));
4525             sysTime.roll!"months"(3, AllowDayOverflow.no);
4526             assert(sysTime == SysTime(Date(-1999, 10, 6)));
4527             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4528             assert(sysTime == SysTime(Date(-1999, 6, 6)));
4529         }
4530 
4531         {
4532             auto sysTime = SysTime(Date(-1999, 7, 6));
4533             sysTime.roll!"months"(6, AllowDayOverflow.no);
4534             assert(sysTime == SysTime(Date(-1999, 1, 6)));
4535             sysTime.roll!"months"(-6, AllowDayOverflow.no);
4536             assert(sysTime == SysTime(Date(-1999, 7, 6)));
4537         }
4538 
4539         {
4540             auto sysTime = SysTime(Date(-1999, 7, 6));
4541             sysTime.roll!"months"(-27, AllowDayOverflow.no);
4542             assert(sysTime == SysTime(Date(-1999, 4, 6)));
4543             sysTime.roll!"months"(28, AllowDayOverflow.no);
4544             assert(sysTime == SysTime(Date(-1999, 8, 6)));
4545         }
4546 
4547         {
4548             auto sysTime = SysTime(Date(-1999, 5, 31));
4549             sysTime.roll!"months"(1, AllowDayOverflow.no);
4550             assert(sysTime == SysTime(Date(-1999, 6, 30)));
4551         }
4552 
4553         {
4554             auto sysTime = SysTime(Date(-1999, 5, 31));
4555             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4556             assert(sysTime == SysTime(Date(-1999, 4, 30)));
4557         }
4558 
4559         {
4560             auto sysTime = SysTime(Date(-1999, 2, 28));
4561             sysTime.roll!"months"(-12, AllowDayOverflow.no);
4562             assert(sysTime == SysTime(Date(-1999, 2, 28)));
4563         }
4564 
4565         {
4566             auto sysTime = SysTime(Date(-2000, 2, 29));
4567             sysTime.roll!"months"(-12, AllowDayOverflow.no);
4568             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4569         }
4570 
4571         {
4572             auto sysTime = SysTime(Date(-1999, 7, 31));
4573             sysTime.roll!"months"(1, AllowDayOverflow.no);
4574             assert(sysTime == SysTime(Date(-1999, 8, 31)));
4575             sysTime.roll!"months"(1, AllowDayOverflow.no);
4576             assert(sysTime == SysTime(Date(-1999, 9, 30)));
4577         }
4578 
4579         {
4580             auto sysTime = SysTime(Date(-1998, 8, 31));
4581             sysTime.roll!"months"(13, AllowDayOverflow.no);
4582             assert(sysTime == SysTime(Date(-1998, 9, 30)));
4583             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4584             assert(sysTime == SysTime(Date(-1998, 8, 30)));
4585         }
4586 
4587         {
4588             auto sysTime = SysTime(Date(-1997, 12, 31));
4589             sysTime.roll!"months"(13, AllowDayOverflow.no);
4590             assert(sysTime == SysTime(Date(-1997, 1, 31)));
4591             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4592             assert(sysTime == SysTime(Date(-1997, 12, 31)));
4593         }
4594 
4595         {
4596             auto sysTime = SysTime(Date(-1997, 12, 31));
4597             sysTime.roll!"months"(14, AllowDayOverflow.no);
4598             assert(sysTime == SysTime(Date(-1997, 2, 28)));
4599             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4600             assert(sysTime == SysTime(Date(-1997, 12, 28)));
4601         }
4602 
4603         {
4604             auto sysTime = SysTime(Date(-2002, 12, 31));
4605             sysTime.roll!"months"(14, AllowDayOverflow.no);
4606             assert(sysTime == SysTime(Date(-2002, 2, 28)));
4607             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4608             assert(sysTime == SysTime(Date(-2002, 12, 28)));
4609         }
4610 
4611         {
4612             auto sysTime = SysTime(Date(-2001, 12, 31));
4613             sysTime.roll!"months"(14, AllowDayOverflow.no);
4614             assert(sysTime == SysTime(Date(-2001, 2, 28)));
4615             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4616             assert(sysTime == SysTime(Date(-2001, 12, 28)));
4617         }
4618 
4619         {
4620             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
4621             sysTime.roll!"months"(3, AllowDayOverflow.no);
4622             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
4623             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4624             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
4625         }
4626 
4627         {
4628             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
4629             sysTime.roll!"months"(14, AllowDayOverflow.no);
4630             assert(sysTime == SysTime(DateTime(-2002, 2, 28, 7, 7, 7), hnsecs(422202)));
4631             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4632             assert(sysTime == SysTime(DateTime(-2002, 12, 28, 7, 7, 7), hnsecs(422202)));
4633         }
4634 
4635         {
4636             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
4637             sysTime.roll!"months"(14, AllowDayOverflow.no);
4638             assert(sysTime == SysTime(DateTime(-2001, 2, 28, 7, 7, 7), hnsecs(422202)));
4639             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4640             assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202)));
4641         }
4642 
4643         // Test Both
4644         {
4645             auto sysTime = SysTime(Date(1, 1, 1));
4646             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4647             assert(sysTime == SysTime(Date(1, 12, 1)));
4648             sysTime.roll!"months"(1, AllowDayOverflow.no);
4649             assert(sysTime == SysTime(Date(1, 1, 1)));
4650         }
4651 
4652         {
4653             auto sysTime = SysTime(Date(4, 1, 1));
4654             sysTime.roll!"months"(-48, AllowDayOverflow.no);
4655             assert(sysTime == SysTime(Date(4, 1, 1)));
4656             sysTime.roll!"months"(48, AllowDayOverflow.no);
4657             assert(sysTime == SysTime(Date(4, 1, 1)));
4658         }
4659 
4660         {
4661             auto sysTime = SysTime(Date(4, 3, 31));
4662             sysTime.roll!"months"(-49, AllowDayOverflow.no);
4663             assert(sysTime == SysTime(Date(4, 2, 29)));
4664             sysTime.roll!"months"(49, AllowDayOverflow.no);
4665             assert(sysTime == SysTime(Date(4, 3, 29)));
4666         }
4667 
4668         {
4669             auto sysTime = SysTime(Date(4, 3, 31));
4670             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4671             assert(sysTime == SysTime(Date(4, 2, 29)));
4672             sysTime.roll!"months"(85, AllowDayOverflow.no);
4673             assert(sysTime == SysTime(Date(4, 3, 29)));
4674         }
4675 
4676         {
4677             auto sysTime = SysTime(Date(-1, 1, 1));
4678             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4679             assert(sysTime == SysTime(Date(-1, 12, 1)));
4680             sysTime.roll!"months"(1, AllowDayOverflow.no);
4681             assert(sysTime == SysTime(Date(-1, 1, 1)));
4682         }
4683 
4684         {
4685             auto sysTime = SysTime(Date(-4, 1, 1));
4686             sysTime.roll!"months"(-48, AllowDayOverflow.no);
4687             assert(sysTime == SysTime(Date(-4, 1, 1)));
4688             sysTime.roll!"months"(48, AllowDayOverflow.no);
4689             assert(sysTime == SysTime(Date(-4, 1, 1)));
4690         }
4691 
4692         {
4693             auto sysTime = SysTime(Date(-4, 3, 31));
4694             sysTime.roll!"months"(-49, AllowDayOverflow.no);
4695             assert(sysTime == SysTime(Date(-4, 2, 29)));
4696             sysTime.roll!"months"(49, AllowDayOverflow.no);
4697             assert(sysTime == SysTime(Date(-4, 3, 29)));
4698         }
4699 
4700         {
4701             auto sysTime = SysTime(Date(-4, 3, 31));
4702             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4703             assert(sysTime == SysTime(Date(-4, 2, 29)));
4704             sysTime.roll!"months"(85, AllowDayOverflow.no);
4705             assert(sysTime == SysTime(Date(-4, 3, 29)));
4706         }
4707 
4708         {
4709             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
4710             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4711             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0)));
4712             sysTime.roll!"months"(1, AllowDayOverflow.no);
4713             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
4714         }
4715 
4716         {
4717             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
4718             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4719             assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4720             sysTime.roll!"months"(1, AllowDayOverflow.no);
4721             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4722         }
4723 
4724         {
4725             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
4726             sysTime.roll!"months"(1, AllowDayOverflow.no);
4727             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
4728             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4729             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
4730         }
4731 
4732         {
4733             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
4734             sysTime.roll!"months"(1, AllowDayOverflow.no);
4735             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4736             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4737             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4738         }
4739 
4740         {
4741             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
4742             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4743             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17)));
4744             sysTime.roll!"months"(1, AllowDayOverflow.no);
4745             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
4746         }
4747 
4748         {
4749             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
4750             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4751             assert(sysTime == SysTime(DateTime(4, 2, 29, 12, 11, 10), msecs(9)));
4752             sysTime.roll!"months"(85, AllowDayOverflow.no);
4753             assert(sysTime == SysTime(DateTime(4, 3, 29, 12, 11, 10), msecs(9)));
4754         }
4755 
4756         {
4757             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4758             sysTime.roll!"months"(85, AllowDayOverflow.no);
4759             assert(sysTime == SysTime(DateTime(-3, 4, 30, 12, 11, 10), msecs(9)));
4760             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4761             assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9)));
4762         }
4763 
4764         {
4765             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4766             sysTime.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no);
4767             assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9)));
4768         }
4769     }
4770 
4771 
4772     /++
4773         Adds the given number of units to this $(LREF SysTime). A negative number
4774         will subtract.
4775 
4776         The difference between rolling and adding is that rolling does not
4777         affect larger units. For instance, rolling a $(LREF SysTime) one
4778         year's worth of days gets the exact same $(LREF SysTime).
4779 
4780         Accepted units are `"days"`, `"minutes"`, `"hours"`,
4781         `"minutes"`, `"seconds"`, `"msecs"`, `"usecs"`, and
4782         `"hnsecs"`.
4783 
4784         Note that when rolling msecs, usecs or hnsecs, they all add up to a
4785         second. So, for example, rolling 1000 msecs is exactly the same as
4786         rolling 100,000 usecs.
4787 
4788         Params:
4789             units = The units to add.
4790             value = The number of $(D_PARAM units) to add to this
4791                     $(LREF SysTime).
4792       +/
4793     ref SysTime roll(string units)(long value) @safe nothrow scope
4794         if (units == "days")
4795     {
4796         auto hnsecs = adjTime;
4797         auto gdays = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
4798 
4799         if (hnsecs < 0)
4800         {
4801             hnsecs += convert!("hours", "hnsecs")(24);
4802             --gdays;
4803         }
4804 
4805         auto date = Date(cast(int) gdays);
4806         date.roll!"days"(value);
4807         gdays = date.dayOfGregorianCal - 1;
4808 
4809         if (gdays < 0)
4810         {
4811             hnsecs -= convert!("hours", "hnsecs")(24);
4812             ++gdays;
4813         }
4814 
4815         immutable newDaysHNSecs = convert!("days", "hnsecs")(gdays);
4816         adjTime = newDaysHNSecs + hnsecs;
4817         return  this;
4818     }
4819 
4820     ///
4821     @safe unittest
4822     {
4823         import core.time : msecs, hnsecs;
4824         import std.datetime.date : DateTime;
4825 
4826         auto st1 = SysTime(DateTime(2010, 1, 1, 11, 23, 12));
4827         st1.roll!"days"(1);
4828         assert(st1 == SysTime(DateTime(2010, 1, 2, 11, 23, 12)));
4829         st1.roll!"days"(365);
4830         assert(st1 == SysTime(DateTime(2010, 1, 26, 11, 23, 12)));
4831         st1.roll!"days"(-32);
4832         assert(st1 == SysTime(DateTime(2010, 1, 25, 11, 23, 12)));
4833 
4834         auto st2 = SysTime(DateTime(2010, 7, 4, 12, 0, 0));
4835         st2.roll!"hours"(1);
4836         assert(st2 == SysTime(DateTime(2010, 7, 4, 13, 0, 0)));
4837 
4838         auto st3 = SysTime(DateTime(2010, 2, 12, 12, 0, 0));
4839         st3.roll!"hours"(-1);
4840         assert(st3 == SysTime(DateTime(2010, 2, 12, 11, 0, 0)));
4841 
4842         auto st4 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
4843         st4.roll!"minutes"(1);
4844         assert(st4 == SysTime(DateTime(2009, 12, 31, 0, 1, 0)));
4845 
4846         auto st5 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
4847         st5.roll!"minutes"(-1);
4848         assert(st5 == SysTime(DateTime(2010, 1, 1, 0, 59, 0)));
4849 
4850         auto st6 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
4851         st6.roll!"seconds"(1);
4852         assert(st6 == SysTime(DateTime(2009, 12, 31, 0, 0, 1)));
4853 
4854         auto st7 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
4855         st7.roll!"seconds"(-1);
4856         assert(st7 == SysTime(DateTime(2010, 1, 1, 0, 0, 59)));
4857 
4858         auto dt = DateTime(2010, 1, 1, 0, 0, 0);
4859         auto st8 = SysTime(dt);
4860         st8.roll!"msecs"(1);
4861         assert(st8 == SysTime(dt, msecs(1)));
4862 
4863         auto st9 = SysTime(dt);
4864         st9.roll!"msecs"(-1);
4865         assert(st9 == SysTime(dt, msecs(999)));
4866 
4867         auto st10 = SysTime(dt);
4868         st10.roll!"hnsecs"(1);
4869         assert(st10 == SysTime(dt, hnsecs(1)));
4870 
4871         auto st11 = SysTime(dt);
4872         st11.roll!"hnsecs"(-1);
4873         assert(st11 == SysTime(dt, hnsecs(9_999_999)));
4874     }
4875 
4876     @safe unittest
4877     {
4878         import core.time;
4879         // Test A.D.
4880         {
4881             auto sysTime = SysTime(Date(1999, 2, 28));
4882             sysTime.roll!"days"(1);
4883             assert(sysTime == SysTime(Date(1999, 2, 1)));
4884             sysTime.roll!"days"(-1);
4885             assert(sysTime == SysTime(Date(1999, 2, 28)));
4886         }
4887 
4888         {
4889             auto sysTime = SysTime(Date(2000, 2, 28));
4890             sysTime.roll!"days"(1);
4891             assert(sysTime == SysTime(Date(2000, 2, 29)));
4892             sysTime.roll!"days"(1);
4893             assert(sysTime == SysTime(Date(2000, 2, 1)));
4894             sysTime.roll!"days"(-1);
4895             assert(sysTime == SysTime(Date(2000, 2, 29)));
4896         }
4897 
4898         {
4899             auto sysTime = SysTime(Date(1999, 6, 30));
4900             sysTime.roll!"days"(1);
4901             assert(sysTime == SysTime(Date(1999, 6, 1)));
4902             sysTime.roll!"days"(-1);
4903             assert(sysTime == SysTime(Date(1999, 6, 30)));
4904         }
4905 
4906         {
4907             auto sysTime = SysTime(Date(1999, 7, 31));
4908             sysTime.roll!"days"(1);
4909             assert(sysTime == SysTime(Date(1999, 7, 1)));
4910             sysTime.roll!"days"(-1);
4911             assert(sysTime == SysTime(Date(1999, 7, 31)));
4912         }
4913 
4914         {
4915             auto sysTime = SysTime(Date(1999, 1, 1));
4916             sysTime.roll!"days"(-1);
4917             assert(sysTime == SysTime(Date(1999, 1, 31)));
4918             sysTime.roll!"days"(1);
4919             assert(sysTime == SysTime(Date(1999, 1, 1)));
4920         }
4921 
4922         {
4923             auto sysTime = SysTime(Date(1999, 7, 6));
4924             sysTime.roll!"days"(9);
4925             assert(sysTime == SysTime(Date(1999, 7, 15)));
4926             sysTime.roll!"days"(-11);
4927             assert(sysTime == SysTime(Date(1999, 7, 4)));
4928             sysTime.roll!"days"(30);
4929             assert(sysTime == SysTime(Date(1999, 7, 3)));
4930             sysTime.roll!"days"(-3);
4931             assert(sysTime == SysTime(Date(1999, 7, 31)));
4932         }
4933 
4934         {
4935             auto sysTime = SysTime(Date(1999, 7, 6));
4936             sysTime.roll!"days"(365);
4937             assert(sysTime == SysTime(Date(1999, 7, 30)));
4938             sysTime.roll!"days"(-365);
4939             assert(sysTime == SysTime(Date(1999, 7, 6)));
4940             sysTime.roll!"days"(366);
4941             assert(sysTime == SysTime(Date(1999, 7, 31)));
4942             sysTime.roll!"days"(730);
4943             assert(sysTime == SysTime(Date(1999, 7, 17)));
4944             sysTime.roll!"days"(-1096);
4945             assert(sysTime == SysTime(Date(1999, 7, 6)));
4946         }
4947 
4948         {
4949             auto sysTime = SysTime(Date(1999, 2, 6));
4950             sysTime.roll!"days"(365);
4951             assert(sysTime == SysTime(Date(1999, 2, 7)));
4952             sysTime.roll!"days"(-365);
4953             assert(sysTime == SysTime(Date(1999, 2, 6)));
4954             sysTime.roll!"days"(366);
4955             assert(sysTime == SysTime(Date(1999, 2, 8)));
4956             sysTime.roll!"days"(730);
4957             assert(sysTime == SysTime(Date(1999, 2, 10)));
4958             sysTime.roll!"days"(-1096);
4959             assert(sysTime == SysTime(Date(1999, 2, 6)));
4960         }
4961 
4962         {
4963             auto sysTime = SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578));
4964             sysTime.roll!"days"(1);
4965             assert(sysTime == SysTime(DateTime(1999, 2, 1, 7, 9, 2), usecs(234578)));
4966             sysTime.roll!"days"(-1);
4967             assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578)));
4968         }
4969 
4970         {
4971             auto sysTime = SysTime(DateTime(1999, 7, 6, 7, 9, 2), usecs(234578));
4972             sysTime.roll!"days"(9);
4973             assert(sysTime == SysTime(DateTime(1999, 7, 15, 7, 9, 2), usecs(234578)));
4974             sysTime.roll!"days"(-11);
4975             assert(sysTime == SysTime(DateTime(1999, 7, 4, 7, 9, 2), usecs(234578)));
4976             sysTime.roll!"days"(30);
4977             assert(sysTime == SysTime(DateTime(1999, 7, 3, 7, 9, 2), usecs(234578)));
4978             sysTime.roll!"days"(-3);
4979             assert(sysTime == SysTime(DateTime(1999, 7, 31, 7, 9, 2), usecs(234578)));
4980         }
4981 
4982         // Test B.C.
4983         {
4984             auto sysTime = SysTime(Date(-1999, 2, 28));
4985             sysTime.roll!"days"(1);
4986             assert(sysTime == SysTime(Date(-1999, 2, 1)));
4987             sysTime.roll!"days"(-1);
4988             assert(sysTime == SysTime(Date(-1999, 2, 28)));
4989         }
4990 
4991         {
4992             auto sysTime = SysTime(Date(-2000, 2, 28));
4993             sysTime.roll!"days"(1);
4994             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4995             sysTime.roll!"days"(1);
4996             assert(sysTime == SysTime(Date(-2000, 2, 1)));
4997             sysTime.roll!"days"(-1);
4998             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4999         }
5000 
5001         {
5002             auto sysTime = SysTime(Date(-1999, 6, 30));
5003             sysTime.roll!"days"(1);
5004             assert(sysTime == SysTime(Date(-1999, 6, 1)));
5005             sysTime.roll!"days"(-1);
5006             assert(sysTime == SysTime(Date(-1999, 6, 30)));
5007         }
5008 
5009         {
5010             auto sysTime = SysTime(Date(-1999, 7, 31));
5011             sysTime.roll!"days"(1);
5012             assert(sysTime == SysTime(Date(-1999, 7, 1)));
5013             sysTime.roll!"days"(-1);
5014             assert(sysTime == SysTime(Date(-1999, 7, 31)));
5015         }
5016 
5017         {
5018             auto sysTime = SysTime(Date(-1999, 1, 1));
5019             sysTime.roll!"days"(-1);
5020             assert(sysTime == SysTime(Date(-1999, 1, 31)));
5021             sysTime.roll!"days"(1);
5022             assert(sysTime == SysTime(Date(-1999, 1, 1)));
5023         }
5024 
5025         {
5026             auto sysTime = SysTime(Date(-1999, 7, 6));
5027             sysTime.roll!"days"(9);
5028             assert(sysTime == SysTime(Date(-1999, 7, 15)));
5029             sysTime.roll!"days"(-11);
5030             assert(sysTime == SysTime(Date(-1999, 7, 4)));
5031             sysTime.roll!"days"(30);
5032             assert(sysTime == SysTime(Date(-1999, 7, 3)));
5033             sysTime.roll!"days"(-3);
5034             assert(sysTime == SysTime(Date(-1999, 7, 31)));
5035         }
5036 
5037         {
5038             auto sysTime = SysTime(Date(-1999, 7, 6));
5039             sysTime.roll!"days"(365);
5040             assert(sysTime == SysTime(Date(-1999, 7, 30)));
5041             sysTime.roll!"days"(-365);
5042             assert(sysTime == SysTime(Date(-1999, 7, 6)));
5043             sysTime.roll!"days"(366);
5044             assert(sysTime == SysTime(Date(-1999, 7, 31)));
5045             sysTime.roll!"days"(730);
5046             assert(sysTime == SysTime(Date(-1999, 7, 17)));
5047             sysTime.roll!"days"(-1096);
5048             assert(sysTime == SysTime(Date(-1999, 7, 6)));
5049         }
5050 
5051         {
5052             auto sysTime = SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578));
5053             sysTime.roll!"days"(1);
5054             assert(sysTime == SysTime(DateTime(-1999, 2, 1, 7, 9, 2), usecs(234578)));
5055             sysTime.roll!"days"(-1);
5056             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578)));
5057         }
5058 
5059         {
5060             auto sysTime = SysTime(DateTime(-1999, 7, 6, 7, 9, 2), usecs(234578));
5061             sysTime.roll!"days"(9);
5062             assert(sysTime == SysTime(DateTime(-1999, 7, 15, 7, 9, 2), usecs(234578)));
5063             sysTime.roll!"days"(-11);
5064             assert(sysTime == SysTime(DateTime(-1999, 7, 4, 7, 9, 2), usecs(234578)));
5065             sysTime.roll!"days"(30);
5066             assert(sysTime == SysTime(DateTime(-1999, 7, 3, 7, 9, 2), usecs(234578)));
5067             sysTime.roll!"days"(-3);
5068         }
5069 
5070         // Test Both
5071         {
5072             auto sysTime = SysTime(Date(1, 7, 6));
5073             sysTime.roll!"days"(-365);
5074             assert(sysTime == SysTime(Date(1, 7, 13)));
5075             sysTime.roll!"days"(365);
5076             assert(sysTime == SysTime(Date(1, 7, 6)));
5077             sysTime.roll!"days"(-731);
5078             assert(sysTime == SysTime(Date(1, 7, 19)));
5079             sysTime.roll!"days"(730);
5080             assert(sysTime == SysTime(Date(1, 7, 5)));
5081         }
5082 
5083         {
5084             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5085             sysTime.roll!"days"(-1);
5086             assert(sysTime == SysTime(DateTime(1, 1, 31, 0, 0, 0)));
5087             sysTime.roll!"days"(1);
5088             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5089         }
5090 
5091         {
5092             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
5093             sysTime.roll!"days"(-1);
5094             assert(sysTime == SysTime(DateTime(1, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
5095             sysTime.roll!"days"(1);
5096             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
5097         }
5098 
5099         {
5100             auto sysTime = SysTime(DateTime(0, 12, 31, 0, 0, 0));
5101             sysTime.roll!"days"(1);
5102             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
5103             sysTime.roll!"days"(-1);
5104             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0)));
5105         }
5106 
5107         {
5108             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5109             sysTime.roll!"days"(1);
5110             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
5111             sysTime.roll!"days"(-1);
5112             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5113         }
5114 
5115         {
5116             auto sysTime = SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22));
5117             sysTime.roll!"days"(-365);
5118             assert(sysTime == SysTime(DateTime(1, 7, 13, 13, 13, 9), msecs(22)));
5119             sysTime.roll!"days"(365);
5120             assert(sysTime == SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22)));
5121             sysTime.roll!"days"(-731);
5122             assert(sysTime == SysTime(DateTime(1, 7, 19, 13, 13, 9), msecs(22)));
5123             sysTime.roll!"days"(730);
5124             assert(sysTime == SysTime(DateTime(1, 7, 5, 13, 13, 9), msecs(22)));
5125         }
5126 
5127         {
5128             auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22));
5129             sysTime.roll!"days"(-365);
5130             assert(sysTime == SysTime(DateTime(0, 7, 13, 13, 13, 9), msecs(22)));
5131             sysTime.roll!"days"(365);
5132             assert(sysTime == SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22)));
5133             sysTime.roll!"days"(-731);
5134             assert(sysTime == SysTime(DateTime(0, 7, 19, 13, 13, 9), msecs(22)));
5135             sysTime.roll!"days"(730);
5136             assert(sysTime == SysTime(DateTime(0, 7, 5, 13, 13, 9), msecs(22)));
5137         }
5138 
5139         {
5140             auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22));
5141             sysTime.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730);
5142             assert(sysTime == SysTime(DateTime(0, 7, 8, 13, 13, 9), msecs(22)));
5143         }
5144 
5145         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5146         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5147         static assert(!__traits(compiles, cst.roll!"days"(4)));
5148         static assert(!__traits(compiles, ist.roll!"days"(4)));
5149 
5150         static void testScope(scope ref SysTime st) @safe
5151         {
5152             auto result = st.roll!"days"(42);
5153         }
5154     }
5155 
5156 
5157     // Shares documentation with "days" version.
5158     ref SysTime roll(string units)(long value) @safe nothrow scope
5159         if (units == "hours" || units == "minutes" || units == "seconds")
5160     {
5161         try
5162         {
5163             auto hnsecs = adjTime;
5164             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
5165 
5166             if (hnsecs < 0)
5167             {
5168                 hnsecs += convert!("hours", "hnsecs")(24);
5169                 --days;
5170             }
5171 
5172             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
5173             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
5174             immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
5175 
5176             auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
5177                                           cast(int) minute, cast(int) second));
5178             dateTime.roll!units(value);
5179             --days;
5180 
5181             hnsecs += convert!("hours", "hnsecs")(dateTime.hour);
5182             hnsecs += convert!("minutes", "hnsecs")(dateTime.minute);
5183             hnsecs += convert!("seconds", "hnsecs")(dateTime.second);
5184 
5185             if (days < 0)
5186             {
5187                 hnsecs -= convert!("hours", "hnsecs")(24);
5188                 ++days;
5189             }
5190 
5191             immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
5192             adjTime = newDaysHNSecs + hnsecs;
5193             return this;
5194         }
5195         catch (Exception e)
5196             assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw.");
5197     }
5198 
5199     // Test roll!"hours"().
5200     @safe unittest
5201     {
5202         import core.time;
5203         static void testST(SysTime orig, int hours, SysTime expected, size_t line = __LINE__) @safe
5204         {
5205             orig.roll!"hours"(hours);
5206             if (orig != expected)
5207                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5208         }
5209 
5210         // Test A.D.
5211         immutable d = msecs(45);
5212         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
5213         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5214         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
5215         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
5216         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d));
5217         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d));
5218         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d));
5219         testST(beforeAD, 6, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d));
5220         testST(beforeAD, 7, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d));
5221         testST(beforeAD, 8, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
5222         testST(beforeAD, 9, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d));
5223         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
5224         testST(beforeAD, 11, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5225         testST(beforeAD, 12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5226         testST(beforeAD, 13, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
5227         testST(beforeAD, 14, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d));
5228         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d));
5229         testST(beforeAD, 16, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
5230         testST(beforeAD, 17, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d));
5231         testST(beforeAD, 18, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d));
5232         testST(beforeAD, 19, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d));
5233         testST(beforeAD, 20, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d));
5234         testST(beforeAD, 21, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d));
5235         testST(beforeAD, 22, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
5236         testST(beforeAD, 23, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
5237         testST(beforeAD, 24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5238         testST(beforeAD, 25, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
5239         testST(beforeAD, 50, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
5240         testST(beforeAD, 10_000, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
5241 
5242         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
5243         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
5244         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d));
5245         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d));
5246         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d));
5247         testST(beforeAD, -6, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d));
5248         testST(beforeAD, -7, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d));
5249         testST(beforeAD, -8, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
5250         testST(beforeAD, -9, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d));
5251         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d));
5252         testST(beforeAD, -11, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
5253         testST(beforeAD, -12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5254         testST(beforeAD, -13, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5255         testST(beforeAD, -14, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
5256         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d));
5257         testST(beforeAD, -16, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
5258         testST(beforeAD, -17, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d));
5259         testST(beforeAD, -18, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d));
5260         testST(beforeAD, -19, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d));
5261         testST(beforeAD, -20, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d));
5262         testST(beforeAD, -21, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d));
5263         testST(beforeAD, -22, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
5264         testST(beforeAD, -23, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
5265         testST(beforeAD, -24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5266         testST(beforeAD, -25, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
5267         testST(beforeAD, -50, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
5268         testST(beforeAD, -10_000, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
5269 
5270         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
5271         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5272         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5273 
5274         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5275         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5276         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
5277 
5278         testST(SysTime(DateTime(1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 31, 0, 30, 33), d));
5279         testST(SysTime(DateTime(1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(1999, 8, 1, 23, 30, 33), d));
5280 
5281         testST(SysTime(DateTime(1999, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 12, 31, 0, 30, 33), d));
5282         testST(SysTime(DateTime(2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(2000, 1, 1, 23, 30, 33), d));
5283 
5284         testST(SysTime(DateTime(1999, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(1999, 2, 28, 0, 30, 33), d));
5285         testST(SysTime(DateTime(1999, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(1999, 3, 2, 23, 30, 33), d));
5286 
5287         testST(SysTime(DateTime(2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(2000, 2, 28, 0, 30, 33), d));
5288         testST(SysTime(DateTime(2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(2000, 3, 1, 23, 30, 33), d));
5289 
5290         // Test B.C.
5291         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5292         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5293         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
5294         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
5295         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d));
5296         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d));
5297         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d));
5298         testST(beforeBC, 6, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d));
5299         testST(beforeBC, 7, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d));
5300         testST(beforeBC, 8, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
5301         testST(beforeBC, 9, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d));
5302         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
5303         testST(beforeBC, 11, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5304         testST(beforeBC, 12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5305         testST(beforeBC, 13, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
5306         testST(beforeBC, 14, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d));
5307         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d));
5308         testST(beforeBC, 16, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
5309         testST(beforeBC, 17, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d));
5310         testST(beforeBC, 18, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d));
5311         testST(beforeBC, 19, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d));
5312         testST(beforeBC, 20, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d));
5313         testST(beforeBC, 21, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d));
5314         testST(beforeBC, 22, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
5315         testST(beforeBC, 23, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
5316         testST(beforeBC, 24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5317         testST(beforeBC, 25, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
5318         testST(beforeBC, 50, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
5319         testST(beforeBC, 10_000, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
5320 
5321         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
5322         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
5323         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d));
5324         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d));
5325         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d));
5326         testST(beforeBC, -6, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d));
5327         testST(beforeBC, -7, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d));
5328         testST(beforeBC, -8, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
5329         testST(beforeBC, -9, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d));
5330         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d));
5331         testST(beforeBC, -11, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
5332         testST(beforeBC, -12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5333         testST(beforeBC, -13, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5334         testST(beforeBC, -14, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
5335         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d));
5336         testST(beforeBC, -16, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
5337         testST(beforeBC, -17, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d));
5338         testST(beforeBC, -18, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d));
5339         testST(beforeBC, -19, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d));
5340         testST(beforeBC, -20, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d));
5341         testST(beforeBC, -21, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d));
5342         testST(beforeBC, -22, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
5343         testST(beforeBC, -23, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
5344         testST(beforeBC, -24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5345         testST(beforeBC, -25, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
5346         testST(beforeBC, -50, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
5347         testST(beforeBC, -10_000, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
5348 
5349         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
5350         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5351         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5352 
5353         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5354         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5355         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
5356 
5357         testST(SysTime(DateTime(-1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 31, 0, 30, 33), d));
5358         testST(SysTime(DateTime(-1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 8, 1, 23, 30, 33), d));
5359 
5360         testST(SysTime(DateTime(-2001, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(-2001, 12, 31, 0, 30, 33), d));
5361         testST(SysTime(DateTime(-2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(-2000, 1, 1, 23, 30, 33), d));
5362 
5363         testST(SysTime(DateTime(-2001, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2001, 2, 28, 0, 30, 33), d));
5364         testST(SysTime(DateTime(-2001, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(-2001, 3, 2, 23, 30, 33), d));
5365 
5366         testST(SysTime(DateTime(-2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2000, 2, 28, 0, 30, 33), d));
5367         testST(SysTime(DateTime(-2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(-2000, 3, 1, 23, 30, 33), d));
5368 
5369         // Test Both
5370         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 17_546, SysTime(DateTime(-1, 1, 1, 13, 30, 33), d));
5371         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -17_546, SysTime(DateTime(1, 1, 1, 11, 30, 33), d));
5372 
5373         {
5374             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5375             sysTime.roll!"hours"(-1);
5376             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 0, 0)));
5377             sysTime.roll!"hours"(1);
5378             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5379         }
5380 
5381         {
5382             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999));
5383             sysTime.roll!"hours"(-1);
5384             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
5385             sysTime.roll!"hours"(1);
5386             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999)));
5387         }
5388 
5389         {
5390             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 0, 0));
5391             sysTime.roll!"hours"(1);
5392             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0)));
5393             sysTime.roll!"hours"(-1);
5394             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5395         }
5396 
5397         {
5398             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5399             sysTime.roll!"hours"(1);
5400             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 59, 59), hnsecs(9_999_999)));
5401             sysTime.roll!"hours"(-1);
5402             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5403         }
5404 
5405         {
5406             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5407             sysTime.roll!"hours"(1).roll!"hours"(-67);
5408             assert(sysTime == SysTime(DateTime(0, 12, 31, 5, 59, 59), hnsecs(9_999_999)));
5409         }
5410 
5411         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5412         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5413         static assert(!__traits(compiles, cst.roll!"hours"(4)));
5414         static assert(!__traits(compiles, ist.roll!"hours"(4)));
5415 
5416         static void testScope(scope ref SysTime st) @safe
5417         {
5418             auto result = st.roll!"hours"(42);
5419         }
5420     }
5421 
5422     // Test roll!"minutes"().
5423     @safe unittest
5424     {
5425         import core.time;
5426         static void testST(SysTime orig, int minutes, SysTime expected, size_t line = __LINE__) @safe
5427         {
5428             orig.roll!"minutes"(minutes);
5429             if (orig != expected)
5430                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5431         }
5432 
5433         // Test A.D.
5434         immutable d = usecs(7203);
5435         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
5436         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5437         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5438         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 32, 33), d));
5439         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 33, 33), d));
5440         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 34, 33), d));
5441         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 35, 33), d));
5442         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 40, 33), d));
5443         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5444         testST(beforeAD, 29, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5445         testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5446         testST(beforeAD, 45, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5447         testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5448         testST(beforeAD, 75, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5449         testST(beforeAD, 90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5450         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 10, 33), d));
5451 
5452         testST(beforeAD, 689, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5453         testST(beforeAD, 690, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5454         testST(beforeAD, 691, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5455         testST(beforeAD, 960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5456         testST(beforeAD, 1439, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5457         testST(beforeAD, 1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5458         testST(beforeAD, 1441, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5459         testST(beforeAD, 2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5460 
5461         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5462         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 28, 33), d));
5463         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 27, 33), d));
5464         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 26, 33), d));
5465         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 25, 33), d));
5466         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 20, 33), d));
5467         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5468         testST(beforeAD, -29, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5469         testST(beforeAD, -30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5470         testST(beforeAD, -45, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5471         testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5472         testST(beforeAD, -75, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5473         testST(beforeAD, -90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5474         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 50, 33), d));
5475 
5476         testST(beforeAD, -749, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5477         testST(beforeAD, -750, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5478         testST(beforeAD, -751, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5479         testST(beforeAD, -960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5480         testST(beforeAD, -1439, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5481         testST(beforeAD, -1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5482         testST(beforeAD, -1441, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5483         testST(beforeAD, -2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5484 
5485         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5486         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5487         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5488 
5489         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(1999, 7, 6, 11, 0, 33), d));
5490         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(1999, 7, 6, 11, 59, 33), d));
5491         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(1999, 7, 6, 11, 58, 33), d));
5492 
5493         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 1, 33), d));
5494         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 33), d));
5495         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 0, 59, 33), d));
5496 
5497         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(1999, 7, 5, 23, 0, 33), d));
5498         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 33), d));
5499         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(1999, 7, 5, 23, 58, 33), d));
5500 
5501         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(1998, 12, 31, 23, 0, 33), d));
5502         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 33), d));
5503         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(1998, 12, 31, 23, 58, 33), d));
5504 
5505         // Test B.C.
5506         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5507         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5508         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5509         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 32, 33), d));
5510         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 33, 33), d));
5511         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 34, 33), d));
5512         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 35, 33), d));
5513         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 40, 33), d));
5514         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5515         testST(beforeBC, 29, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5516         testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5517         testST(beforeBC, 45, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5518         testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5519         testST(beforeBC, 75, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5520         testST(beforeBC, 90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5521         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 10, 33), d));
5522 
5523         testST(beforeBC, 689, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5524         testST(beforeBC, 690, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5525         testST(beforeBC, 691, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5526         testST(beforeBC, 960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5527         testST(beforeBC, 1439, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5528         testST(beforeBC, 1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5529         testST(beforeBC, 1441, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5530         testST(beforeBC, 2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5531 
5532         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5533         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 28, 33), d));
5534         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 27, 33), d));
5535         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 26, 33), d));
5536         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 25, 33), d));
5537         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 20, 33), d));
5538         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5539         testST(beforeBC, -29, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5540         testST(beforeBC, -30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5541         testST(beforeBC, -45, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5542         testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5543         testST(beforeBC, -75, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5544         testST(beforeBC, -90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5545         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 50, 33), d));
5546 
5547         testST(beforeBC, -749, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5548         testST(beforeBC, -750, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5549         testST(beforeBC, -751, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5550         testST(beforeBC, -960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5551         testST(beforeBC, -1439, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5552         testST(beforeBC, -1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5553         testST(beforeBC, -1441, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5554         testST(beforeBC, -2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5555 
5556         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5557         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5558         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5559 
5560         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 11, 0, 33), d));
5561         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d));
5562         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 11, 58, 33), d));
5563 
5564         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 1, 33), d));
5565         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d));
5566         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 59, 33), d));
5567 
5568         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 0, 33), d));
5569         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d));
5570         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 58, 33), d));
5571 
5572         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 0, 33), d));
5573         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d));
5574         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 58, 33), d));
5575 
5576         // Test Both
5577         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(1, 1, 1, 0, 59, 0)));
5578         testST(SysTime(DateTime(0, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5579 
5580         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(0, 1, 1, 0, 59, 0)));
5581         testST(SysTime(DateTime(-1, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(-1, 12, 31, 23, 0, 0)));
5582 
5583         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 1_052_760, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d));
5584         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -1_052_760, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5585 
5586         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 1_052_782, SysTime(DateTime(-1, 1, 1, 11, 52, 33), d));
5587         testST(SysTime(DateTime(1, 1, 1, 13, 52, 33), d), -1_052_782, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5588 
5589         {
5590             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5591             sysTime.roll!"minutes"(-1);
5592             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 0)));
5593             sysTime.roll!"minutes"(1);
5594             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5595         }
5596 
5597         {
5598             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999));
5599             sysTime.roll!"minutes"(-1);
5600             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999)));
5601             sysTime.roll!"minutes"(1);
5602             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999)));
5603         }
5604 
5605         {
5606             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 0));
5607             sysTime.roll!"minutes"(1);
5608             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5609             sysTime.roll!"minutes"(-1);
5610             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0)));
5611         }
5612 
5613         {
5614             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5615             sysTime.roll!"minutes"(1);
5616             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 59), hnsecs(9_999_999)));
5617             sysTime.roll!"minutes"(-1);
5618             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5619         }
5620 
5621         {
5622             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5623             sysTime.roll!"minutes"(1).roll!"minutes"(-79);
5624             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 41, 59), hnsecs(9_999_999)));
5625         }
5626 
5627         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5628         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5629         static assert(!__traits(compiles, cst.roll!"minutes"(4)));
5630         static assert(!__traits(compiles, ist.roll!"minutes"(4)));
5631 
5632         static void testScope(scope ref SysTime st) @safe
5633         {
5634             auto result = st.roll!"minutes"(42);
5635         }
5636     }
5637 
5638     // Test roll!"seconds"().
5639     @safe unittest
5640     {
5641         import core.time;
5642         static void testST(SysTime orig, int seconds, SysTime expected, size_t line = __LINE__) @safe
5643         {
5644             orig.roll!"seconds"(seconds);
5645             if (orig != expected)
5646                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5647         }
5648 
5649         // Test A.D.
5650         immutable d = msecs(274);
5651         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
5652         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5653         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5654         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 35), d));
5655         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 30, 36), d));
5656         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 30, 37), d));
5657         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 30, 38), d));
5658         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 43), d));
5659         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 30, 48), d));
5660         testST(beforeAD, 26, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5661         testST(beforeAD, 27, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5662         testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 30, 3), d));
5663         testST(beforeAD, 59, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5664         testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5665         testST(beforeAD, 61, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5666 
5667         testST(beforeAD, 1766, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5668         testST(beforeAD, 1767, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5669         testST(beforeAD, 1768, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d));
5670         testST(beforeAD, 2007, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5671         testST(beforeAD, 3599, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5672         testST(beforeAD, 3600, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5673         testST(beforeAD, 3601, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5674         testST(beforeAD, 7200, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5675 
5676         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5677         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 31), d));
5678         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 30, 30), d));
5679         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 30, 29), d));
5680         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 30, 28), d));
5681         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 23), d));
5682         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 30, 18), d));
5683         testST(beforeAD, -33, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5684         testST(beforeAD, -34, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5685         testST(beforeAD, -35, SysTime(DateTime(1999, 7, 6, 12, 30, 58), d));
5686         testST(beforeAD, -59, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5687         testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5688         testST(beforeAD, -61, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5689 
5690         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d));
5691         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5692         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5693 
5694         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 0, 1), d));
5695         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 0), d));
5696         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 0, 59), d));
5697 
5698         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 0, 0, 1), d));
5699         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 0), d));
5700         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 0, 0, 59), d));
5701 
5702         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(1999, 7, 5, 23, 59, 0), d));
5703         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 59), d));
5704         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(1999, 7, 5, 23, 59, 58), d));
5705 
5706         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(1998, 12, 31, 23, 59, 0), d));
5707         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 59), d));
5708         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(1998, 12, 31, 23, 59, 58), d));
5709 
5710         // Test B.C.
5711         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5712         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5713         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5714         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 35), d));
5715         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 30, 36), d));
5716         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 30, 37), d));
5717         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 30, 38), d));
5718         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 43), d));
5719         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 30, 48), d));
5720         testST(beforeBC, 26, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5721         testST(beforeBC, 27, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5722         testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 30, 3), d));
5723         testST(beforeBC, 59, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5724         testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5725         testST(beforeBC, 61, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5726 
5727         testST(beforeBC, 1766, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5728         testST(beforeBC, 1767, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5729         testST(beforeBC, 1768, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d));
5730         testST(beforeBC, 2007, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5731         testST(beforeBC, 3599, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5732         testST(beforeBC, 3600, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5733         testST(beforeBC, 3601, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5734         testST(beforeBC, 7200, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5735 
5736         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5737         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 31), d));
5738         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 30, 30), d));
5739         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 30, 29), d));
5740         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 30, 28), d));
5741         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 23), d));
5742         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 30, 18), d));
5743         testST(beforeBC, -33, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5744         testST(beforeBC, -34, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5745         testST(beforeBC, -35, SysTime(DateTime(-1999, 7, 6, 12, 30, 58), d));
5746         testST(beforeBC, -59, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5747         testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5748         testST(beforeBC, -61, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5749 
5750         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d));
5751         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5752         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5753 
5754         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 0, 1), d));
5755         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d));
5756         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 0, 59), d));
5757 
5758         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 0, 1), d));
5759         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d));
5760         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 0, 59), d));
5761 
5762         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 59, 0), d));
5763         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d));
5764         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 59, 58), d));
5765 
5766         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 59, 0), d));
5767         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d));
5768         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 59, 58), d));
5769 
5770         // Test Both
5771         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(1, 1, 1, 0, 0, 59), d));
5772         testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(0, 12, 31, 23, 59, 0), d));
5773 
5774         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(0, 1, 1, 0, 0, 59), d));
5775         testST(SysTime(DateTime(-1, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-1, 12, 31, 23, 59, 0), d));
5776 
5777         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_600L, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d));
5778         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -63_165_600L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5779 
5780         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_617L, SysTime(DateTime(-1, 1, 1, 11, 30, 50), d));
5781         testST(SysTime(DateTime(1, 1, 1, 13, 30, 50), d), -63_165_617L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5782 
5783         {
5784             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5785             sysTime.roll!"seconds"(-1);
5786             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59)));
5787             sysTime.roll!"seconds"(1);
5788             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5789         }
5790 
5791         {
5792             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999));
5793             sysTime.roll!"seconds"(-1);
5794             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999)));
5795             sysTime.roll!"seconds"(1);
5796             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
5797         }
5798 
5799         {
5800             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59));
5801             sysTime.roll!"seconds"(1);
5802             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0)));
5803             sysTime.roll!"seconds"(-1);
5804             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59)));
5805         }
5806 
5807         {
5808             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5809             sysTime.roll!"seconds"(1);
5810             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0), hnsecs(9_999_999)));
5811             sysTime.roll!"seconds"(-1);
5812             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5813         }
5814 
5815         {
5816             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5817             sysTime.roll!"seconds"(1).roll!"seconds"(-102);
5818             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 18), hnsecs(9_999_999)));
5819         }
5820 
5821         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5822         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5823         static assert(!__traits(compiles, cst.roll!"seconds"(4)));
5824         static assert(!__traits(compiles, ist.roll!"seconds"(4)));
5825 
5826         static void testScope(scope ref SysTime st) @safe
5827         {
5828             auto result = st.roll!"seconds"(42);
5829         }
5830     }
5831 
5832 
5833     // Shares documentation with "days" version.
5834     ref SysTime roll(string units)(long value) @safe nothrow scope
5835         if (units == "msecs" || units == "usecs" || units == "hnsecs")
5836     {
5837         auto hnsecs = adjTime;
5838         immutable days = splitUnitsFromHNSecs!"days"(hnsecs);
5839         immutable negative = hnsecs < 0;
5840 
5841         if (negative)
5842             hnsecs += convert!("hours", "hnsecs")(24);
5843 
5844         immutable seconds = splitUnitsFromHNSecs!"seconds"(hnsecs);
5845         hnsecs += convert!(units, "hnsecs")(value);
5846         hnsecs %= convert!("seconds", "hnsecs")(1);
5847 
5848         if (hnsecs < 0)
5849             hnsecs += convert!("seconds", "hnsecs")(1);
5850         hnsecs += convert!("seconds", "hnsecs")(seconds);
5851 
5852         if (negative)
5853             hnsecs -= convert!("hours", "hnsecs")(24);
5854 
5855         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
5856         adjTime = newDaysHNSecs + hnsecs;
5857         return this;
5858     }
5859 
5860 
5861     // Test roll!"msecs"().
5862     @safe unittest
5863     {
5864         import core.time;
5865         static void testST(SysTime orig, int milliseconds, SysTime expected, size_t line = __LINE__) @safe
5866         {
5867             orig.roll!"msecs"(milliseconds);
5868             if (orig != expected)
5869                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5870         }
5871 
5872         // Test A.D.
5873         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274));
5874         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5875         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275)));
5876         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(276)));
5877         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(284)));
5878         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(374)));
5879         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5880         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5881         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5882         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275)));
5883         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5884         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5885         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5886         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(1)));
5887         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5888         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5889 
5890         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273)));
5891         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(272)));
5892         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(264)));
5893         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(174)));
5894         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5895         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5896         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5897         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273)));
5898         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5899         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5900         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5901         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5902         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5903 
5904         // Test B.C.
5905         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274));
5906         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5907         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275)));
5908         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(276)));
5909         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(284)));
5910         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(374)));
5911         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5912         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5913         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5914         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275)));
5915         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5916         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5917         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5918         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(1)));
5919         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5920         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5921 
5922         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273)));
5923         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(272)));
5924         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(264)));
5925         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(174)));
5926         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5927         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5928         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5929         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273)));
5930         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5931         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5932         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5933         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5934         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5935 
5936         // Test Both
5937         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5938         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(1)));
5939         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5940         testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(999)));
5941         testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(998)));
5942         testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5943         testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5944         testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(445)));
5945 
5946         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5947         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_989_999)));
5948         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5949         testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999)));
5950         testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999)));
5951         testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5952         testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5953         testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(5_549_999)));
5954 
5955         {
5956             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5957             st.roll!"msecs"(1202).roll!"msecs"(-703);
5958             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(4_989_999)));
5959         }
5960 
5961         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5962         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5963         static assert(!__traits(compiles, cst.roll!"msecs"(4)));
5964         static assert(!__traits(compiles, ist.roll!"msecs"(4)));
5965 
5966         static void testScope(scope ref SysTime st) @safe
5967         {
5968             auto result = st.roll!"msecs"(42);
5969         }
5970     }
5971 
5972     // Test roll!"usecs"().
5973     @safe unittest
5974     {
5975         import core.time;
5976         static void testST(SysTime orig, long microseconds, SysTime expected, size_t line = __LINE__) @safe
5977         {
5978             orig.roll!"usecs"(microseconds);
5979             if (orig != expected)
5980                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5981         }
5982 
5983         // Test A.D.
5984         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274));
5985         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5986         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(275)));
5987         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(276)));
5988         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(284)));
5989         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(374)));
5990         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999)));
5991         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1000)));
5992         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1274)));
5993         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1275)));
5994         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(2274)));
5995         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(26_999)));
5996         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_000)));
5997         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_001)));
5998         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(766_999)));
5999         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(767_000)));
6000         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6001         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6002         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6003 
6004         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(273)));
6005         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(272)));
6006         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(264)));
6007         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(174)));
6008         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
6009         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_999)));
6010         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_274)));
6011         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_273)));
6012         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(998_274)));
6013         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(967_000)));
6014         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(966_999)));
6015         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(167_000)));
6016         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(166_999)));
6017         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6018         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6019         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6020 
6021         // Test B.C.
6022         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274));
6023         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6024         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(275)));
6025         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(276)));
6026         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(284)));
6027         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(374)));
6028         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999)));
6029         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1000)));
6030         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1274)));
6031         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1275)));
6032         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(2274)));
6033         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(26_999)));
6034         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_000)));
6035         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_001)));
6036         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(766_999)));
6037         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(767_000)));
6038         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6039         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6040         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6041 
6042         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(273)));
6043         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(272)));
6044         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(264)));
6045         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(174)));
6046         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6047         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_999)));
6048         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_274)));
6049         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_273)));
6050         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(998_274)));
6051         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(967_000)));
6052         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(966_999)));
6053         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(167_000)));
6054         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(166_999)));
6055         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6056         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6057         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6058 
6059         // Test Both
6060         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6061         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(1)));
6062         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6063         testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_999)));
6064         testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_998)));
6065         testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_000)));
6066         testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(998_000)));
6067         testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(997_445)));
6068         testST(beforeBoth1, -1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6069         testST(beforeBoth1, -2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6070         testST(beforeBoth1, -2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(666_667)));
6071 
6072         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6073         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_989)));
6074         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6075         testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9)));
6076         testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19)));
6077         testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999)));
6078         testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999)));
6079         testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(25_549)));
6080         testST(beforeBoth2, 1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6081         testST(beforeBoth2, 2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6082         testST(beforeBoth2, 2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(3_333_329)));
6083 
6084         {
6085             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6086             st.roll!"usecs"(9_020_027);
6087             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(200_269)));
6088         }
6089 
6090         {
6091             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6092             st.roll!"usecs"(9_020_027).roll!"usecs"(-70_034);
6093             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_499_929)));
6094         }
6095 
6096         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6097         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6098         static assert(!__traits(compiles, cst.roll!"usecs"(4)));
6099         static assert(!__traits(compiles, ist.roll!"usecs"(4)));
6100 
6101         static void testScope(scope ref SysTime st) @safe
6102         {
6103             auto result = st.roll!"usecs"(42);
6104         }
6105     }
6106 
6107     // Test roll!"hnsecs"().
6108     @safe unittest
6109     {
6110         import core.time;
6111         static void testST(SysTime orig, long hnsecs, SysTime expected, size_t line = __LINE__) @safe
6112         {
6113             orig.roll!"hnsecs"(hnsecs);
6114             if (orig != expected)
6115                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
6116         }
6117 
6118         // Test A.D.
6119         auto dtAD = DateTime(1999, 7, 6, 12, 30, 33);
6120         auto beforeAD = SysTime(dtAD, hnsecs(274));
6121         testST(beforeAD, 0, SysTime(dtAD, hnsecs(274)));
6122         testST(beforeAD, 1, SysTime(dtAD, hnsecs(275)));
6123         testST(beforeAD, 2, SysTime(dtAD, hnsecs(276)));
6124         testST(beforeAD, 10, SysTime(dtAD, hnsecs(284)));
6125         testST(beforeAD, 100, SysTime(dtAD, hnsecs(374)));
6126         testST(beforeAD, 725, SysTime(dtAD, hnsecs(999)));
6127         testST(beforeAD, 726, SysTime(dtAD, hnsecs(1000)));
6128         testST(beforeAD, 1000, SysTime(dtAD, hnsecs(1274)));
6129         testST(beforeAD, 1001, SysTime(dtAD, hnsecs(1275)));
6130         testST(beforeAD, 2000, SysTime(dtAD, hnsecs(2274)));
6131         testST(beforeAD, 26_725, SysTime(dtAD, hnsecs(26_999)));
6132         testST(beforeAD, 26_726, SysTime(dtAD, hnsecs(27_000)));
6133         testST(beforeAD, 26_727, SysTime(dtAD, hnsecs(27_001)));
6134         testST(beforeAD, 1_766_725, SysTime(dtAD, hnsecs(1_766_999)));
6135         testST(beforeAD, 1_766_726, SysTime(dtAD, hnsecs(1_767_000)));
6136         testST(beforeAD, 1_000_000, SysTime(dtAD, hnsecs(1_000_274)));
6137         testST(beforeAD, 60_000_000L, SysTime(dtAD, hnsecs(274)));
6138         testST(beforeAD, 3_600_000_000L, SysTime(dtAD, hnsecs(274)));
6139         testST(beforeAD, 600_000_000L, SysTime(dtAD, hnsecs(274)));
6140         testST(beforeAD, 36_000_000_000L, SysTime(dtAD, hnsecs(274)));
6141 
6142         testST(beforeAD, -1, SysTime(dtAD, hnsecs(273)));
6143         testST(beforeAD, -2, SysTime(dtAD, hnsecs(272)));
6144         testST(beforeAD, -10, SysTime(dtAD, hnsecs(264)));
6145         testST(beforeAD, -100, SysTime(dtAD, hnsecs(174)));
6146         testST(beforeAD, -274, SysTime(dtAD));
6147         testST(beforeAD, -275, SysTime(dtAD, hnsecs(9_999_999)));
6148         testST(beforeAD, -1000, SysTime(dtAD, hnsecs(9_999_274)));
6149         testST(beforeAD, -1001, SysTime(dtAD, hnsecs(9_999_273)));
6150         testST(beforeAD, -2000, SysTime(dtAD, hnsecs(9_998_274)));
6151         testST(beforeAD, -33_274, SysTime(dtAD, hnsecs(9_967_000)));
6152         testST(beforeAD, -33_275, SysTime(dtAD, hnsecs(9_966_999)));
6153         testST(beforeAD, -1_833_274, SysTime(dtAD, hnsecs(8_167_000)));
6154         testST(beforeAD, -1_833_275, SysTime(dtAD, hnsecs(8_166_999)));
6155         testST(beforeAD, -1_000_000, SysTime(dtAD, hnsecs(9_000_274)));
6156         testST(beforeAD, -60_000_000L, SysTime(dtAD, hnsecs(274)));
6157         testST(beforeAD, -3_600_000_000L, SysTime(dtAD, hnsecs(274)));
6158         testST(beforeAD, -600_000_000L, SysTime(dtAD, hnsecs(274)));
6159         testST(beforeAD, -36_000_000_000L, SysTime(dtAD, hnsecs(274)));
6160 
6161         // Test B.C.
6162         auto dtBC = DateTime(-1999, 7, 6, 12, 30, 33);
6163         auto beforeBC = SysTime(dtBC, hnsecs(274));
6164         testST(beforeBC, 0, SysTime(dtBC, hnsecs(274)));
6165         testST(beforeBC, 1, SysTime(dtBC, hnsecs(275)));
6166         testST(beforeBC, 2, SysTime(dtBC, hnsecs(276)));
6167         testST(beforeBC, 10, SysTime(dtBC, hnsecs(284)));
6168         testST(beforeBC, 100, SysTime(dtBC, hnsecs(374)));
6169         testST(beforeBC, 725, SysTime(dtBC, hnsecs(999)));
6170         testST(beforeBC, 726, SysTime(dtBC, hnsecs(1000)));
6171         testST(beforeBC, 1000, SysTime(dtBC, hnsecs(1274)));
6172         testST(beforeBC, 1001, SysTime(dtBC, hnsecs(1275)));
6173         testST(beforeBC, 2000, SysTime(dtBC, hnsecs(2274)));
6174         testST(beforeBC, 26_725, SysTime(dtBC, hnsecs(26_999)));
6175         testST(beforeBC, 26_726, SysTime(dtBC, hnsecs(27_000)));
6176         testST(beforeBC, 26_727, SysTime(dtBC, hnsecs(27_001)));
6177         testST(beforeBC, 1_766_725, SysTime(dtBC, hnsecs(1_766_999)));
6178         testST(beforeBC, 1_766_726, SysTime(dtBC, hnsecs(1_767_000)));
6179         testST(beforeBC, 1_000_000, SysTime(dtBC, hnsecs(1_000_274)));
6180         testST(beforeBC, 60_000_000L, SysTime(dtBC, hnsecs(274)));
6181         testST(beforeBC, 3_600_000_000L, SysTime(dtBC, hnsecs(274)));
6182         testST(beforeBC, 600_000_000L, SysTime(dtBC, hnsecs(274)));
6183         testST(beforeBC, 36_000_000_000L, SysTime(dtBC, hnsecs(274)));
6184 
6185         testST(beforeBC, -1, SysTime(dtBC, hnsecs(273)));
6186         testST(beforeBC, -2, SysTime(dtBC, hnsecs(272)));
6187         testST(beforeBC, -10, SysTime(dtBC, hnsecs(264)));
6188         testST(beforeBC, -100, SysTime(dtBC, hnsecs(174)));
6189         testST(beforeBC, -274, SysTime(dtBC));
6190         testST(beforeBC, -275, SysTime(dtBC, hnsecs(9_999_999)));
6191         testST(beforeBC, -1000, SysTime(dtBC, hnsecs(9_999_274)));
6192         testST(beforeBC, -1001, SysTime(dtBC, hnsecs(9_999_273)));
6193         testST(beforeBC, -2000, SysTime(dtBC, hnsecs(9_998_274)));
6194         testST(beforeBC, -33_274, SysTime(dtBC, hnsecs(9_967_000)));
6195         testST(beforeBC, -33_275, SysTime(dtBC, hnsecs(9_966_999)));
6196         testST(beforeBC, -1_833_274, SysTime(dtBC, hnsecs(8_167_000)));
6197         testST(beforeBC, -1_833_275, SysTime(dtBC, hnsecs(8_166_999)));
6198         testST(beforeBC, -1_000_000, SysTime(dtBC, hnsecs(9_000_274)));
6199         testST(beforeBC, -60_000_000L, SysTime(dtBC, hnsecs(274)));
6200         testST(beforeBC, -3_600_000_000L, SysTime(dtBC, hnsecs(274)));
6201         testST(beforeBC, -600_000_000L, SysTime(dtBC, hnsecs(274)));
6202         testST(beforeBC, -36_000_000_000L, SysTime(dtBC, hnsecs(274)));
6203 
6204         // Test Both
6205         auto dtBoth1 = DateTime(1, 1, 1, 0, 0, 0);
6206         auto beforeBoth1 = SysTime(dtBoth1);
6207         testST(beforeBoth1, 1, SysTime(dtBoth1, hnsecs(1)));
6208         testST(beforeBoth1, 0, SysTime(dtBoth1));
6209         testST(beforeBoth1, -1, SysTime(dtBoth1, hnsecs(9_999_999)));
6210         testST(beforeBoth1, -2, SysTime(dtBoth1, hnsecs(9_999_998)));
6211         testST(beforeBoth1, -1000, SysTime(dtBoth1, hnsecs(9_999_000)));
6212         testST(beforeBoth1, -2000, SysTime(dtBoth1, hnsecs(9_998_000)));
6213         testST(beforeBoth1, -2555, SysTime(dtBoth1, hnsecs(9_997_445)));
6214         testST(beforeBoth1, -1_000_000, SysTime(dtBoth1, hnsecs(9_000_000)));
6215         testST(beforeBoth1, -2_000_000, SysTime(dtBoth1, hnsecs(8_000_000)));
6216         testST(beforeBoth1, -2_333_333, SysTime(dtBoth1, hnsecs(7_666_667)));
6217         testST(beforeBoth1, -10_000_000, SysTime(dtBoth1));
6218         testST(beforeBoth1, -20_000_000, SysTime(dtBoth1));
6219         testST(beforeBoth1, -20_888_888, SysTime(dtBoth1, hnsecs(9_111_112)));
6220 
6221         auto dtBoth2 = DateTime(0, 12, 31, 23, 59, 59);
6222         auto beforeBoth2 = SysTime(dtBoth2, hnsecs(9_999_999));
6223         testST(beforeBoth2, -1, SysTime(dtBoth2, hnsecs(9_999_998)));
6224         testST(beforeBoth2, 0, SysTime(dtBoth2, hnsecs(9_999_999)));
6225         testST(beforeBoth2, 1, SysTime(dtBoth2));
6226         testST(beforeBoth2, 2, SysTime(dtBoth2, hnsecs(1)));
6227         testST(beforeBoth2, 1000, SysTime(dtBoth2, hnsecs(999)));
6228         testST(beforeBoth2, 2000, SysTime(dtBoth2, hnsecs(1999)));
6229         testST(beforeBoth2, 2555, SysTime(dtBoth2, hnsecs(2554)));
6230         testST(beforeBoth2, 1_000_000, SysTime(dtBoth2, hnsecs(999_999)));
6231         testST(beforeBoth2, 2_000_000, SysTime(dtBoth2, hnsecs(1_999_999)));
6232         testST(beforeBoth2, 2_333_333, SysTime(dtBoth2, hnsecs(2_333_332)));
6233         testST(beforeBoth2, 10_000_000, SysTime(dtBoth2, hnsecs(9_999_999)));
6234         testST(beforeBoth2, 20_000_000, SysTime(dtBoth2, hnsecs(9_999_999)));
6235         testST(beforeBoth2, 20_888_888, SysTime(dtBoth2, hnsecs(888_887)));
6236 
6237         {
6238             auto st = SysTime(dtBoth2, hnsecs(9_999_999));
6239             st.roll!"hnsecs"(70_777_222).roll!"hnsecs"(-222_555_292);
6240             assert(st == SysTime(dtBoth2, hnsecs(8_221_929)));
6241         }
6242 
6243         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6244         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6245         static assert(!__traits(compiles, cst.roll!"hnsecs"(4)));
6246         static assert(!__traits(compiles, ist.roll!"hnsecs"(4)));
6247 
6248         static void testScope(scope ref SysTime st) @safe
6249         {
6250             auto result = st.roll!"hnsecs"(42);
6251         }
6252     }
6253 
6254 
6255     /++
6256         Gives the result of adding or subtracting a $(REF Duration, core,time)
6257         from this $(LREF SysTime).
6258 
6259         The legal types of arithmetic for $(LREF SysTime) using this operator
6260         are
6261 
6262         $(BOOKTABLE,
6263         $(TR $(TD SysTime) $(TD +) $(TD Duration) $(TD -->) $(TD SysTime))
6264         $(TR $(TD SysTime) $(TD -) $(TD Duration) $(TD -->) $(TD SysTime))
6265         )
6266 
6267         Params:
6268             duration = The $(REF Duration, core,time) to add to or subtract from
6269                        this $(LREF SysTime).
6270       +/
6271     SysTime opBinary(string op)(Duration duration) @safe const pure nothrow scope
6272         if (op == "+" || op == "-")
6273     {
6274         SysTime retval = SysTime(this._stdTime, this._timezone);
6275         immutable hnsecs = duration.total!"hnsecs";
6276         mixin("retval._stdTime " ~ op ~ "= hnsecs;");
6277         return retval;
6278     }
6279 
6280     ///
6281     @safe unittest
6282     {
6283         import core.time : hours, seconds;
6284         import std.datetime.date : DateTime;
6285 
6286         assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + seconds(1) ==
6287                SysTime(DateTime(2016, 1, 1, 0, 0, 0)));
6288 
6289         assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + hours(1) ==
6290                SysTime(DateTime(2016, 1, 1, 0, 59, 59)));
6291 
6292         assert(SysTime(DateTime(2016, 1, 1, 0, 0, 0)) - seconds(1) ==
6293                SysTime(DateTime(2015, 12, 31, 23, 59, 59)));
6294 
6295         assert(SysTime(DateTime(2016, 1, 1, 0, 59, 59)) - hours(1) ==
6296                SysTime(DateTime(2015, 12, 31, 23, 59, 59)));
6297     }
6298 
6299     @safe unittest
6300     {
6301         import core.time;
6302         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_678));
6303 
6304         assert(st + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
6305         assert(st + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
6306         assert(st + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
6307         assert(st + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
6308         assert(st + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
6309         assert(st + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
6310         assert(st + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
6311         assert(st + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
6312         assert(st + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
6313         assert(st + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
6314         assert(st + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
6315         assert(st + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
6316         assert(st + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
6317         assert(st + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
6318         assert(st + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
6319         assert(st + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671)));
6320 
6321         assert(st - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
6322         assert(st - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
6323         assert(st - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
6324         assert(st - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
6325         assert(st - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
6326         assert(st - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
6327         assert(st - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
6328         assert(st - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
6329         assert(st - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
6330         assert(st - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
6331         assert(st - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
6332         assert(st - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
6333         assert(st - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
6334         assert(st - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
6335         assert(st - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
6336         assert(st - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671)));
6337 
6338         static void testST(SysTime orig, long hnsecs, SysTime expected, size_t line = __LINE__) @safe
6339         {
6340             auto result = orig + dur!"hnsecs"(hnsecs);
6341             if (result != expected)
6342                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", result, expected), __FILE__, line);
6343         }
6344 
6345         // Test A.D.
6346         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
6347         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
6348         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
6349         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
6350         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
6351         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
6352         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
6353         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6354         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6355         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6356         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6357         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6358         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6359         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6360         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6361         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6362         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6363         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
6364         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
6365         testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
6366         testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
6367 
6368         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
6369         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
6370         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
6371         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
6372         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
6373         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6374         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6375         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6376         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6377         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6378         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6379         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6380         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6381         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6382         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
6383         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
6384         testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
6385         testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
6386 
6387         // Test B.C.
6388         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
6389         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
6390         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
6391         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
6392         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
6393         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
6394         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
6395         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6396         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6397         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6398         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6399         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6400         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6401         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6402         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6403         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6404         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6405         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
6406         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
6407         testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
6408         testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
6409 
6410         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
6411         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
6412         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
6413         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
6414         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6415         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6416         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6417         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6418         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6419         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6420         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6421         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6422         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6423         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6424         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
6425         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
6426         testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
6427         testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
6428 
6429         // Test Both
6430         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6431         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6432         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6433         testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6434         testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6435         testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
6436         testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
6437         testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
6438         testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
6439         testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
6440         testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
6441         testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6442         testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
6443         testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
6444 
6445         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6446         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6447         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6448         testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6449         testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6450         testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
6451         testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
6452         testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
6453         testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
6454         testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
6455         testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
6456         testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6457         testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
6458         testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887)));
6459 
6460         auto duration = dur!"seconds"(12);
6461         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6462         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6463         assert(cst + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45)));
6464         assert(ist + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45)));
6465         assert(cst - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21)));
6466         assert(ist - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21)));
6467 
6468         static void testScope(scope ref SysTime st, scope ref Duration d) @safe
6469         {
6470             auto result = st + d;
6471         }
6472     }
6473 
6474 
6475     /++
6476         Gives the result of adding or subtracting a $(REF Duration, core,time) from
6477         this $(LREF SysTime), as well as assigning the result to this
6478         $(LREF SysTime).
6479 
6480         The legal types of arithmetic for $(LREF SysTime) using this operator are
6481 
6482         $(BOOKTABLE,
6483         $(TR $(TD SysTime) $(TD +) $(TD Duration) $(TD -->) $(TD SysTime))
6484         $(TR $(TD SysTime) $(TD -) $(TD Duration) $(TD -->) $(TD SysTime))
6485         )
6486 
6487         Params:
6488             duration = The $(REF Duration, core,time) to add to or subtract from
6489                        this $(LREF SysTime).
6490       +/
6491     ref SysTime opOpAssign(string op)(Duration duration) @safe pure nothrow scope
6492         if (op == "+" || op == "-")
6493     {
6494         immutable hnsecs = duration.total!"hnsecs";
6495         mixin("_stdTime " ~ op ~ "= hnsecs;");
6496         return this;
6497     }
6498 
6499     @safe unittest
6500     {
6501         import core.time;
6502         auto before = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6503         assert(before + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
6504         assert(before + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
6505         assert(before + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
6506         assert(before + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
6507 
6508         assert(before + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
6509         assert(before + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
6510         assert(before + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
6511         assert(before + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
6512         assert(before + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
6513         assert(before + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
6514         assert(before + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
6515         assert(before + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
6516         assert(before + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
6517         assert(before + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
6518         assert(before + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
6519         assert(before + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
6520 
6521         assert(before - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
6522         assert(before - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
6523         assert(before - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
6524         assert(before - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
6525 
6526         assert(before - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
6527         assert(before - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
6528         assert(before - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
6529         assert(before - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
6530         assert(before - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
6531         assert(before - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
6532         assert(before - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
6533         assert(before - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
6534         assert(before - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
6535         assert(before - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
6536         assert(before - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
6537         assert(before - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
6538 
6539         static void testST(SysTime orig, long hnsecs, SysTime expected, size_t line = __LINE__) @safe
6540         {
6541             auto r = orig += dur!"hnsecs"(hnsecs);
6542             if (orig != expected)
6543                 throw new AssertError(format("Failed 1. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
6544             if (r != expected)
6545                 throw new AssertError(format("Failed 2. actual [%s] != expected [%s]", r, expected), __FILE__, line);
6546         }
6547 
6548         // Test A.D.
6549         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
6550         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
6551         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
6552         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
6553         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
6554         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
6555         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
6556         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6557         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6558         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6559         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6560         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6561         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6562         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6563         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6564         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6565         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6566         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
6567         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
6568         testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
6569         testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
6570 
6571         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
6572         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
6573         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
6574         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
6575         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
6576         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6577         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6578         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6579         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6580         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6581         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6582         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6583         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6584         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6585         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
6586         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
6587         testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
6588         testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
6589 
6590         // Test B.C.
6591         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
6592         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
6593         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
6594         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
6595         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
6596         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
6597         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
6598         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6599         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6600         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6601         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6602         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6603         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6604         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6605         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6606         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6607         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6608         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
6609         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
6610         testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
6611         testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
6612 
6613         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
6614         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
6615         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
6616         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
6617         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6618         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6619         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6620         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6621         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6622         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6623         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6624         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6625         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6626         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6627         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
6628         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
6629         testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
6630         testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
6631 
6632         // Test Both
6633         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6634         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6635         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6636         testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6637         testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6638         testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
6639         testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
6640         testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
6641         testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
6642         testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
6643         testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
6644         testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6645         testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
6646         testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
6647 
6648         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6649         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6650         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6651         testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6652         testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6653         testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
6654         testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
6655         testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
6656         testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
6657         testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
6658         testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
6659         testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6660         testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
6661         testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887)));
6662 
6663         {
6664             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6665             (st += dur!"hnsecs"(52)) += dur!"seconds"(-907);
6666             assert(st == SysTime(DateTime(0, 12, 31, 23, 44, 53), hnsecs(51)));
6667         }
6668 
6669         auto duration = dur!"seconds"(12);
6670         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6671         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6672         static assert(!__traits(compiles, cst += duration));
6673         static assert(!__traits(compiles, ist += duration));
6674         static assert(!__traits(compiles, cst -= duration));
6675         static assert(!__traits(compiles, ist -= duration));
6676 
6677         static void testScope(scope ref SysTime st, scope ref Duration d) @safe
6678         {
6679             auto result1 = st += d;
6680             auto result2 = st -= d;
6681         }
6682     }
6683 
6684 
6685     /++
6686         Gives the difference between two $(LREF SysTime)s.
6687 
6688         The legal types of arithmetic for $(LREF SysTime) using this operator
6689         are
6690 
6691         $(BOOKTABLE,
6692         $(TR $(TD SysTime) $(TD -) $(TD SysTime) $(TD -->) $(TD duration))
6693         )
6694       +/
6695     Duration opBinary(string op)(SysTime rhs) @safe const pure nothrow scope
6696         if (op == "-")
6697     {
6698         return dur!"hnsecs"(_stdTime - rhs._stdTime);
6699     }
6700 
6701     @safe unittest
6702     {
6703         import core.time;
6704         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1998, 7, 6, 12, 30, 33)) ==
6705                dur!"seconds"(31_536_000));
6706         assert(SysTime(DateTime(1998, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6707                dur!"seconds"(-31_536_000));
6708 
6709         assert(SysTime(DateTime(1999, 8, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6710                dur!"seconds"(26_78_400));
6711         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 8, 6, 12, 30, 33)) ==
6712                dur!"seconds"(-26_78_400));
6713 
6714         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 5, 12, 30, 33)) ==
6715                dur!"seconds"(86_400));
6716         assert(SysTime(DateTime(1999, 7, 5, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6717                dur!"seconds"(-86_400));
6718 
6719         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 11, 30, 33)) ==
6720                dur!"seconds"(3600));
6721         assert(SysTime(DateTime(1999, 7, 6, 11, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6722                dur!"seconds"(-3600));
6723 
6724         assert(SysTime(DateTime(1999, 7, 6, 12, 31, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6725                dur!"seconds"(60));
6726         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 31, 33)) ==
6727                dur!"seconds"(-60));
6728 
6729         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 34)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6730                dur!"seconds"(1));
6731         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 34)) ==
6732                dur!"seconds"(-1));
6733 
6734         {
6735             auto dt = DateTime(1999, 7, 6, 12, 30, 33);
6736             assert(SysTime(dt, msecs(532)) - SysTime(dt) == msecs(532));
6737             assert(SysTime(dt) - SysTime(dt, msecs(532)) == msecs(-532));
6738 
6739             assert(SysTime(dt, usecs(333_347)) - SysTime(dt) == usecs(333_347));
6740             assert(SysTime(dt) - SysTime(dt, usecs(333_347)) == usecs(-333_347));
6741 
6742             assert(SysTime(dt, hnsecs(1_234_567)) - SysTime(dt) == hnsecs(1_234_567));
6743             assert(SysTime(dt) - SysTime(dt, hnsecs(1_234_567)) == hnsecs(-1_234_567));
6744         }
6745 
6746         assert(SysTime(DateTime(1, 1, 1, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(45033));
6747         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(1, 1, 1, 12, 30, 33)) == dur!"seconds"(-45033));
6748         assert(SysTime(DateTime(0, 12, 31, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(-41367));
6749         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 12, 30, 33)) == dur!"seconds"(41367));
6750 
6751         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) ==
6752                dur!"hnsecs"(1));
6753         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) ==
6754                dur!"hnsecs"(-1));
6755 
6756         version (Posix)
6757         {
6758             import std.datetime.timezone : PosixTimeZone;
6759             immutable tz = PosixTimeZone.getTimeZone("America/Los_Angeles");
6760         }
6761         else version (Windows)
6762         {
6763             import std.datetime.timezone : WindowsTimeZone;
6764             immutable tz = WindowsTimeZone.getTimeZone("Pacific Standard Time");
6765         }
6766 
6767         {
6768             auto dt = DateTime(2011, 1, 13, 8, 17, 2);
6769             auto d = msecs(296);
6770             assert(SysTime(dt, d, tz) - SysTime(dt, d, tz) == Duration.zero);
6771             assert(SysTime(dt, d, tz) - SysTime(dt, d, UTC()) == hours(8));
6772             assert(SysTime(dt, d, UTC()) - SysTime(dt, d, tz) == hours(-8));
6773         }
6774 
6775         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6776         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6777         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6778         assert(st - st == Duration.zero);
6779         assert(cst - st == Duration.zero);
6780         assert(ist - st == Duration.zero);
6781 
6782         assert(st - cst == Duration.zero);
6783         assert(cst - cst == Duration.zero);
6784         assert(ist - cst == Duration.zero);
6785 
6786         assert(st - ist == Duration.zero);
6787         assert(cst - ist == Duration.zero);
6788         assert(ist - ist == Duration.zero);
6789 
6790         static void testScope(scope ref SysTime left, scope ref SysTime right) @safe
6791         {
6792             auto result = left - right;
6793         }
6794     }
6795 
6796 
6797     /++
6798         Returns the difference between the two $(LREF SysTime)s in months.
6799 
6800         To get the difference in years, subtract the year property
6801         of two $(LREF SysTime)s. To get the difference in days or weeks,
6802         subtract the $(LREF SysTime)s themselves and use the
6803         $(REF Duration, core,time) that results. Because converting between
6804         months and smaller units requires a specific date (which
6805         $(REF Duration, core,time)s don't have), getting the difference in
6806         months requires some math using both the year and month properties, so
6807         this is a convenience function for getting the difference in months.
6808 
6809         Note that the number of days in the months or how far into the month
6810         either date is is irrelevant. It is the difference in the month property
6811         combined with the difference in years * 12. So, for instance,
6812         December 31st and January 1st are one month apart just as December 1st
6813         and January 31st are one month apart.
6814 
6815         Params:
6816             rhs = The $(LREF SysTime) to subtract from this one.
6817       +/
6818     int diffMonths(scope SysTime rhs) @safe const nothrow scope
6819     {
6820         return (cast(Date) this).diffMonths(cast(Date) rhs);
6821     }
6822 
6823     ///
6824     @safe unittest
6825     {
6826         import core.time;
6827         import std.datetime.date : Date;
6828 
6829         assert(SysTime(Date(1999, 2, 1)).diffMonths(
6830                    SysTime(Date(1999, 1, 31))) == 1);
6831 
6832         assert(SysTime(Date(1999, 1, 31)).diffMonths(
6833                    SysTime(Date(1999, 2, 1))) == -1);
6834 
6835         assert(SysTime(Date(1999, 3, 1)).diffMonths(
6836                    SysTime(Date(1999, 1, 1))) == 2);
6837 
6838         assert(SysTime(Date(1999, 1, 1)).diffMonths(
6839                    SysTime(Date(1999, 3, 31))) == -2);
6840     }
6841 
6842     @safe unittest
6843     {
6844         import core.time;
6845         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6846         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6847         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6848         assert(st.diffMonths(st) == 0);
6849         assert(cst.diffMonths(st) == 0);
6850         assert(ist.diffMonths(st) == 0);
6851 
6852         assert(st.diffMonths(cst) == 0);
6853         assert(cst.diffMonths(cst) == 0);
6854         assert(ist.diffMonths(cst) == 0);
6855 
6856         assert(st.diffMonths(ist) == 0);
6857         assert(cst.diffMonths(ist) == 0);
6858         assert(ist.diffMonths(ist) == 0);
6859 
6860         static void testScope(scope ref SysTime left, scope ref SysTime right) @safe
6861         {
6862             auto result = left.diffMonths(right);
6863         }
6864     }
6865 
6866 
6867     /++
6868         Whether this $(LREF SysTime) is in a leap year.
6869      +/
6870     @property bool isLeapYear() @safe const nothrow scope
6871     {
6872         return (cast(Date) this).isLeapYear;
6873     }
6874 
6875     @safe unittest
6876     {
6877         import core.time;
6878         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6879         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6880         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6881         assert(!st.isLeapYear);
6882         assert(!cst.isLeapYear);
6883         assert(!ist.isLeapYear);
6884 
6885         static void testScope(scope ref SysTime st) @safe
6886         {
6887             auto result = st.isLeapYear;
6888         }
6889     }
6890 
6891 
6892     /++
6893         Day of the week this $(LREF SysTime) is on.
6894       +/
6895     @property DayOfWeek dayOfWeek() @safe const nothrow scope
6896     {
6897         return getDayOfWeek(dayOfGregorianCal);
6898     }
6899 
6900     @safe unittest
6901     {
6902         import core.time;
6903         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6904         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6905         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6906         assert(st.dayOfWeek == DayOfWeek.tue);
6907         assert(cst.dayOfWeek == DayOfWeek.tue);
6908         assert(ist.dayOfWeek == DayOfWeek.tue);
6909 
6910         static void testScope(scope ref SysTime st) @safe
6911         {
6912             auto result = st.dayOfWeek;
6913         }
6914     }
6915 
6916 
6917     /++
6918         Day of the year this $(LREF SysTime) is on.
6919       +/
6920     @property ushort dayOfYear() @safe const nothrow scope
6921     {
6922         return (cast(Date) this).dayOfYear;
6923     }
6924 
6925     ///
6926     @safe unittest
6927     {
6928         import core.time;
6929         import std.datetime.date : DateTime;
6930 
6931         assert(SysTime(DateTime(1999, 1, 1, 12, 22, 7)).dayOfYear == 1);
6932         assert(SysTime(DateTime(1999, 12, 31, 7, 2, 59)).dayOfYear == 365);
6933         assert(SysTime(DateTime(2000, 12, 31, 21, 20, 0)).dayOfYear == 366);
6934     }
6935 
6936     @safe unittest
6937     {
6938         import core.time;
6939         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6940         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6941         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6942         assert(st.dayOfYear == 187);
6943         assert(cst.dayOfYear == 187);
6944         assert(ist.dayOfYear == 187);
6945 
6946         static void testScope(scope ref SysTime st) @safe
6947         {
6948             auto result = st.dayOfYear;
6949         }
6950     }
6951 
6952 
6953     /++
6954         Day of the year.
6955 
6956         Params:
6957             day = The day of the year to set which day of the year this
6958                   $(LREF SysTime) is on.
6959       +/
6960     @property void dayOfYear(int day) @safe scope
6961     {
6962         immutable hnsecs = adjTime;
6963         immutable days = convert!("hnsecs", "days")(hnsecs);
6964         immutable theRest = hnsecs - convert!("days", "hnsecs")(days);
6965 
6966         auto date = Date(cast(int) days);
6967         date.dayOfYear = day;
6968 
6969         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
6970 
6971         adjTime = newDaysHNSecs + theRest;
6972     }
6973 
6974     @safe unittest
6975     {
6976         import core.time;
6977         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6978         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6979         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6980         st.dayOfYear = 12;
6981         assert(st.dayOfYear == 12);
6982         static assert(!__traits(compiles, cst.dayOfYear = 12));
6983         static assert(!__traits(compiles, ist.dayOfYear = 12));
6984 
6985         static void testScope(scope ref SysTime st) @safe
6986         {
6987             st.dayOfYear = 42;
6988         }
6989     }
6990 
6991 
6992     /++
6993         The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on.
6994      +/
6995     @property int dayOfGregorianCal() @safe const nothrow scope
6996     {
6997         immutable adjustedTime = adjTime;
6998 
6999         // We have to add one because 0 would be midnight, January 1st, 1 A.D.,
7000         // which would be the 1st day of the Gregorian Calendar, not the 0th. So,
7001         // simply casting to days is one day off.
7002         if (adjustedTime > 0)
7003             return cast(int) getUnitsFromHNSecs!"days"(adjustedTime) + 1;
7004 
7005         long hnsecs = adjustedTime;
7006         immutable days = cast(int) splitUnitsFromHNSecs!"days"(hnsecs);
7007 
7008         return hnsecs == 0 ? days + 1 : days;
7009     }
7010 
7011     ///
7012     @safe unittest
7013     {
7014         import core.time;
7015         import std.datetime.date : DateTime;
7016 
7017         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
7018         assert(SysTime(DateTime(1, 12, 31, 23, 59, 59)).dayOfGregorianCal == 365);
7019         assert(SysTime(DateTime(2, 1, 1, 2, 2, 2)).dayOfGregorianCal == 366);
7020 
7021         assert(SysTime(DateTime(0, 12, 31, 7, 7, 7)).dayOfGregorianCal == 0);
7022         assert(SysTime(DateTime(0, 1, 1, 19, 30, 0)).dayOfGregorianCal == -365);
7023         assert(SysTime(DateTime(-1, 12, 31, 4, 7, 0)).dayOfGregorianCal == -366);
7024 
7025         assert(SysTime(DateTime(2000, 1, 1, 9, 30, 20)).dayOfGregorianCal == 730_120);
7026         assert(SysTime(DateTime(2010, 12, 31, 15, 45, 50)).dayOfGregorianCal == 734_137);
7027     }
7028 
7029     @safe unittest
7030     {
7031         import core.time;
7032         // Test A.D.
7033         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
7034         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 1);
7035         assert(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 1);
7036 
7037         assert(SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1);
7038         assert(SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)).dayOfGregorianCal == 2);
7039         assert(SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 32);
7040         assert(SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 366);
7041         assert(SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 731);
7042         assert(SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1096);
7043         assert(SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1462);
7044         assert(SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 17_898);
7045         assert(SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 35_065);
7046         assert(SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_160);
7047         assert(SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_525);
7048         assert(SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 37_986);
7049         assert(SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 72_684);
7050         assert(SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 73_049);
7051         assert(SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_208);
7052         assert(SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_573);
7053         assert(SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 145_732);
7054         assert(SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 146_098);
7055         assert(SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_257);
7056         assert(SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_622);
7057         assert(SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 364_878);
7058         assert(SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 365_243);
7059         assert(SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_023);
7060         assert(SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_389);
7061         assert(SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_596);
7062         assert(SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_961);
7063         assert(SysTime(DateTime(1945, 11, 12, 12, 2, 9), msecs(212)).dayOfGregorianCal == 710_347);
7064         assert(SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 729_755);
7065         assert(SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_120);
7066         assert(SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_486);
7067 
7068         assert(SysTime(DateTime(2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_773);
7069         assert(SysTime(DateTime(2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_803);
7070         assert(SysTime(DateTime(2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_804);
7071         assert(SysTime(DateTime(2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_831);
7072         assert(SysTime(DateTime(2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_832);
7073         assert(SysTime(DateTime(2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_862);
7074         assert(SysTime(DateTime(2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_863);
7075         assert(SysTime(DateTime(2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_892);
7076         assert(SysTime(DateTime(2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_893);
7077         assert(SysTime(DateTime(2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_923);
7078         assert(SysTime(DateTime(2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_924);
7079         assert(SysTime(DateTime(2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_953);
7080         assert(SysTime(DateTime(2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_954);
7081         assert(SysTime(DateTime(2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_984);
7082         assert(SysTime(DateTime(2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_985);
7083         assert(SysTime(DateTime(2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_015);
7084         assert(SysTime(DateTime(2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_016);
7085         assert(SysTime(DateTime(2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_045);
7086         assert(SysTime(DateTime(2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_046);
7087         assert(SysTime(DateTime(2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_076);
7088         assert(SysTime(DateTime(2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_077);
7089         assert(SysTime(DateTime(2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_106);
7090         assert(SysTime(DateTime(2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_107);
7091         assert(SysTime(DateTime(2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_137);
7092 
7093         assert(SysTime(DateTime(2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == 734_534);
7094         assert(SysTime(DateTime(2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == 734_561);
7095         assert(SysTime(DateTime(2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == 734_562);
7096         assert(SysTime(DateTime(2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == 734_563);
7097 
7098         // Test B.C.
7099         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 0);
7100         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == 0);
7101         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59)).dayOfGregorianCal == 0);
7102         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 0);
7103         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).dayOfGregorianCal == 0);
7104 
7105         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == -366);
7106         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == -366);
7107         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59)).dayOfGregorianCal == -366);
7108         assert(SysTime(DateTime(-1, 12, 31, 0, 0, 0)).dayOfGregorianCal == -366);
7109 
7110         assert(SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == 0);
7111         assert(SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1);
7112         assert(SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -30);
7113         assert(SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -31);
7114 
7115         assert(SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -366);
7116         assert(SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -367);
7117         assert(SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730);
7118         assert(SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731);
7119         assert(SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1095);
7120         assert(SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1096);
7121         assert(SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1460);
7122         assert(SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1461);
7123         assert(SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1826);
7124         assert(SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1827);
7125         assert(SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -2191);
7126         assert(SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -3652);
7127 
7128         assert(SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_262);
7129         assert(SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_627);
7130         assert(SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -35_794);
7131         assert(SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_160);
7132         assert(SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_524);
7133         assert(SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_889);
7134         assert(SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -37_254);
7135         assert(SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -38_715);
7136         assert(SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_413);
7137         assert(SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_778);
7138         assert(SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -109_937);
7139         assert(SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -110_302);
7140         assert(SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_097);
7141         assert(SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_462);
7142         assert(SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_827);
7143         assert(SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_621);
7144         assert(SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_986);
7145         assert(SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -183_351);
7146         assert(SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_607);
7147         assert(SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_972);
7148         assert(SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_387);
7149         assert(SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_388);
7150         assert(SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_753);
7151         assert(SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -585_118);
7152         assert(SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_325);
7153         assert(SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_690);
7154         assert(SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_484);
7155         assert(SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_485);
7156         assert(SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_850);
7157         assert(SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731_215);
7158 
7159         assert(SysTime(DateTime(-2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_502);
7160         assert(SysTime(DateTime(-2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_472);
7161         assert(SysTime(DateTime(-2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_471);
7162         assert(SysTime(DateTime(-2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_444);
7163         assert(SysTime(DateTime(-2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_443);
7164         assert(SysTime(DateTime(-2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_413);
7165         assert(SysTime(DateTime(-2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_412);
7166         assert(SysTime(DateTime(-2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_383);
7167         assert(SysTime(DateTime(-2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_382);
7168         assert(SysTime(DateTime(-2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_352);
7169         assert(SysTime(DateTime(-2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_351);
7170         assert(SysTime(DateTime(-2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_322);
7171         assert(SysTime(DateTime(-2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_321);
7172         assert(SysTime(DateTime(-2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_291);
7173         assert(SysTime(DateTime(-2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_290);
7174         assert(SysTime(DateTime(-2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_260);
7175         assert(SysTime(DateTime(-2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_259);
7176         assert(SysTime(DateTime(-2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_230);
7177         assert(SysTime(DateTime(-2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_229);
7178         assert(SysTime(DateTime(-2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_199);
7179         assert(SysTime(DateTime(-2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_198);
7180         assert(SysTime(DateTime(-2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_169);
7181         assert(SysTime(DateTime(-2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_168);
7182         assert(SysTime(DateTime(-2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_138);
7183 
7184         assert(SysTime(DateTime(-2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == -735_202);
7185         assert(SysTime(DateTime(-2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == -735_175);
7186         assert(SysTime(DateTime(-2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == -735_174);
7187         assert(SysTime(DateTime(-2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == -735_173);
7188 
7189         // Start of Hebrew Calendar
7190         assert(SysTime(DateTime(-3760, 9, 7, 0, 0, 0)).dayOfGregorianCal == -1_373_427);
7191 
7192         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7193         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7194         assert(cst.dayOfGregorianCal == 729_941);
7195         assert(ist.dayOfGregorianCal == 729_941);
7196 
7197         static void testScope(scope ref SysTime st) @safe
7198         {
7199             auto result = st.dayOfGregorianCal;
7200         }
7201     }
7202 
7203 
7204     // Test that the logic for the day of the Gregorian Calendar is consistent
7205     // between Date and SysTime.
7206     @safe unittest
7207     {
7208         import core.time;
7209         void test(Date date, SysTime st, size_t line = __LINE__)
7210         {
7211             if (date.dayOfGregorianCal != st.dayOfGregorianCal)
7212             {
7213                 throw new AssertError(format("Date [%s] SysTime [%s]", date.dayOfGregorianCal, st.dayOfGregorianCal),
7214                                       __FILE__, line);
7215             }
7216         }
7217 
7218         // Test A.D.
7219         test(Date(1, 1, 1), SysTime(DateTime(1, 1, 1, 0, 0, 0)));
7220         test(Date(1, 1, 2), SysTime(DateTime(1, 1, 2, 0, 0, 0), hnsecs(500)));
7221         test(Date(1, 2, 1), SysTime(DateTime(1, 2, 1, 0, 0, 0), hnsecs(50_000)));
7222         test(Date(2, 1, 1), SysTime(DateTime(2, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7223         test(Date(3, 1, 1), SysTime(DateTime(3, 1, 1, 12, 13, 14)));
7224         test(Date(4, 1, 1), SysTime(DateTime(4, 1, 1, 12, 13, 14), hnsecs(500)));
7225         test(Date(5, 1, 1), SysTime(DateTime(5, 1, 1, 12, 13, 14), hnsecs(50_000)));
7226         test(Date(50, 1, 1), SysTime(DateTime(50, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7227         test(Date(97, 1, 1), SysTime(DateTime(97, 1, 1, 23, 59, 59)));
7228         test(Date(100, 1, 1), SysTime(DateTime(100, 1, 1, 23, 59, 59), hnsecs(500)));
7229         test(Date(101, 1, 1), SysTime(DateTime(101, 1, 1, 23, 59, 59), hnsecs(50_000)));
7230         test(Date(105, 1, 1), SysTime(DateTime(105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7231         test(Date(200, 1, 1), SysTime(DateTime(200, 1, 1, 0, 0, 0)));
7232         test(Date(201, 1, 1), SysTime(DateTime(201, 1, 1, 0, 0, 0), hnsecs(500)));
7233         test(Date(300, 1, 1), SysTime(DateTime(300, 1, 1, 0, 0, 0), hnsecs(50_000)));
7234         test(Date(301, 1, 1), SysTime(DateTime(301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7235         test(Date(400, 1, 1), SysTime(DateTime(400, 1, 1, 12, 13, 14)));
7236         test(Date(401, 1, 1), SysTime(DateTime(401, 1, 1, 12, 13, 14), hnsecs(500)));
7237         test(Date(500, 1, 1), SysTime(DateTime(500, 1, 1, 12, 13, 14), hnsecs(50_000)));
7238         test(Date(501, 1, 1), SysTime(DateTime(501, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7239         test(Date(1000, 1, 1), SysTime(DateTime(1000, 1, 1, 23, 59, 59)));
7240         test(Date(1001, 1, 1), SysTime(DateTime(1001, 1, 1, 23, 59, 59), hnsecs(500)));
7241         test(Date(1600, 1, 1), SysTime(DateTime(1600, 1, 1, 23, 59, 59), hnsecs(50_000)));
7242         test(Date(1601, 1, 1), SysTime(DateTime(1601, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7243         test(Date(1900, 1, 1), SysTime(DateTime(1900, 1, 1, 0, 0, 0)));
7244         test(Date(1901, 1, 1), SysTime(DateTime(1901, 1, 1, 0, 0, 0), hnsecs(500)));
7245         test(Date(1945, 11, 12), SysTime(DateTime(1945, 11, 12, 0, 0, 0), hnsecs(50_000)));
7246         test(Date(1999, 1, 1), SysTime(DateTime(1999, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7247         test(Date(1999, 7, 6), SysTime(DateTime(1999, 7, 6, 12, 13, 14)));
7248         test(Date(2000, 1, 1), SysTime(DateTime(2000, 1, 1, 12, 13, 14), hnsecs(500)));
7249         test(Date(2001, 1, 1), SysTime(DateTime(2001, 1, 1, 12, 13, 14), hnsecs(50_000)));
7250 
7251         test(Date(2010, 1, 1), SysTime(DateTime(2010, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7252         test(Date(2010, 1, 31), SysTime(DateTime(2010, 1, 31, 23, 0, 0)));
7253         test(Date(2010, 2, 1), SysTime(DateTime(2010, 2, 1, 23, 59, 59), hnsecs(500)));
7254         test(Date(2010, 2, 28), SysTime(DateTime(2010, 2, 28, 23, 59, 59), hnsecs(50_000)));
7255         test(Date(2010, 3, 1), SysTime(DateTime(2010, 3, 1, 23, 59, 59), hnsecs(9_999_999)));
7256         test(Date(2010, 3, 31), SysTime(DateTime(2010, 3, 31, 0, 0, 0)));
7257         test(Date(2010, 4, 1), SysTime(DateTime(2010, 4, 1, 0, 0, 0), hnsecs(500)));
7258         test(Date(2010, 4, 30), SysTime(DateTime(2010, 4, 30, 0, 0, 0), hnsecs(50_000)));
7259         test(Date(2010, 5, 1), SysTime(DateTime(2010, 5, 1, 0, 0, 0), hnsecs(9_999_999)));
7260         test(Date(2010, 5, 31), SysTime(DateTime(2010, 5, 31, 12, 13, 14)));
7261         test(Date(2010, 6, 1), SysTime(DateTime(2010, 6, 1, 12, 13, 14), hnsecs(500)));
7262         test(Date(2010, 6, 30), SysTime(DateTime(2010, 6, 30, 12, 13, 14), hnsecs(50_000)));
7263         test(Date(2010, 7, 1), SysTime(DateTime(2010, 7, 1, 12, 13, 14), hnsecs(9_999_999)));
7264         test(Date(2010, 7, 31), SysTime(DateTime(2010, 7, 31, 23, 59, 59)));
7265         test(Date(2010, 8, 1), SysTime(DateTime(2010, 8, 1, 23, 59, 59), hnsecs(500)));
7266         test(Date(2010, 8, 31), SysTime(DateTime(2010, 8, 31, 23, 59, 59), hnsecs(50_000)));
7267         test(Date(2010, 9, 1), SysTime(DateTime(2010, 9, 1, 23, 59, 59), hnsecs(9_999_999)));
7268         test(Date(2010, 9, 30), SysTime(DateTime(2010, 9, 30, 12, 0, 0)));
7269         test(Date(2010, 10, 1), SysTime(DateTime(2010, 10, 1, 0, 12, 0), hnsecs(500)));
7270         test(Date(2010, 10, 31), SysTime(DateTime(2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
7271         test(Date(2010, 11, 1), SysTime(DateTime(2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
7272         test(Date(2010, 11, 30), SysTime(DateTime(2010, 11, 30, 0, 59, 0)));
7273         test(Date(2010, 12, 1), SysTime(DateTime(2010, 12, 1, 0, 0, 59), hnsecs(500)));
7274         test(Date(2010, 12, 31), SysTime(DateTime(2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
7275 
7276         test(Date(2012, 2, 1), SysTime(DateTime(2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
7277         test(Date(2012, 2, 28), SysTime(DateTime(2012, 2, 28, 23, 59, 0)));
7278         test(Date(2012, 2, 29), SysTime(DateTime(2012, 2, 29, 7, 7, 7), hnsecs(7)));
7279         test(Date(2012, 3, 1), SysTime(DateTime(2012, 3, 1, 7, 7, 7), hnsecs(7)));
7280 
7281         // Test B.C.
7282         test(Date(0, 12, 31), SysTime(DateTime(0, 12, 31, 0, 0, 0)));
7283         test(Date(0, 12, 30), SysTime(DateTime(0, 12, 30, 0, 0, 0), hnsecs(500)));
7284         test(Date(0, 12, 1), SysTime(DateTime(0, 12, 1, 0, 0, 0), hnsecs(50_000)));
7285         test(Date(0, 11, 30), SysTime(DateTime(0, 11, 30, 0, 0, 0), hnsecs(9_999_999)));
7286 
7287         test(Date(-1, 12, 31), SysTime(DateTime(-1, 12, 31, 12, 13, 14)));
7288         test(Date(-1, 12, 30), SysTime(DateTime(-1, 12, 30, 12, 13, 14), hnsecs(500)));
7289         test(Date(-1, 1, 1), SysTime(DateTime(-1, 1, 1, 12, 13, 14), hnsecs(50_000)));
7290         test(Date(-2, 12, 31), SysTime(DateTime(-2, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
7291         test(Date(-2, 1, 1), SysTime(DateTime(-2, 1, 1, 23, 59, 59)));
7292         test(Date(-3, 12, 31), SysTime(DateTime(-3, 12, 31, 23, 59, 59), hnsecs(500)));
7293         test(Date(-3, 1, 1), SysTime(DateTime(-3, 1, 1, 23, 59, 59), hnsecs(50_000)));
7294         test(Date(-4, 12, 31), SysTime(DateTime(-4, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7295         test(Date(-4, 1, 1), SysTime(DateTime(-4, 1, 1, 0, 0, 0)));
7296         test(Date(-5, 12, 31), SysTime(DateTime(-5, 12, 31, 0, 0, 0), hnsecs(500)));
7297         test(Date(-5, 1, 1), SysTime(DateTime(-5, 1, 1, 0, 0, 0), hnsecs(50_000)));
7298         test(Date(-9, 1, 1), SysTime(DateTime(-9, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7299 
7300         test(Date(-49, 1, 1), SysTime(DateTime(-49, 1, 1, 12, 13, 14)));
7301         test(Date(-50, 1, 1), SysTime(DateTime(-50, 1, 1, 12, 13, 14), hnsecs(500)));
7302         test(Date(-97, 1, 1), SysTime(DateTime(-97, 1, 1, 12, 13, 14), hnsecs(50_000)));
7303         test(Date(-99, 12, 31), SysTime(DateTime(-99, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
7304         test(Date(-99, 1, 1), SysTime(DateTime(-99, 1, 1, 23, 59, 59)));
7305         test(Date(-100, 1, 1), SysTime(DateTime(-100, 1, 1, 23, 59, 59), hnsecs(500)));
7306         test(Date(-101, 1, 1), SysTime(DateTime(-101, 1, 1, 23, 59, 59), hnsecs(50_000)));
7307         test(Date(-105, 1, 1), SysTime(DateTime(-105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7308         test(Date(-200, 1, 1), SysTime(DateTime(-200, 1, 1, 0, 0, 0)));
7309         test(Date(-201, 1, 1), SysTime(DateTime(-201, 1, 1, 0, 0, 0), hnsecs(500)));
7310         test(Date(-300, 1, 1), SysTime(DateTime(-300, 1, 1, 0, 0, 0), hnsecs(50_000)));
7311         test(Date(-301, 1, 1), SysTime(DateTime(-301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7312         test(Date(-400, 12, 31), SysTime(DateTime(-400, 12, 31, 12, 13, 14)));
7313         test(Date(-400, 1, 1), SysTime(DateTime(-400, 1, 1, 12, 13, 14), hnsecs(500)));
7314         test(Date(-401, 1, 1), SysTime(DateTime(-401, 1, 1, 12, 13, 14), hnsecs(50_000)));
7315         test(Date(-499, 1, 1), SysTime(DateTime(-499, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7316         test(Date(-500, 1, 1), SysTime(DateTime(-500, 1, 1, 23, 59, 59)));
7317         test(Date(-501, 1, 1), SysTime(DateTime(-501, 1, 1, 23, 59, 59), hnsecs(500)));
7318         test(Date(-1000, 1, 1), SysTime(DateTime(-1000, 1, 1, 23, 59, 59), hnsecs(50_000)));
7319         test(Date(-1001, 1, 1), SysTime(DateTime(-1001, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7320         test(Date(-1599, 1, 1), SysTime(DateTime(-1599, 1, 1, 0, 0, 0)));
7321         test(Date(-1600, 12, 31), SysTime(DateTime(-1600, 12, 31, 0, 0, 0), hnsecs(500)));
7322         test(Date(-1600, 1, 1), SysTime(DateTime(-1600, 1, 1, 0, 0, 0), hnsecs(50_000)));
7323         test(Date(-1601, 1, 1), SysTime(DateTime(-1601, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7324         test(Date(-1900, 1, 1), SysTime(DateTime(-1900, 1, 1, 12, 13, 14)));
7325         test(Date(-1901, 1, 1), SysTime(DateTime(-1901, 1, 1, 12, 13, 14), hnsecs(500)));
7326         test(Date(-1999, 1, 1), SysTime(DateTime(-1999, 1, 1, 12, 13, 14), hnsecs(50_000)));
7327         test(Date(-1999, 7, 6), SysTime(DateTime(-1999, 7, 6, 12, 13, 14), hnsecs(9_999_999)));
7328         test(Date(-2000, 12, 31), SysTime(DateTime(-2000, 12, 31, 23, 59, 59)));
7329         test(Date(-2000, 1, 1), SysTime(DateTime(-2000, 1, 1, 23, 59, 59), hnsecs(500)));
7330         test(Date(-2001, 1, 1), SysTime(DateTime(-2001, 1, 1, 23, 59, 59), hnsecs(50_000)));
7331 
7332         test(Date(-2010, 1, 1), SysTime(DateTime(-2010, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7333         test(Date(-2010, 1, 31), SysTime(DateTime(-2010, 1, 31, 0, 0, 0)));
7334         test(Date(-2010, 2, 1), SysTime(DateTime(-2010, 2, 1, 0, 0, 0), hnsecs(500)));
7335         test(Date(-2010, 2, 28), SysTime(DateTime(-2010, 2, 28, 0, 0, 0), hnsecs(50_000)));
7336         test(Date(-2010, 3, 1), SysTime(DateTime(-2010, 3, 1, 0, 0, 0), hnsecs(9_999_999)));
7337         test(Date(-2010, 3, 31), SysTime(DateTime(-2010, 3, 31, 12, 13, 14)));
7338         test(Date(-2010, 4, 1), SysTime(DateTime(-2010, 4, 1, 12, 13, 14), hnsecs(500)));
7339         test(Date(-2010, 4, 30), SysTime(DateTime(-2010, 4, 30, 12, 13, 14), hnsecs(50_000)));
7340         test(Date(-2010, 5, 1), SysTime(DateTime(-2010, 5, 1, 12, 13, 14), hnsecs(9_999_999)));
7341         test(Date(-2010, 5, 31), SysTime(DateTime(-2010, 5, 31, 23, 59, 59)));
7342         test(Date(-2010, 6, 1), SysTime(DateTime(-2010, 6, 1, 23, 59, 59), hnsecs(500)));
7343         test(Date(-2010, 6, 30), SysTime(DateTime(-2010, 6, 30, 23, 59, 59), hnsecs(50_000)));
7344         test(Date(-2010, 7, 1), SysTime(DateTime(-2010, 7, 1, 23, 59, 59), hnsecs(9_999_999)));
7345         test(Date(-2010, 7, 31), SysTime(DateTime(-2010, 7, 31, 0, 0, 0)));
7346         test(Date(-2010, 8, 1), SysTime(DateTime(-2010, 8, 1, 0, 0, 0), hnsecs(500)));
7347         test(Date(-2010, 8, 31), SysTime(DateTime(-2010, 8, 31, 0, 0, 0), hnsecs(50_000)));
7348         test(Date(-2010, 9, 1), SysTime(DateTime(-2010, 9, 1, 0, 0, 0), hnsecs(9_999_999)));
7349         test(Date(-2010, 9, 30), SysTime(DateTime(-2010, 9, 30, 12, 0, 0)));
7350         test(Date(-2010, 10, 1), SysTime(DateTime(-2010, 10, 1, 0, 12, 0), hnsecs(500)));
7351         test(Date(-2010, 10, 31), SysTime(DateTime(-2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
7352         test(Date(-2010, 11, 1), SysTime(DateTime(-2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
7353         test(Date(-2010, 11, 30), SysTime(DateTime(-2010, 11, 30, 0, 59, 0)));
7354         test(Date(-2010, 12, 1), SysTime(DateTime(-2010, 12, 1, 0, 0, 59), hnsecs(500)));
7355         test(Date(-2010, 12, 31), SysTime(DateTime(-2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
7356 
7357         test(Date(-2012, 2, 1), SysTime(DateTime(-2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
7358         test(Date(-2012, 2, 28), SysTime(DateTime(-2012, 2, 28, 23, 59, 0)));
7359         test(Date(-2012, 2, 29), SysTime(DateTime(-2012, 2, 29, 7, 7, 7), hnsecs(7)));
7360         test(Date(-2012, 3, 1), SysTime(DateTime(-2012, 3, 1, 7, 7, 7), hnsecs(7)));
7361 
7362         test(Date(-3760, 9, 7), SysTime(DateTime(-3760, 9, 7, 0, 0, 0)));
7363     }
7364 
7365 
7366     /++
7367         The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on.
7368         Setting this property does not affect the time portion of $(LREF SysTime).
7369 
7370         Params:
7371             days = The day of the Gregorian Calendar to set this $(LREF SysTime)
7372                    to.
7373      +/
7374     @property void dayOfGregorianCal(int days) @safe nothrow scope
7375     {
7376         auto hnsecs = adjTime;
7377         hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
7378 
7379         if (hnsecs < 0)
7380             hnsecs += convert!("hours", "hnsecs")(24);
7381 
7382         if (--days < 0)
7383         {
7384             hnsecs -= convert!("hours", "hnsecs")(24);
7385             ++days;
7386         }
7387 
7388         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
7389 
7390         adjTime = newDaysHNSecs + hnsecs;
7391     }
7392 
7393     ///
7394     @safe unittest
7395     {
7396         import core.time;
7397         import std.datetime.date : DateTime;
7398 
7399         auto st = SysTime(DateTime(0, 1, 1, 12, 0, 0));
7400         st.dayOfGregorianCal = 1;
7401         assert(st == SysTime(DateTime(1, 1, 1, 12, 0, 0)));
7402 
7403         st.dayOfGregorianCal = 365;
7404         assert(st == SysTime(DateTime(1, 12, 31, 12, 0, 0)));
7405 
7406         st.dayOfGregorianCal = 366;
7407         assert(st == SysTime(DateTime(2, 1, 1, 12, 0, 0)));
7408 
7409         st.dayOfGregorianCal = 0;
7410         assert(st == SysTime(DateTime(0, 12, 31, 12, 0, 0)));
7411 
7412         st.dayOfGregorianCal = -365;
7413         assert(st == SysTime(DateTime(-0, 1, 1, 12, 0, 0)));
7414 
7415         st.dayOfGregorianCal = -366;
7416         assert(st == SysTime(DateTime(-1, 12, 31, 12, 0, 0)));
7417 
7418         st.dayOfGregorianCal = 730_120;
7419         assert(st == SysTime(DateTime(2000, 1, 1, 12, 0, 0)));
7420 
7421         st.dayOfGregorianCal = 734_137;
7422         assert(st == SysTime(DateTime(2010, 12, 31, 12, 0, 0)));
7423     }
7424 
7425     @safe unittest
7426     {
7427         import core.time;
7428         void testST(SysTime orig, int day, SysTime expected, size_t line = __LINE__) @safe
7429         {
7430             orig.dayOfGregorianCal = day;
7431             if (orig != expected)
7432                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
7433         }
7434 
7435         // Test A.D.
7436         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
7437         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
7438         testST(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 1,
7439                SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7440 
7441         // Test B.C.
7442         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
7443         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 0,
7444                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7445         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(1)), 0,
7446                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
7447         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
7448 
7449         // Test Both.
7450         testST(SysTime(DateTime(-512, 7, 20, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
7451         testST(SysTime(DateTime(-513, 6, 6, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
7452         testST(SysTime(DateTime(-511, 5, 7, 23, 59, 59), hnsecs(9_999_999)), 1,
7453                SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7454 
7455         testST(SysTime(DateTime(1607, 4, 8, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
7456         testST(SysTime(DateTime(1500, 3, 9, 23, 59, 59), hnsecs(9_999_999)), 0,
7457                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7458         testST(SysTime(DateTime(999, 2, 10, 23, 59, 59), hnsecs(1)), 0,
7459                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
7460         testST(SysTime(DateTime(2007, 12, 11, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
7461 
7462 
7463         auto st = SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212));
7464 
7465         void testST2(int day, SysTime expected, size_t line = __LINE__) @safe
7466         {
7467             st.dayOfGregorianCal = day;
7468             if (st != expected)
7469                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", st, expected), __FILE__, line);
7470         }
7471 
7472         // Test A.D.
7473         testST2(1, SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)));
7474         testST2(2, SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)));
7475         testST2(32, SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)));
7476         testST2(366, SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)));
7477         testST2(731, SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)));
7478         testST2(1096, SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)));
7479         testST2(1462, SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)));
7480         testST2(17_898, SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)));
7481         testST2(35_065, SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)));
7482         testST2(36_160, SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)));
7483         testST2(36_525, SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)));
7484         testST2(37_986, SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)));
7485         testST2(72_684, SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)));
7486         testST2(73_049, SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)));
7487         testST2(109_208, SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)));
7488         testST2(109_573, SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)));
7489         testST2(145_732, SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)));
7490         testST2(146_098, SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)));
7491         testST2(182_257, SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)));
7492         testST2(182_622, SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)));
7493         testST2(364_878, SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)));
7494         testST2(365_243, SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)));
7495         testST2(584_023, SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)));
7496         testST2(584_389, SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)));
7497         testST2(693_596, SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)));
7498         testST2(693_961, SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)));
7499         testST2(729_755, SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)));
7500         testST2(730_120, SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)));
7501         testST2(730_486, SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)));
7502 
7503         testST2(733_773, SysTime(DateTime(2010, 1, 1, 12, 2, 9), msecs(212)));
7504         testST2(733_803, SysTime(DateTime(2010, 1, 31, 12, 2, 9), msecs(212)));
7505         testST2(733_804, SysTime(DateTime(2010, 2, 1, 12, 2, 9), msecs(212)));
7506         testST2(733_831, SysTime(DateTime(2010, 2, 28, 12, 2, 9), msecs(212)));
7507         testST2(733_832, SysTime(DateTime(2010, 3, 1, 12, 2, 9), msecs(212)));
7508         testST2(733_862, SysTime(DateTime(2010, 3, 31, 12, 2, 9), msecs(212)));
7509         testST2(733_863, SysTime(DateTime(2010, 4, 1, 12, 2, 9), msecs(212)));
7510         testST2(733_892, SysTime(DateTime(2010, 4, 30, 12, 2, 9), msecs(212)));
7511         testST2(733_893, SysTime(DateTime(2010, 5, 1, 12, 2, 9), msecs(212)));
7512         testST2(733_923, SysTime(DateTime(2010, 5, 31, 12, 2, 9), msecs(212)));
7513         testST2(733_924, SysTime(DateTime(2010, 6, 1, 12, 2, 9), msecs(212)));
7514         testST2(733_953, SysTime(DateTime(2010, 6, 30, 12, 2, 9), msecs(212)));
7515         testST2(733_954, SysTime(DateTime(2010, 7, 1, 12, 2, 9), msecs(212)));
7516         testST2(733_984, SysTime(DateTime(2010, 7, 31, 12, 2, 9), msecs(212)));
7517         testST2(733_985, SysTime(DateTime(2010, 8, 1, 12, 2, 9), msecs(212)));
7518         testST2(734_015, SysTime(DateTime(2010, 8, 31, 12, 2, 9), msecs(212)));
7519         testST2(734_016, SysTime(DateTime(2010, 9, 1, 12, 2, 9), msecs(212)));
7520         testST2(734_045, SysTime(DateTime(2010, 9, 30, 12, 2, 9), msecs(212)));
7521         testST2(734_046, SysTime(DateTime(2010, 10, 1, 12, 2, 9), msecs(212)));
7522         testST2(734_076, SysTime(DateTime(2010, 10, 31, 12, 2, 9), msecs(212)));
7523         testST2(734_077, SysTime(DateTime(2010, 11, 1, 12, 2, 9), msecs(212)));
7524         testST2(734_106, SysTime(DateTime(2010, 11, 30, 12, 2, 9), msecs(212)));
7525         testST2(734_107, SysTime(DateTime(2010, 12, 1, 12, 2, 9), msecs(212)));
7526         testST2(734_137, SysTime(DateTime(2010, 12, 31, 12, 2, 9), msecs(212)));
7527 
7528         testST2(734_534, SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
7529         testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
7530         testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
7531         testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
7532 
7533         testST2(734_534,  SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
7534 
7535         testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
7536         testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
7537         testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
7538 
7539         // Test B.C.
7540         testST2(0, SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)));
7541         testST2(-1, SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)));
7542         testST2(-30, SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)));
7543         testST2(-31, SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)));
7544 
7545         testST2(-366, SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)));
7546         testST2(-367, SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)));
7547         testST2(-730, SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)));
7548         testST2(-731, SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)));
7549         testST2(-1095, SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)));
7550         testST2(-1096, SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)));
7551         testST2(-1460, SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)));
7552         testST2(-1461, SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)));
7553         testST2(-1826, SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)));
7554         testST2(-1827, SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)));
7555         testST2(-2191, SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)));
7556         testST2(-3652, SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)));
7557 
7558         testST2(-18_262, SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)));
7559         testST2(-18_627, SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)));
7560         testST2(-35_794, SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)));
7561         testST2(-36_160, SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)));
7562         testST2(-36_524, SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)));
7563         testST2(-36_889, SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)));
7564         testST2(-37_254, SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)));
7565         testST2(-38_715, SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)));
7566         testST2(-73_413, SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)));
7567         testST2(-73_778, SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)));
7568         testST2(-109_937, SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)));
7569         testST2(-110_302, SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)));
7570         testST2(-146_097, SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)));
7571         testST2(-146_462, SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)));
7572         testST2(-146_827, SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)));
7573         testST2(-182_621, SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)));
7574         testST2(-182_986, SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)));
7575         testST2(-183_351, SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)));
7576         testST2(-365_607, SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)));
7577         testST2(-365_972, SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)));
7578         testST2(-584_387, SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)));
7579         testST2(-584_388, SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)));
7580         testST2(-584_753, SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)));
7581         testST2(-585_118, SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)));
7582         testST2(-694_325, SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)));
7583         testST2(-694_690, SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)));
7584         testST2(-730_484, SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)));
7585         testST2(-730_485, SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)));
7586         testST2(-730_850, SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)));
7587         testST2(-731_215, SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)));
7588 
7589         testST2(-734_502, SysTime(DateTime(-2010, 1, 1, 12, 2, 9), msecs(212)));
7590         testST2(-734_472, SysTime(DateTime(-2010, 1, 31, 12, 2, 9), msecs(212)));
7591         testST2(-734_471, SysTime(DateTime(-2010, 2, 1, 12, 2, 9), msecs(212)));
7592         testST2(-734_444, SysTime(DateTime(-2010, 2, 28, 12, 2, 9), msecs(212)));
7593         testST2(-734_443, SysTime(DateTime(-2010, 3, 1, 12, 2, 9), msecs(212)));
7594         testST2(-734_413, SysTime(DateTime(-2010, 3, 31, 12, 2, 9), msecs(212)));
7595         testST2(-734_412, SysTime(DateTime(-2010, 4, 1, 12, 2, 9), msecs(212)));
7596         testST2(-734_383, SysTime(DateTime(-2010, 4, 30, 12, 2, 9), msecs(212)));
7597         testST2(-734_382, SysTime(DateTime(-2010, 5, 1, 12, 2, 9), msecs(212)));
7598         testST2(-734_352, SysTime(DateTime(-2010, 5, 31, 12, 2, 9), msecs(212)));
7599         testST2(-734_351, SysTime(DateTime(-2010, 6, 1, 12, 2, 9), msecs(212)));
7600         testST2(-734_322, SysTime(DateTime(-2010, 6, 30, 12, 2, 9), msecs(212)));
7601         testST2(-734_321, SysTime(DateTime(-2010, 7, 1, 12, 2, 9), msecs(212)));
7602         testST2(-734_291, SysTime(DateTime(-2010, 7, 31, 12, 2, 9), msecs(212)));
7603         testST2(-734_290, SysTime(DateTime(-2010, 8, 1, 12, 2, 9), msecs(212)));
7604         testST2(-734_260, SysTime(DateTime(-2010, 8, 31, 12, 2, 9), msecs(212)));
7605         testST2(-734_259, SysTime(DateTime(-2010, 9, 1, 12, 2, 9), msecs(212)));
7606         testST2(-734_230, SysTime(DateTime(-2010, 9, 30, 12, 2, 9), msecs(212)));
7607         testST2(-734_229, SysTime(DateTime(-2010, 10, 1, 12, 2, 9), msecs(212)));
7608         testST2(-734_199, SysTime(DateTime(-2010, 10, 31, 12, 2, 9), msecs(212)));
7609         testST2(-734_198, SysTime(DateTime(-2010, 11, 1, 12, 2, 9), msecs(212)));
7610         testST2(-734_169, SysTime(DateTime(-2010, 11, 30, 12, 2, 9), msecs(212)));
7611         testST2(-734_168, SysTime(DateTime(-2010, 12, 1, 12, 2, 9), msecs(212)));
7612         testST2(-734_138, SysTime(DateTime(-2010, 12, 31, 12, 2, 9), msecs(212)));
7613 
7614         testST2(-735_202, SysTime(DateTime(-2012, 2, 1, 12, 2, 9), msecs(212)));
7615         testST2(-735_175, SysTime(DateTime(-2012, 2, 28, 12, 2, 9), msecs(212)));
7616         testST2(-735_174, SysTime(DateTime(-2012, 2, 29, 12, 2, 9), msecs(212)));
7617         testST2(-735_173, SysTime(DateTime(-2012, 3, 1, 12, 2, 9), msecs(212)));
7618 
7619         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7620         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7621         static assert(!__traits(compiles, cst.dayOfGregorianCal = 7));
7622         static assert(!__traits(compiles, ist.dayOfGregorianCal = 7));
7623 
7624         static void testScope(scope ref SysTime st) @safe
7625         {
7626             st.dayOfGregorianCal = 42;
7627         }
7628     }
7629 
7630 
7631     /++
7632         The ISO 8601 week of the year that this $(LREF SysTime) is in.
7633 
7634         See_Also:
7635             $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date).
7636       +/
7637     @property ubyte isoWeek() @safe const nothrow scope
7638     {
7639         return (cast(Date) this).isoWeek;
7640     }
7641 
7642     ///
7643     @safe unittest
7644     {
7645         import core.time;
7646         import std.datetime.date : Date;
7647 
7648         auto st = SysTime(Date(1999, 7, 6));
7649         const cst = SysTime(Date(2010, 5, 1));
7650         immutable ist = SysTime(Date(2015, 10, 10));
7651 
7652         assert(st.isoWeek == 27);
7653         assert(cst.isoWeek == 17);
7654         assert(ist.isoWeek == 41);
7655     }
7656 
7657     @safe unittest
7658     {
7659         static void testScope(scope ref SysTime st) @safe
7660         {
7661             auto result = st.isoWeek;
7662         }
7663     }
7664 
7665 
7666     /++
7667         $(LREF SysTime) for the last day in the month that this Date is in.
7668         The time portion of endOfMonth is always 23:59:59.9999999.
7669       +/
7670     @property SysTime endOfMonth() @safe const nothrow scope
7671     {
7672         immutable hnsecs = adjTime;
7673         immutable days = getUnitsFromHNSecs!"days"(hnsecs);
7674 
7675         auto date = Date(cast(int) days + 1).endOfMonth;
7676         auto newDays = date.dayOfGregorianCal - 1;
7677         long theTimeHNSecs;
7678 
7679         if (newDays < 0)
7680         {
7681             theTimeHNSecs = -1;
7682             ++newDays;
7683         }
7684         else
7685             theTimeHNSecs = convert!("days", "hnsecs")(1) - 1;
7686 
7687         immutable newDaysHNSecs = convert!("days", "hnsecs")(newDays);
7688 
7689         auto retval = SysTime(this._stdTime, this._timezone);
7690         retval.adjTime = newDaysHNSecs + theTimeHNSecs;
7691 
7692         return retval;
7693     }
7694 
7695     ///
7696     @safe unittest
7697     {
7698         import core.time : msecs, usecs, hnsecs;
7699         import std.datetime.date : DateTime;
7700 
7701         assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonth ==
7702                SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7703 
7704         assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0), msecs(24)).endOfMonth ==
7705                SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7706 
7707         assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27), usecs(5203)).endOfMonth ==
7708                SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7709 
7710         assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9), hnsecs(12345)).endOfMonth ==
7711                SysTime(DateTime(2000, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7712     }
7713 
7714     @safe unittest
7715     {
7716         import core.time;
7717         // Test A.D.
7718         assert(SysTime(Date(1999, 1, 1)).endOfMonth == SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7719         assert(SysTime(Date(1999, 2, 1)).endOfMonth == SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7720         assert(SysTime(Date(2000, 2, 1)).endOfMonth == SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7721         assert(SysTime(Date(1999, 3, 1)).endOfMonth == SysTime(DateTime(1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
7722         assert(SysTime(Date(1999, 4, 1)).endOfMonth == SysTime(DateTime(1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
7723         assert(SysTime(Date(1999, 5, 1)).endOfMonth == SysTime(DateTime(1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
7724         assert(SysTime(Date(1999, 6, 1)).endOfMonth == SysTime(DateTime(1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7725         assert(SysTime(Date(1999, 7, 1)).endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7726         assert(SysTime(Date(1999, 8, 1)).endOfMonth == SysTime(DateTime(1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
7727         assert(SysTime(Date(1999, 9, 1)).endOfMonth == SysTime(DateTime(1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
7728         assert(SysTime(Date(1999, 10, 1)).endOfMonth == SysTime(DateTime(1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
7729         assert(SysTime(Date(1999, 11, 1)).endOfMonth == SysTime(DateTime(1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
7730         assert(SysTime(Date(1999, 12, 1)).endOfMonth == SysTime(DateTime(1999, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7731 
7732         // Test B.C.
7733         assert(SysTime(Date(-1999, 1, 1)).endOfMonth == SysTime(DateTime(-1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7734         assert(SysTime(Date(-1999, 2, 1)).endOfMonth == SysTime(DateTime(-1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7735         assert(SysTime(Date(-2000, 2, 1)).endOfMonth == SysTime(DateTime(-2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7736         assert(SysTime(Date(-1999, 3, 1)).endOfMonth == SysTime(DateTime(-1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
7737         assert(SysTime(Date(-1999, 4, 1)).endOfMonth == SysTime(DateTime(-1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
7738         assert(SysTime(Date(-1999, 5, 1)).endOfMonth == SysTime(DateTime(-1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
7739         assert(SysTime(Date(-1999, 6, 1)).endOfMonth == SysTime(DateTime(-1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7740         assert(SysTime(Date(-1999, 7, 1)).endOfMonth == SysTime(DateTime(-1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7741         assert(SysTime(Date(-1999, 8, 1)).endOfMonth == SysTime(DateTime(-1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
7742         assert(SysTime(Date(-1999, 9, 1)).endOfMonth == SysTime(DateTime(-1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
7743         assert(SysTime(Date(-1999, 10, 1)).endOfMonth ==
7744                SysTime(DateTime(-1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
7745         assert(SysTime(Date(-1999, 11, 1)).endOfMonth ==
7746                SysTime(DateTime(-1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
7747         assert(SysTime(Date(-1999, 12, 1)).endOfMonth ==
7748                SysTime(DateTime(-1999, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7749 
7750         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7751         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7752         assert(cst.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7753         assert(ist.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7754 
7755         static void testScope(scope ref SysTime st) @safe
7756         {
7757             auto result = st.endOfMonth;
7758         }
7759     }
7760 
7761 
7762     /++
7763         The last day in the month that this $(LREF SysTime) is in.
7764       +/
7765     @property ubyte daysInMonth() @safe const nothrow scope
7766     {
7767         return Date(dayOfGregorianCal).daysInMonth;
7768     }
7769 
7770     ///
7771     @safe unittest
7772     {
7773         import core.time;
7774         import std.datetime.date : DateTime;
7775 
7776         assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).daysInMonth == 31);
7777         assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0)).daysInMonth == 28);
7778         assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27)).daysInMonth == 29);
7779         assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9)).daysInMonth == 30);
7780     }
7781 
7782     @safe unittest
7783     {
7784         import core.time;
7785         // Test A.D.
7786         assert(SysTime(DateTime(1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
7787         assert(SysTime(DateTime(1999, 2, 1, 17, 13, 12)).daysInMonth == 28);
7788         assert(SysTime(DateTime(2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
7789         assert(SysTime(DateTime(1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
7790         assert(SysTime(DateTime(1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
7791         assert(SysTime(DateTime(1999, 5, 1, 15, 13, 12)).daysInMonth == 31);
7792         assert(SysTime(DateTime(1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
7793         assert(SysTime(DateTime(1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
7794         assert(SysTime(DateTime(1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
7795         assert(SysTime(DateTime(1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
7796         assert(SysTime(DateTime(1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
7797         assert(SysTime(DateTime(1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
7798         assert(SysTime(DateTime(1999, 12, 1, 12, 52, 13)).daysInMonth == 31);
7799 
7800         // Test B.C.
7801         assert(SysTime(DateTime(-1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
7802         assert(SysTime(DateTime(-1999, 2, 1, 7, 13, 12)).daysInMonth == 28);
7803         assert(SysTime(DateTime(-2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
7804         assert(SysTime(DateTime(-1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
7805         assert(SysTime(DateTime(-1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
7806         assert(SysTime(DateTime(-1999, 5, 1, 5, 13, 12)).daysInMonth == 31);
7807         assert(SysTime(DateTime(-1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
7808         assert(SysTime(DateTime(-1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
7809         assert(SysTime(DateTime(-1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
7810         assert(SysTime(DateTime(-1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
7811         assert(SysTime(DateTime(-1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
7812         assert(SysTime(DateTime(-1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
7813         assert(SysTime(DateTime(-1999, 12, 1, 12, 52, 13)).daysInMonth == 31);
7814 
7815         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7816         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7817         assert(cst.daysInMonth == 31);
7818         assert(ist.daysInMonth == 31);
7819 
7820         static void testScope(scope ref SysTime st) @safe
7821         {
7822             auto result = st.daysInMonth;
7823         }
7824     }
7825 
7826 
7827     /++
7828         Whether the current year is a date in A.D.
7829       +/
7830     @property bool isAD() @safe const nothrow scope
7831     {
7832         return adjTime >= 0;
7833     }
7834 
7835     ///
7836     @safe unittest
7837     {
7838         import core.time;
7839         import std.datetime.date : DateTime;
7840 
7841         assert(SysTime(DateTime(1, 1, 1, 12, 7, 0)).isAD);
7842         assert(SysTime(DateTime(2010, 12, 31, 0, 0, 0)).isAD);
7843         assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
7844         assert(!SysTime(DateTime(-2010, 1, 1, 2, 2, 2)).isAD);
7845     }
7846 
7847     @safe unittest
7848     {
7849         import core.time;
7850         assert(SysTime(DateTime(2010, 7, 4, 12, 0, 9)).isAD);
7851         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).isAD);
7852         assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
7853         assert(!SysTime(DateTime(0, 1, 1, 23, 59, 59)).isAD);
7854         assert(!SysTime(DateTime(-1, 1, 1, 23 ,59 ,59)).isAD);
7855         assert(!SysTime(DateTime(-2010, 7, 4, 12, 2, 2)).isAD);
7856 
7857         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7858         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7859         assert(cst.isAD);
7860         assert(ist.isAD);
7861 
7862         static void testScope(scope ref SysTime st) @safe
7863         {
7864             auto result = st.isAD;
7865         }
7866     }
7867 
7868 
7869     /++
7870         The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day)
7871         for this $(LREF SysTime) at the given time. For example,
7872         prior to noon, 1996-03-31 would be the Julian day number 2_450_173, so
7873         this function returns 2_450_173, while from noon onward, the Julian
7874         day number would be 2_450_174, so this function returns 2_450_174.
7875       +/
7876     @property long julianDay() @safe const nothrow scope
7877     {
7878         immutable jd = dayOfGregorianCal + 1_721_425;
7879         return hour < 12 ? jd - 1 : jd;
7880     }
7881 
7882     @safe unittest
7883     {
7884         import core.time;
7885         assert(SysTime(DateTime(-4713, 11, 24, 0, 0, 0)).julianDay == -1);
7886         assert(SysTime(DateTime(-4713, 11, 24, 12, 0, 0)).julianDay == 0);
7887 
7888         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).julianDay == 1_721_424);
7889         assert(SysTime(DateTime(0, 12, 31, 12, 0, 0)).julianDay == 1_721_425);
7890 
7891         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).julianDay == 1_721_425);
7892         assert(SysTime(DateTime(1, 1, 1, 12, 0, 0)).julianDay == 1_721_426);
7893 
7894         assert(SysTime(DateTime(1582, 10, 15, 0, 0, 0)).julianDay == 2_299_160);
7895         assert(SysTime(DateTime(1582, 10, 15, 12, 0, 0)).julianDay == 2_299_161);
7896 
7897         assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).julianDay == 2_400_000);
7898         assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).julianDay == 2_400_001);
7899 
7900         assert(SysTime(DateTime(1982, 1, 4, 0, 0, 0)).julianDay == 2_444_973);
7901         assert(SysTime(DateTime(1982, 1, 4, 12, 0, 0)).julianDay == 2_444_974);
7902 
7903         assert(SysTime(DateTime(1996, 3, 31, 0, 0, 0)).julianDay == 2_450_173);
7904         assert(SysTime(DateTime(1996, 3, 31, 12, 0, 0)).julianDay == 2_450_174);
7905 
7906         assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).julianDay == 2_455_432);
7907         assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).julianDay == 2_455_433);
7908 
7909         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7910         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7911         assert(cst.julianDay == 2_451_366);
7912         assert(ist.julianDay == 2_451_366);
7913 
7914         static void testScope(scope ref SysTime st) @safe
7915         {
7916             auto result = st.julianDay;
7917         }
7918     }
7919 
7920 
7921     /++
7922         The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for
7923         any time on this date (since, the modified Julian day changes at
7924         midnight).
7925       +/
7926     @property long modJulianDay() @safe const nothrow scope
7927     {
7928         return dayOfGregorianCal + 1_721_425 - 2_400_001;
7929     }
7930 
7931     @safe unittest
7932     {
7933         import core.time;
7934         assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).modJulianDay == 0);
7935         assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).modJulianDay == 0);
7936 
7937         assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).modJulianDay == 55_432);
7938         assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).modJulianDay == 55_432);
7939 
7940         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7941         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7942         assert(cst.modJulianDay == 51_365);
7943         assert(ist.modJulianDay == 51_365);
7944 
7945         static void testScope(scope ref SysTime st) @safe
7946         {
7947             auto result = st.modJulianDay;
7948         }
7949     }
7950 
7951 
7952     /++
7953         Returns a $(REF Date,std,datetime,date) equivalent to this $(LREF SysTime).
7954       +/
7955     Date opCast(T)() @safe const nothrow scope
7956         if (is(immutable T == immutable Date))
7957     {
7958         return Date(dayOfGregorianCal);
7959     }
7960 
7961     @safe unittest
7962     {
7963         import core.time;
7964         assert(cast(Date) SysTime(Date(1999, 7, 6)) == Date(1999, 7, 6));
7965         assert(cast(Date) SysTime(Date(2000, 12, 31)) == Date(2000, 12, 31));
7966         assert(cast(Date) SysTime(Date(2001, 1, 1)) == Date(2001, 1, 1));
7967 
7968         assert(cast(Date) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == Date(1999, 7, 6));
7969         assert(cast(Date) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == Date(2000, 12, 31));
7970         assert(cast(Date) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == Date(2001, 1, 1));
7971 
7972         assert(cast(Date) SysTime(Date(-1999, 7, 6)) == Date(-1999, 7, 6));
7973         assert(cast(Date) SysTime(Date(-2000, 12, 31)) == Date(-2000, 12, 31));
7974         assert(cast(Date) SysTime(Date(-2001, 1, 1)) == Date(-2001, 1, 1));
7975 
7976         assert(cast(Date) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == Date(-1999, 7, 6));
7977         assert(cast(Date) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == Date(-2000, 12, 31));
7978         assert(cast(Date) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == Date(-2001, 1, 1));
7979 
7980         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7981         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7982         assert(cast(Date) cst != Date.init);
7983         assert(cast(Date) ist != Date.init);
7984 
7985         static void testScope(scope ref SysTime st) @safe
7986         {
7987             auto result = cast(Date) st;
7988         }
7989     }
7990 
7991 
7992     /++
7993         Returns a $(REF DateTime,std,datetime,date) equivalent to this
7994         $(LREF SysTime).
7995       +/
7996     DateTime opCast(T)() @safe const nothrow scope
7997         if (is(immutable T == immutable DateTime))
7998     {
7999         try
8000         {
8001             auto hnsecs = adjTime;
8002             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8003 
8004             if (hnsecs < 0)
8005             {
8006                 hnsecs += convert!("hours", "hnsecs")(24);
8007                 --days;
8008             }
8009 
8010             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8011             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8012             immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
8013 
8014             return DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour, cast(int) minute, cast(int) second));
8015         }
8016         catch (Exception e)
8017             assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw.");
8018     }
8019 
8020     @safe unittest
8021     {
8022         import core.time;
8023         assert(cast(DateTime) SysTime(DateTime(1, 1, 6, 7, 12, 22)) == DateTime(1, 1, 6, 7, 12, 22));
8024         assert(cast(DateTime) SysTime(DateTime(1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(1, 1, 6, 7, 12, 22));
8025         assert(cast(DateTime) SysTime(Date(1999, 7, 6)) == DateTime(1999, 7, 6, 0, 0, 0));
8026         assert(cast(DateTime) SysTime(Date(2000, 12, 31)) == DateTime(2000, 12, 31, 0, 0, 0));
8027         assert(cast(DateTime) SysTime(Date(2001, 1, 1)) == DateTime(2001, 1, 1, 0, 0, 0));
8028 
8029         assert(cast(DateTime) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == DateTime(1999, 7, 6, 12, 10, 9));
8030         assert(cast(DateTime) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == DateTime(2000, 12, 31, 13, 11, 10));
8031         assert(cast(DateTime) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == DateTime(2001, 1, 1, 14, 12, 11));
8032 
8033         assert(cast(DateTime) SysTime(DateTime(-1, 1, 6, 7, 12, 22)) == DateTime(-1, 1, 6, 7, 12, 22));
8034         assert(cast(DateTime) SysTime(DateTime(-1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(-1, 1, 6, 7, 12, 22));
8035         assert(cast(DateTime) SysTime(Date(-1999, 7, 6)) == DateTime(-1999, 7, 6, 0, 0, 0));
8036         assert(cast(DateTime) SysTime(Date(-2000, 12, 31)) == DateTime(-2000, 12, 31, 0, 0, 0));
8037         assert(cast(DateTime) SysTime(Date(-2001, 1, 1)) == DateTime(-2001, 1, 1, 0, 0, 0));
8038 
8039         assert(cast(DateTime) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == DateTime(-1999, 7, 6, 12, 10, 9));
8040         assert(cast(DateTime) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == DateTime(-2000, 12, 31, 13, 11, 10));
8041         assert(cast(DateTime) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == DateTime(-2001, 1, 1, 14, 12, 11));
8042 
8043         assert(cast(DateTime) SysTime(DateTime(2011, 1, 13, 8, 17, 2), msecs(296), LocalTime()) ==
8044                DateTime(2011, 1, 13, 8, 17, 2));
8045 
8046         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8047         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8048         assert(cast(DateTime) cst != DateTime.init);
8049         assert(cast(DateTime) ist != DateTime.init);
8050 
8051         static void testScope(scope ref SysTime st) @safe
8052         {
8053             auto result = cast(DateTime) st;
8054         }
8055     }
8056 
8057 
8058     /++
8059         Returns a $(REF TimeOfDay,std,datetime,date) equivalent to this
8060         $(LREF SysTime).
8061       +/
8062     TimeOfDay opCast(T)() @safe const nothrow scope
8063         if (is(immutable T == immutable TimeOfDay))
8064     {
8065         try
8066         {
8067             auto hnsecs = adjTime;
8068             hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
8069 
8070             if (hnsecs < 0)
8071                 hnsecs += convert!("hours", "hnsecs")(24);
8072 
8073             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8074             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8075             immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
8076 
8077             return TimeOfDay(cast(int) hour, cast(int) minute, cast(int) second);
8078         }
8079         catch (Exception e)
8080             assert(0, "TimeOfDay's constructor threw.");
8081     }
8082 
8083     @safe unittest
8084     {
8085         import core.time;
8086         assert(cast(TimeOfDay) SysTime(Date(1999, 7, 6)) == TimeOfDay(0, 0, 0));
8087         assert(cast(TimeOfDay) SysTime(Date(2000, 12, 31)) == TimeOfDay(0, 0, 0));
8088         assert(cast(TimeOfDay) SysTime(Date(2001, 1, 1)) == TimeOfDay(0, 0, 0));
8089 
8090         assert(cast(TimeOfDay) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
8091         assert(cast(TimeOfDay) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
8092         assert(cast(TimeOfDay) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11));
8093 
8094         assert(cast(TimeOfDay) SysTime(Date(-1999, 7, 6)) == TimeOfDay(0, 0, 0));
8095         assert(cast(TimeOfDay) SysTime(Date(-2000, 12, 31)) == TimeOfDay(0, 0, 0));
8096         assert(cast(TimeOfDay) SysTime(Date(-2001, 1, 1)) == TimeOfDay(0, 0, 0));
8097 
8098         assert(cast(TimeOfDay) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
8099         assert(cast(TimeOfDay) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
8100         assert(cast(TimeOfDay) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11));
8101 
8102         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8103         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8104         assert(cast(TimeOfDay) cst != TimeOfDay.init);
8105         assert(cast(TimeOfDay) ist != TimeOfDay.init);
8106 
8107         static void testScope(scope ref SysTime st) @safe
8108         {
8109             auto result = cast(TimeOfDay) st;
8110         }
8111     }
8112 
8113 
8114     // Temporary hack until bug https://issues.dlang.org/show_bug.cgi?id=4867 is fixed.
8115     // This allows assignment from const(SysTime) to SysTime.
8116     // It may be a good idea to keep it though, since casting from a type to itself
8117     // should be allowed, and it doesn't work without this opCast() since opCast()
8118     // has already been defined for other types.
8119     SysTime opCast(T)() @safe const pure nothrow scope
8120         if (is(immutable T == immutable SysTime))
8121     {
8122         return SysTime(_stdTime, _timezone);
8123     }
8124 
8125     @safe unittest
8126     {
8127         static void testScope(scope ref SysTime st) @safe
8128         {
8129             auto result = cast(SysTime) st;
8130         }
8131     }
8132 
8133 
8134     /++
8135         Converts this $(LREF SysTime) to a string with the format
8136         YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds and TZ is time
8137         zone).
8138 
8139         Note that the number of digits in the fractional seconds varies with the
8140         number of fractional seconds. It's a maximum of 7 (which would be
8141         hnsecs), but only has as many as are necessary to hold the correct value
8142         (so no trailing zeroes), and if there are no fractional seconds, then
8143         there is no decimal point.
8144 
8145         If this $(LREF SysTime)'s time zone is
8146         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
8147         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
8148         (e.g. +0100 or -0700). Note that the offset from UTC is $(I not) enough
8149         to uniquely identify the time zone.
8150 
8151         Time zone offsets will be in the form +HHMM or -HHMM.
8152 
8153         $(RED Warning:
8154             Previously, toISOString did the same as $(LREF toISOExtString) and
8155             generated +HH:MM or -HH:MM for the time zone when it was not
8156             $(REF LocalTime,std,datetime,timezone) or
8157             $(REF UTC,std,datetime,timezone), which is not in conformance with
8158             ISO 8601 for the non-extended string format. This has now been
8159             fixed. However, for now, fromISOString will continue to accept the
8160             extended format for the time zone so that any code which has been
8161             writing out the result of toISOString to read in later will continue
8162             to work. The current behavior will be kept until July 2019 at which
8163             point, fromISOString will be fixed to be standards compliant.)
8164 
8165         Params:
8166             writer = A `char` accepting
8167             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8168         Returns:
8169             A `string` when not using an output range; `void` otherwise.
8170       +/
8171     string toISOString() @safe const nothrow scope
8172     {
8173         import std.array : appender;
8174         auto app = appender!string();
8175         app.reserve(30);
8176         try
8177             toISOString(app);
8178         catch (Exception e)
8179             assert(0, "toISOString() threw.");
8180         return app.data;
8181     }
8182 
8183     /// ditto
8184     void toISOString(W)(ref W writer) const scope
8185     if (isOutputRange!(W, char))
8186     {
8187         immutable adjustedTime = adjTime;
8188         long hnsecs = adjustedTime;
8189 
8190         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8191 
8192         if (hnsecs < 0)
8193         {
8194             hnsecs += convert!("hours", "hnsecs")(24);
8195             --days;
8196         }
8197 
8198         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8199         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8200         immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
8201 
8202         auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
8203                                       cast(int) minute, cast(int) second));
8204 
8205         if (_timezone is LocalTime())
8206         {
8207             dateTime.toISOString(writer);
8208             fracSecsToISOString(writer, cast(int) hnsecs);
8209             return;
8210         }
8211 
8212         if (_timezone is UTC())
8213         {
8214             dateTime.toISOString(writer);
8215             fracSecsToISOString(writer, cast(int) hnsecs);
8216             put(writer, 'Z');
8217             return;
8218         }
8219 
8220         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
8221 
8222         dateTime.toISOString(writer);
8223         fracSecsToISOString(writer, cast(int) hnsecs);
8224         SimpleTimeZone.toISOExtString(writer, utcOffset);
8225     }
8226 
8227     ///
8228     @safe unittest
8229     {
8230         import core.time : msecs, hnsecs;
8231         import std.datetime.date : DateTime;
8232 
8233         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOString() ==
8234                "20100704T070612");
8235 
8236         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOString() ==
8237                "19981225T021500.024");
8238 
8239         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOString() ==
8240                "00000105T230959");
8241 
8242         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOString() ==
8243                "-00040105T000002.052092");
8244     }
8245 
8246     @safe unittest
8247     {
8248         import core.time;
8249         // Test A.D.
8250         assert(SysTime(DateTime.init, UTC()).toISOString() == "00010101T000000Z");
8251         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOString() == "00010101T000000.0000001Z");
8252 
8253         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOString() == "00091204T000000");
8254         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOString() == "00991204T050612");
8255         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOString() == "09991204T134459");
8256         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOString() == "99990704T235959");
8257         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOString() == "+100001020T010101");
8258 
8259         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "00091204T000000.042");
8260         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "00991204T050612.1");
8261         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "09991204T134459.04502");
8262         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "99990704T235959.0000012");
8263         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "+100001020T010101.050789");
8264 
8265         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8266                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOString() ==
8267                "20121221T121212-06:00");
8268 
8269         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8270                        new immutable SimpleTimeZone(dur!"minutes"(420))).toISOString() ==
8271                "20121221T121212+07:00");
8272 
8273         // Test B.C.
8274         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOString() ==
8275                "00001231T235959.9999999Z");
8276         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOString() == "00001231T235959.0000001Z");
8277         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOString() == "00001231T235959Z");
8278 
8279         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOString() == "00001204T001204");
8280         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOString() == "-00091204T000000");
8281         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOString() == "-00991204T050612");
8282         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOString() == "-09991204T134459");
8283         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOString() == "-99990704T235959");
8284         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOString() == "-100001020T010101");
8285 
8286         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOString() == "00001204T000000.007");
8287         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "-00091204T000000.042");
8288         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "-00991204T050612.1");
8289         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "-09991204T134459.04502");
8290         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "-99990704T235959.0000012");
8291         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "-100001020T010101.050789");
8292 
8293         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8294         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8295         assert(cst.toISOString() == "19990706T123033");
8296         assert(ist.toISOString() == "19990706T123033");
8297 
8298         static void testScope(scope ref SysTime st) @safe
8299         {
8300             auto result = st.toISOString();
8301         }
8302     }
8303 
8304 
8305 
8306     /++
8307         Converts this $(LREF SysTime) to a string with the format
8308         YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
8309         is the time zone).
8310 
8311         Note that the number of digits in the fractional seconds varies with the
8312         number of fractional seconds. It's a maximum of 7 (which would be
8313         hnsecs), but only has as many as are necessary to hold the correct value
8314         (so no trailing zeroes), and if there are no fractional seconds, then
8315         there is no decimal point.
8316 
8317         If this $(LREF SysTime)'s time zone is
8318         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
8319         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
8320         (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not)
8321         enough to uniquely identify the time zone.
8322 
8323         Time zone offsets will be in the form +HH:MM or -HH:MM.
8324 
8325         Params:
8326             writer = A `char` accepting
8327             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8328         Returns:
8329             A `string` when not using an output range; `void` otherwise.
8330       +/
8331     string toISOExtString() @safe const nothrow scope
8332     {
8333         import std.array : appender;
8334         auto app = appender!string();
8335         app.reserve(35);
8336         try
8337             toISOExtString(app);
8338         catch (Exception e)
8339             assert(0, "toISOExtString() threw.");
8340         return app.data;
8341     }
8342 
8343     /// ditto
8344     void toISOExtString(W)(ref W writer) const scope
8345     if (isOutputRange!(W, char))
8346     {
8347         immutable adjustedTime = adjTime;
8348         long hnsecs = adjustedTime;
8349 
8350         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8351 
8352         if (hnsecs < 0)
8353         {
8354             hnsecs += convert!("hours", "hnsecs")(24);
8355             --days;
8356         }
8357 
8358         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8359         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8360         immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
8361 
8362         immutable dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
8363                                       cast(int) minute, cast(int) second));
8364 
8365         if (_timezone is LocalTime())
8366         {
8367             dateTime.toISOExtString(writer);
8368             fracSecsToISOString(writer, cast(int) hnsecs);
8369             return;
8370         }
8371 
8372         if (_timezone is UTC())
8373         {
8374             dateTime.toISOExtString(writer);
8375             fracSecsToISOString(writer, cast(int) hnsecs);
8376             put(writer, 'Z');
8377             return;
8378         }
8379 
8380         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
8381 
8382         dateTime.toISOExtString(writer);
8383         fracSecsToISOString(writer, cast(int) hnsecs);
8384         SimpleTimeZone.toISOExtString(writer, utcOffset);
8385     }
8386 
8387     ///
8388     @safe unittest
8389     {
8390         import core.time : msecs, hnsecs;
8391         import std.datetime.date : DateTime;
8392 
8393         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOExtString() ==
8394                "2010-07-04T07:06:12");
8395 
8396         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOExtString() ==
8397                "1998-12-25T02:15:00.024");
8398 
8399         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOExtString() ==
8400                "0000-01-05T23:09:59");
8401 
8402         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString() ==
8403                "-0004-01-05T00:00:02.052092");
8404     }
8405 
8406     @safe unittest
8407     {
8408         import core.time;
8409         // Test A.D.
8410         assert(SysTime(DateTime.init, UTC()).toISOExtString() == "0001-01-01T00:00:00Z");
8411         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOExtString() ==
8412                "0001-01-01T00:00:00.0000001Z");
8413 
8414         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00");
8415         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12");
8416         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59");
8417         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59");
8418         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01");
8419 
8420         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "0009-12-04T00:00:00.042");
8421         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "0099-12-04T05:06:12.1");
8422         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() == "0999-12-04T13:44:59.04502");
8423         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() == "9999-07-04T23:59:59.0000012");
8424         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
8425                "+10000-10-20T01:01:01.050789");
8426 
8427         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8428                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOExtString() ==
8429                "2012-12-21T12:12:12-06:00");
8430 
8431         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8432                        new immutable SimpleTimeZone(dur!"minutes"(420))).toISOExtString() ==
8433                "2012-12-21T12:12:12+07:00");
8434 
8435         // Test B.C.
8436         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOExtString() ==
8437                "0000-12-31T23:59:59.9999999Z");
8438         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOExtString() ==
8439                "0000-12-31T23:59:59.0000001Z");
8440         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOExtString() == "0000-12-31T23:59:59Z");
8441 
8442         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04");
8443         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00");
8444         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12");
8445         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59");
8446         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59");
8447         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01");
8448 
8449         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOExtString() == "0000-12-04T00:00:00.007");
8450         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "-0009-12-04T00:00:00.042");
8451         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "-0099-12-04T05:06:12.1");
8452         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() ==
8453                "-0999-12-04T13:44:59.04502");
8454         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() ==
8455                "-9999-07-04T23:59:59.0000012");
8456         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
8457                "-10000-10-20T01:01:01.050789");
8458 
8459         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8460         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8461         assert(cst.toISOExtString() == "1999-07-06T12:30:33");
8462         assert(ist.toISOExtString() == "1999-07-06T12:30:33");
8463 
8464         static void testScope(scope ref SysTime st) @safe
8465         {
8466             auto result = st.toISOExtString();
8467         }
8468     }
8469 
8470     /++
8471         Converts this $(LREF SysTime) to a string with the format
8472         YYYY-Mon-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
8473         is the time zone).
8474 
8475         Note that the number of digits in the fractional seconds varies with the
8476         number of fractional seconds. It's a maximum of 7 (which would be
8477         hnsecs), but only has as many as are necessary to hold the correct value
8478         (so no trailing zeroes), and if there are no fractional seconds, then
8479         there is no decimal point.
8480 
8481         If this $(LREF SysTime)'s time zone is
8482         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
8483         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
8484         (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not)
8485         enough to uniquely identify the time zone.
8486 
8487         Time zone offsets will be in the form +HH:MM or -HH:MM.
8488 
8489         Params:
8490             writer = A `char` accepting
8491             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8492         Returns:
8493             A `string` when not using an output range; `void` otherwise.
8494       +/
8495     string toSimpleString() @safe const nothrow scope
8496     {
8497         import std.array : appender;
8498         auto app = appender!string();
8499         app.reserve(35);
8500         try
8501             toSimpleString(app);
8502         catch (Exception e)
8503             assert(0, "toSimpleString() threw.");
8504         return app.data;
8505     }
8506 
8507     /// ditto
8508     void toSimpleString(W)(ref W writer) const scope
8509     if (isOutputRange!(W, char))
8510     {
8511         immutable adjustedTime = adjTime;
8512         long hnsecs = adjustedTime;
8513 
8514         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8515 
8516         if (hnsecs < 0)
8517         {
8518             hnsecs += convert!("hours", "hnsecs")(24);
8519             --days;
8520         }
8521 
8522         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8523         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8524         immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
8525 
8526         immutable dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
8527                                       cast(int) minute, cast(int) second));
8528 
8529         if (_timezone is LocalTime())
8530         {
8531             dateTime.toSimpleString(writer);
8532             fracSecsToISOString(writer, cast(int) hnsecs);
8533             return;
8534         }
8535 
8536         if (_timezone is UTC())
8537         {
8538             dateTime.toSimpleString(writer);
8539             fracSecsToISOString(writer, cast(int) hnsecs);
8540             put(writer, 'Z');
8541             return;
8542         }
8543 
8544         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
8545 
8546         dateTime.toSimpleString(writer);
8547         fracSecsToISOString(writer, cast(int) hnsecs);
8548         SimpleTimeZone.toISOExtString(writer, utcOffset);
8549     }
8550 
8551     ///
8552     @safe unittest
8553     {
8554         import core.time : msecs, hnsecs;
8555         import std.datetime.date : DateTime;
8556 
8557         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toSimpleString() ==
8558                "2010-Jul-04 07:06:12");
8559 
8560         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toSimpleString() ==
8561                "1998-Dec-25 02:15:00.024");
8562 
8563         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toSimpleString() ==
8564                "0000-Jan-05 23:09:59");
8565 
8566         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toSimpleString() ==
8567                 "-0004-Jan-05 00:00:02.052092");
8568     }
8569 
8570     @safe unittest
8571     {
8572         import core.time;
8573         // Test A.D.
8574         assert(SysTime(DateTime.init, UTC()).toString() == "0001-Jan-01 00:00:00Z");
8575         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toString() == "0001-Jan-01 00:00:00.0000001Z");
8576 
8577         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00");
8578         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12");
8579         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59");
8580         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59");
8581         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01");
8582 
8583         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "0009-Dec-04 00:00:00.042");
8584         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "0099-Dec-04 05:06:12.1");
8585         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
8586                "0999-Dec-04 13:44:59.04502");
8587         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
8588                "9999-Jul-04 23:59:59.0000012");
8589         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() ==
8590                "+10000-Oct-20 01:01:01.050789");
8591 
8592         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8593                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toSimpleString() ==
8594                "2012-Dec-21 12:12:12-06:00");
8595 
8596         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8597                        new immutable SimpleTimeZone(dur!"minutes"(420))).toSimpleString() ==
8598                "2012-Dec-21 12:12:12+07:00");
8599 
8600         // Test B.C.
8601         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toSimpleString() ==
8602                "0000-Dec-31 23:59:59.9999999Z");
8603         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toSimpleString() ==
8604                "0000-Dec-31 23:59:59.0000001Z");
8605         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toSimpleString() == "0000-Dec-31 23:59:59Z");
8606 
8607         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04");
8608         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00");
8609         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12");
8610         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59");
8611         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59");
8612         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01");
8613 
8614         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toSimpleString() == "0000-Dec-04 00:00:00.007");
8615         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "-0009-Dec-04 00:00:00.042");
8616         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "-0099-Dec-04 05:06:12.1");
8617         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
8618                "-0999-Dec-04 13:44:59.04502");
8619         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
8620                "-9999-Jul-04 23:59:59.0000012");
8621         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() ==
8622                "-10000-Oct-20 01:01:01.050789");
8623 
8624         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8625         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8626         assert(cst.toSimpleString() == "1999-Jul-06 12:30:33");
8627         assert(ist.toSimpleString() == "1999-Jul-06 12:30:33");
8628 
8629         static void testScope(scope ref SysTime st) @safe
8630         {
8631             auto result = st.toSimpleString();
8632         }
8633     }
8634 
8635 
8636     /++
8637         Converts this $(LREF SysTime) to a string.
8638 
8639         This function exists to make it easy to convert a $(LREF SysTime) to a
8640         string for code that does not care what the exact format is - just that
8641         it presents the information in a clear manner. It also makes it easy to
8642         simply convert a $(LREF SysTime) to a string when using functions such
8643         as `to!string`, `format`, or `writeln` which use toString to convert
8644         user-defined types. So, it is unlikely that much code will call
8645         toString directly.
8646 
8647         The format of the string is purposefully unspecified, and code that
8648         cares about the format of the string should use `toISOString`,
8649         `toISOExtString`, `toSimpleString`, or some other custom formatting
8650         function that explicitly generates the format that the code needs. The
8651         reason is that the code is then clear about what format it's using,
8652         making it less error-prone to maintain the code and interact with other
8653         software that consumes the generated strings. It's for this same reason
8654         that $(LREF SysTime) has no `fromString` function, whereas it does have
8655         `fromISOString`, `fromISOExtString`, and `fromSimpleString`.
8656 
8657         The format returned by toString may or may not change in the future.
8658 
8659         Params:
8660             writer = A `char` accepting
8661             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8662         Returns:
8663             A `string` when not using an output range; `void` otherwise.
8664       +/
8665     string toString() @safe const nothrow scope
8666     {
8667         return toSimpleString();
8668     }
8669 
8670     /// ditto
8671     void toString(W)(ref W writer) const scope
8672     if (isOutputRange!(W, char))
8673     {
8674         toSimpleString(writer);
8675     }
8676 
8677     @safe unittest
8678     {
8679         import core.time;
8680         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8681         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8682         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8683         static assert(__traits(compiles, st.toString()));
8684         static assert(__traits(compiles, cst.toString()));
8685         static assert(__traits(compiles, ist.toString()));
8686 
8687         static void testScope(scope ref SysTime st) @safe
8688         {
8689             auto result = st.toString();
8690         }
8691     }
8692 
8693 
8694     /++
8695         Creates a $(LREF SysTime) from a string with the format
8696         YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds is the time
8697         zone). Whitespace is stripped from the given string.
8698 
8699         The exact format is exactly as described in `toISOString` except that
8700         trailing zeroes are permitted - including having fractional seconds with
8701         all zeroes. However, a decimal point with nothing following it is
8702         invalid. Also, while $(LREF toISOString) will never generate a string
8703         with more than 7 digits in the fractional seconds (because that's the
8704         limit with hecto-nanosecond precision), it will allow more than 7 digits
8705         in order to read strings from other sources that have higher precision
8706         (however, any digits beyond 7 will be truncated).
8707 
8708         If there is no time zone in the string, then
8709         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
8710         then `UTC` is used. Otherwise, a
8711         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
8712         given offset from UTC is used. To get the returned $(LREF SysTime) to be
8713         a particular time zone, pass in that time zone and the $(LREF SysTime)
8714         to be returned will be converted to that time zone (though it will still
8715         be read in as whatever time zone is in its string).
8716 
8717         The accepted formats for time zone offsets are +HH, -HH, +HHMM, and
8718         -HHMM.
8719 
8720         $(RED Warning:
8721             Previously, $(LREF toISOString) did the same as
8722             $(LREF toISOExtString) and generated +HH:MM or -HH:MM for the time
8723             zone when it was not $(REF LocalTime,std,datetime,timezone) or
8724             $(REF UTC,std,datetime,timezone), which is not in conformance with
8725             ISO 8601 for the non-extended string format. This has now been
8726             fixed. However, for now, fromISOString will continue to accept the
8727             extended format for the time zone so that any code which has been
8728             writing out the result of toISOString to read in later will continue
8729             to work. The current behavior will be kept until July 2019 at which
8730             point, fromISOString will be fixed to be standards compliant.)
8731 
8732         Params:
8733             isoString = A string formatted in the ISO format for dates and times.
8734             tz        = The time zone to convert the given time to (no
8735                         conversion occurs if null).
8736 
8737         Throws:
8738             $(REF DateTimeException,std,datetime,date) if the given string is
8739             not in the ISO format or if the resulting $(LREF SysTime) would not
8740             be valid.
8741       +/
8742     static SysTime fromISOString(S)(scope const S isoString, immutable TimeZone tz = null) @safe
8743         if (isSomeString!S)
8744     {
8745         import std.algorithm.searching : startsWith, find;
8746         import std.conv : to;
8747         import std.string : strip;
8748         import std.utf : byCodeUnit;
8749 
8750         auto str = strip(isoString);
8751         immutable skipFirst = str.startsWith('+', '-');
8752 
8753         auto found = (skipFirst ? str[1..$] : str).byCodeUnit.find('.', 'Z', '+', '-');
8754         auto dateTimeStr = str[0 .. $ - found[0].length];
8755 
8756         typeof(str.byCodeUnit) foundTZ; // needs to have longer lifetime than zoneStr
8757         typeof(str) fracSecStr;
8758         typeof(str) zoneStr;
8759 
8760         if (found[1] != 0)
8761         {
8762             if (found[1] == 1)
8763             {
8764                 foundTZ = found[0].find('Z', '+', '-')[0];
8765 
8766                 if (foundTZ.length != 0)
8767                 {
8768                     static if (isNarrowString!S)
8769                     {
8770                         fracSecStr = found[0][0 .. $ - foundTZ.length].source;
8771                         zoneStr = foundTZ.source;
8772                     }
8773                     else
8774                     {
8775                         fracSecStr = found[0][0 .. $ - foundTZ.length];
8776                         zoneStr = foundTZ;
8777                     }
8778                 }
8779                 else
8780                 {
8781                     static if (isNarrowString!S)
8782                         fracSecStr = found[0].source;
8783                     else
8784                         fracSecStr = found[0];
8785                 }
8786             }
8787             else
8788             {
8789                 static if (isNarrowString!S)
8790                     zoneStr = found[0].source;
8791                 else
8792                     zoneStr = found[0];
8793             }
8794         }
8795 
8796         try
8797         {
8798             auto dateTime = DateTime.fromISOString(dateTimeStr);
8799             auto fracSec = fracSecsFromISOString(fracSecStr);
8800 
8801             Rebindable!(immutable TimeZone) parsedZone;
8802 
8803             if (zoneStr.empty)
8804                 parsedZone = LocalTime();
8805             else if (zoneStr == "Z")
8806                 parsedZone = UTC();
8807             else
8808             {
8809                 try
8810                     parsedZone = SimpleTimeZone.fromISOString(zoneStr);
8811                 catch (DateTimeException dte)
8812                     parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
8813             }
8814 
8815             auto retval = SysTime(dateTime, fracSec, parsedZone);
8816 
8817             if (tz !is null)
8818                 retval.timezone = tz;
8819 
8820             return retval;
8821         }
8822         catch (DateTimeException dte)
8823             throw new DateTimeException(format("Invalid ISO String: %s", isoString));
8824     }
8825 
8826     ///
8827     @safe unittest
8828     {
8829         import core.time : hours, msecs, usecs, hnsecs;
8830         import std.datetime.date : DateTime;
8831         import std.datetime.timezone : SimpleTimeZone, UTC;
8832 
8833         assert(SysTime.fromISOString("20100704T070612") ==
8834                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8835 
8836         assert(SysTime.fromISOString("19981225T021500.007") ==
8837                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
8838 
8839         assert(SysTime.fromISOString("00000105T230959.00002") ==
8840                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
8841 
8842         assert(SysTime.fromISOString("20130207T043937.000050392") ==
8843                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
8844 
8845         assert(SysTime.fromISOString("-00040105T000002") ==
8846                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
8847 
8848         assert(SysTime.fromISOString(" 20100704T070612 ") ==
8849                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8850 
8851         assert(SysTime.fromISOString("20100704T070612Z") ==
8852                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
8853 
8854         assert(SysTime.fromISOString("20100704T070612-0800") ==
8855                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8856                        new immutable SimpleTimeZone(hours(-8))));
8857 
8858         assert(SysTime.fromISOString("20100704T070612+0800") ==
8859                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8860                        new immutable SimpleTimeZone(hours(8))));
8861     }
8862 
8863     @safe unittest
8864     {
8865         import core.time;
8866         foreach (str; ["", "20100704000000", "20100704 000000", "20100704t000000",
8867                        "20100704T000000.", "20100704T000000.A", "20100704T000000.Z",
8868                        "20100704T000000.0000000A", "20100704T000000.00000000A",
8869                        "20100704T000000+", "20100704T000000-", "20100704T000000:",
8870                        "20100704T000000-:", "20100704T000000+:", "20100704T000000-1:",
8871                        "20100704T000000+1:", "20100704T000000+1:0",
8872                        "20100704T000000-12.00", "20100704T000000+12.00",
8873                        "20100704T000000-8", "20100704T000000+8",
8874                        "20100704T000000-800", "20100704T000000+800",
8875                        "20100704T000000-080", "20100704T000000+080",
8876                        "20100704T000000-2400", "20100704T000000+2400",
8877                        "20100704T000000-1260", "20100704T000000+1260",
8878                        "20100704T000000.0-8", "20100704T000000.0+8",
8879                        "20100704T000000.0-800", "20100704T000000.0+800",
8880                        "20100704T000000.0-080", "20100704T000000.0+080",
8881                        "20100704T000000.0-2400", "20100704T000000.0+2400",
8882                        "20100704T000000.0-1260", "20100704T000000.0+1260",
8883                        "20100704T000000-8:00", "20100704T000000+8:00",
8884                        "20100704T000000-08:0", "20100704T000000+08:0",
8885                        "20100704T000000-24:00", "20100704T000000+24:00",
8886                        "20100704T000000-12:60", "20100704T000000+12:60",
8887                        "20100704T000000.0-8:00", "20100704T000000.0+8:00",
8888                        "20100704T000000.0-08:0", "20100704T000000.0+08:0",
8889                        "20100704T000000.0-24:00", "20100704T000000.0+24:00",
8890                        "20100704T000000.0-12:60", "20100704T000000.0+12:60",
8891                        "2010-07-0400:00:00", "2010-07-04 00:00:00",
8892                        "2010-07-04t00:00:00", "2010-07-04T00:00:00.",
8893                        "2010-Jul-0400:00:00", "2010-Jul-04 00:00:00", "2010-Jul-04t00:00:00",
8894                        "2010-Jul-04T00:00:00", "2010-Jul-04 00:00:00.",
8895                        "2010-12-22T172201", "2010-Dec-22 17:22:01"])
8896         {
8897             assertThrown!DateTimeException(SysTime.fromISOString(str), format("[%s]", str));
8898         }
8899 
8900         static void test(string str, SysTime st, size_t line = __LINE__)
8901         {
8902             if (SysTime.fromISOString(str) != st)
8903                 throw new AssertError("unittest failure", __FILE__, line);
8904         }
8905 
8906         test("20101222T172201", SysTime(DateTime(2010, 12, 22, 17, 22, 1)));
8907         test("19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8908         test("-19990706T123033", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
8909         test("+019990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8910         test("19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8911         test(" 19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8912         test(" 19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8913 
8914         test("19070707T121212.0", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
8915         test("19070707T121212.0000000", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
8916         test("19070707T121212.0000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), hnsecs(1)));
8917         test("20100704T000000.00000000", SysTime(Date(2010, 7, 4)));
8918         test("20100704T000000.00000009", SysTime(Date(2010, 7, 4)));
8919         test("20100704T000000.00000019", SysTime(DateTime(2010, 7, 4), hnsecs(1)));
8920         test("19070707T121212.000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
8921         test("19070707T121212.0000010", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
8922         test("19070707T121212.001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
8923         test("19070707T121212.0010000", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
8924 
8925         auto west60 = new immutable SimpleTimeZone(hours(-1));
8926         auto west90 = new immutable SimpleTimeZone(minutes(-90));
8927         auto west480 = new immutable SimpleTimeZone(hours(-8));
8928         auto east60 = new immutable SimpleTimeZone(hours(1));
8929         auto east90 = new immutable SimpleTimeZone(minutes(90));
8930         auto east480 = new immutable SimpleTimeZone(hours(8));
8931 
8932         test("20101222T172201Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), UTC()));
8933         test("20101222T172201-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
8934         test("20101222T172201-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
8935         test("20101222T172201-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
8936         test("20101222T172201-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
8937         test("20101222T172201+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
8938         test("20101222T172201+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
8939         test("20101222T172201+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
8940         test("20101222T172201+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
8941 
8942         test("20101103T065106.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
8943         test("20101222T172201.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_341_200), UTC()));
8944         test("20101222T172201.23112-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
8945         test("20101222T172201.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), west60));
8946         test("20101222T172201.1-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
8947         test("20101222T172201.55-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
8948         test("20101222T172201.1234567+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
8949         test("20101222T172201.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
8950         test("20101222T172201.0000000+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
8951         test("20101222T172201.45+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
8952 
8953         // for dstring coverage
8954         assert(SysTime.fromISOString("20101222T172201.23112-0100"d) == SysTime(
8955             DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
8956         assert(SysTime.fromISOString("19070707T121212.0010000"d) == SysTime(
8957             DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
8958 
8959         // @@@DEPRECATED_2019-07@@@
8960         // This isn't deprecated per se, but that text will make it so that it
8961         // pops up when deprecations are moved along around July 2019. At that
8962         // time, we will update fromISOString so that it is conformant with ISO
8963         // 8601, and it will no longer accept ISO extended time zones (it does
8964         // currently because of https://issues.dlang.org/show_bug.cgi?id=15654
8965         // toISOString used to incorrectly use the ISO extended time zone format).
8966         // These tests will then start failing will need to be updated accordingly.
8967         // Also, the notes about this issue in toISOString and fromISOString's
8968         // documentation will need to be removed.
8969         test("20101222T172201-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
8970         test("20101222T172201-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
8971         test("20101222T172201-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
8972         test("20101222T172201+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
8973         test("20101222T172201+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
8974         test("20101222T172201+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
8975 
8976         test("20101222T172201.23112-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
8977         test("20101222T172201.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
8978         test("20101222T172201.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
8979         test("20101222T172201.1234567+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
8980         test("20101222T172201.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
8981         test("20101222T172201.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
8982 
8983         static void testScope(scope ref string str) @safe
8984         {
8985             auto result = SysTime.fromISOString(str);
8986         }
8987     }
8988 
8989     // https://issues.dlang.org/show_bug.cgi?id=17801
8990     @safe unittest
8991     {
8992         import std.conv : to;
8993         import std.meta : AliasSeq;
8994         static foreach (C; AliasSeq!(char, wchar, dchar))
8995         {
8996             static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
8997             {
8998                 assert(SysTime.fromISOString(to!S("20121221T141516Z")) ==
8999                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
9000             }
9001         }
9002     }
9003 
9004 
9005     /++
9006         Creates a $(LREF SysTime) from a string with the format
9007         YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds is the
9008         time zone). Whitespace is stripped from the given string.
9009 
9010         The exact format is exactly as described in `toISOExtString`
9011         except that trailing zeroes are permitted - including having fractional
9012         seconds with all zeroes. However, a decimal point with nothing following
9013         it is invalid. Also, while $(LREF toISOExtString) will never generate a
9014         string with more than 7 digits in the fractional seconds (because that's
9015         the limit with hecto-nanosecond precision), it will allow more than 7
9016         digits in order to read strings from other sources that have higher
9017         precision (however, any digits beyond 7 will be truncated).
9018 
9019         If there is no time zone in the string, then
9020         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
9021         then `UTC` is used. Otherwise, a
9022         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
9023         given offset from UTC is used. To get the returned $(LREF SysTime) to be
9024         a particular time zone, pass in that time zone and the $(LREF SysTime)
9025         to be returned will be converted to that time zone (though it will still
9026         be read in as whatever time zone is in its string).
9027 
9028         The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and
9029         -HH:MM.
9030 
9031         Params:
9032             isoExtString = A string formatted in the ISO Extended format for
9033                            dates and times.
9034             tz           = The time zone to convert the given time to (no
9035                            conversion occurs if null).
9036 
9037         Throws:
9038             $(REF DateTimeException,std,datetime,date) if the given string is
9039             not in the ISO format or if the resulting $(LREF SysTime) would not
9040             be valid.
9041       +/
9042     static SysTime fromISOExtString(S)(scope const S isoExtString, immutable TimeZone tz = null) @safe
9043         if (isSomeString!(S))
9044     {
9045         import std.algorithm.searching : countUntil, find;
9046         import std.conv : to;
9047         import std.string : strip, indexOf;
9048 
9049         auto str = strip(isoExtString);
9050 
9051         auto tIndex = str.indexOf('T');
9052         enforce(tIndex != -1, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
9053 
9054         auto found = str[tIndex + 1 .. $].find('.', 'Z', '+', '-');
9055         auto dateTimeStr = str[0 .. $ - found[0].length];
9056 
9057         typeof(str) foundTZ;  // needs to have longer lifetime than zoneStr
9058         typeof(str) fracSecStr;
9059         typeof(str) zoneStr;
9060 
9061         if (found[1] != 0)
9062         {
9063             if (found[1] == 1)
9064             {
9065                 foundTZ = found[0].find('Z', '+', '-')[0];
9066 
9067                 if (foundTZ.length != 0)
9068                 {
9069                     fracSecStr = found[0][0 .. $ - foundTZ.length];
9070                     zoneStr = foundTZ;
9071                 }
9072                 else
9073                     fracSecStr = found[0];
9074             }
9075             else
9076                 zoneStr = found[0];
9077         }
9078 
9079         try
9080         {
9081             auto dateTime = DateTime.fromISOExtString(dateTimeStr);
9082             auto fracSec = fracSecsFromISOString(fracSecStr);
9083             Rebindable!(immutable TimeZone) parsedZone;
9084 
9085             if (zoneStr.empty)
9086                 parsedZone = LocalTime();
9087             else if (zoneStr == "Z")
9088                 parsedZone = UTC();
9089             else
9090                 parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
9091 
9092             auto retval = SysTime(dateTime, fracSec, parsedZone);
9093 
9094             if (tz !is null)
9095                 retval.timezone = tz;
9096 
9097             return retval;
9098         }
9099         catch (DateTimeException dte)
9100             throw new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString));
9101     }
9102 
9103     ///
9104     @safe unittest
9105     {
9106         import core.time : hours, msecs, usecs, hnsecs;
9107         import std.datetime.date : DateTime;
9108         import std.datetime.timezone : SimpleTimeZone, UTC;
9109 
9110         assert(SysTime.fromISOExtString("2010-07-04T07:06:12") ==
9111                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9112 
9113         assert(SysTime.fromISOExtString("1998-12-25T02:15:00.007") ==
9114                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
9115 
9116         assert(SysTime.fromISOExtString("0000-01-05T23:09:59.00002") ==
9117                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
9118 
9119         assert(SysTime.fromISOExtString("2013-02-07T04:39:37.000050392") ==
9120                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
9121 
9122         assert(SysTime.fromISOExtString("-0004-01-05T00:00:02") ==
9123                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
9124 
9125         assert(SysTime.fromISOExtString(" 2010-07-04T07:06:12 ") ==
9126                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9127 
9128         assert(SysTime.fromISOExtString("2010-07-04T07:06:12Z") ==
9129                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
9130 
9131         assert(SysTime.fromISOExtString("2010-07-04T07:06:12-08:00") ==
9132                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9133                        new immutable SimpleTimeZone(hours(-8))));
9134         assert(SysTime.fromISOExtString("2010-07-04T07:06:12+08:00") ==
9135                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9136                        new immutable SimpleTimeZone(hours(8))));
9137     }
9138 
9139     @safe unittest
9140     {
9141         import core.time;
9142         foreach (str; ["", "20100704000000", "20100704 000000",
9143                        "20100704t000000", "20100704T000000.", "20100704T000000.0",
9144                        "2010-07:0400:00:00", "2010-07-04 00:00:00",
9145                        "2010-07-04 00:00:00", "2010-07-04t00:00:00",
9146                        "2010-07-04T00:00:00.", "2010-07-04T00:00:00.A", "2010-07-04T00:00:00.Z",
9147                        "2010-07-04T00:00:00.0000000A", "2010-07-04T00:00:00.00000000A",
9148                        "2010-07-04T00:00:00+", "2010-07-04T00:00:00-",
9149                        "2010-07-04T00:00:00:", "2010-07-04T00:00:00-:", "2010-07-04T00:00:00+:",
9150                        "2010-07-04T00:00:00-1:", "2010-07-04T00:00:00+1:", "2010-07-04T00:00:00+1:0",
9151                        "2010-07-04T00:00:00-12.00", "2010-07-04T00:00:00+12.00",
9152                        "2010-07-04T00:00:00-8", "2010-07-04T00:00:00+8",
9153                        "20100704T000000-800", "20100704T000000+800",
9154                        "20100704T000000-080", "20100704T000000+080",
9155                        "20100704T000000-2400", "20100704T000000+2400",
9156                        "20100704T000000-1260", "20100704T000000+1260",
9157                        "20100704T000000.0-800", "20100704T000000.0+800",
9158                        "20100704T000000.0-8", "20100704T000000.0+8",
9159                        "20100704T000000.0-080", "20100704T000000.0+080",
9160                        "20100704T000000.0-2400", "20100704T000000.0+2400",
9161                        "20100704T000000.0-1260", "20100704T000000.0+1260",
9162                        "2010-07-04T00:00:00-8:00", "2010-07-04T00:00:00+8:00",
9163                        "2010-07-04T00:00:00-24:00", "2010-07-04T00:00:00+24:00",
9164                        "2010-07-04T00:00:00-12:60", "2010-07-04T00:00:00+12:60",
9165                        "2010-07-04T00:00:00.0-8:00", "2010-07-04T00:00:00.0+8:00",
9166                        "2010-07-04T00:00:00.0-8", "2010-07-04T00:00:00.0+8",
9167                        "2010-07-04T00:00:00.0-24:00", "2010-07-04T00:00:00.0+24:00",
9168                        "2010-07-04T00:00:00.0-12:60", "2010-07-04T00:00:00.0+12:60",
9169                        "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00",
9170                        "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.0",
9171                        "20101222T172201", "2010-Dec-22 17:22:01"])
9172         {
9173             assertThrown!DateTimeException(SysTime.fromISOExtString(str), format("[%s]", str));
9174         }
9175 
9176         static void test(string str, SysTime st, size_t line = __LINE__)
9177         {
9178             if (SysTime.fromISOExtString(str) != st)
9179                 throw new AssertError("unittest failure", __FILE__, line);
9180         }
9181 
9182         test("2010-12-22T17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 1)));
9183         test("1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9184         test("-1999-07-06T12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
9185         test("+01999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9186         test("1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9187         test(" 1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9188         test(" 1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9189 
9190         test("1907-07-07T12:12:12.0", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9191         test("1907-07-07T12:12:12.0000000", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9192         test("1907-07-07T12:12:12.0000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), hnsecs(1)));
9193         test("2010-07-04T00:00:00.00000000", SysTime(Date(2010, 7, 4)));
9194         test("2010-07-04T00:00:00.00000009", SysTime(Date(2010, 7, 4)));
9195         test("2010-07-04T00:00:00.00000019", SysTime(DateTime(2010, 7, 4), hnsecs(1)));
9196         test("1907-07-07T12:12:12.000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9197         test("1907-07-07T12:12:12.0000010", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9198         test("1907-07-07T12:12:12.001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9199         test("1907-07-07T12:12:12.0010000", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9200 
9201         auto west60 = new immutable SimpleTimeZone(hours(-1));
9202         auto west90 = new immutable SimpleTimeZone(minutes(-90));
9203         auto west480 = new immutable SimpleTimeZone(hours(-8));
9204         auto east60 = new immutable SimpleTimeZone(hours(1));
9205         auto east90 = new immutable SimpleTimeZone(minutes(90));
9206         auto east480 = new immutable SimpleTimeZone(hours(8));
9207 
9208         test("2010-12-22T17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), UTC()));
9209         test("2010-12-22T17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9210         test("2010-12-22T17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9211         test("2010-12-22T17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
9212         test("2010-12-22T17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
9213         test("2010-12-22T17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9214         test("2010-12-22T17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9215         test("2010-12-22T17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9216         test("2010-12-22T17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
9217 
9218         test("2010-11-03T06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
9219         test("2010-12-22T17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_341_200), UTC()));
9220         test("2010-12-22T17:22:01.23112-01:00",
9221              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9222         test("2010-12-22T17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), west60));
9223         test("2010-12-22T17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
9224         test("2010-12-22T17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
9225         test("2010-12-22T17:22:01.1234567+01:00",
9226              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
9227         test("2010-12-22T17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9228         test("2010-12-22T17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9229         test("2010-12-22T17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
9230 
9231         static void testScope(scope ref string str) @safe
9232         {
9233             auto result = SysTime.fromISOExtString(str);
9234         }
9235     }
9236 
9237     // https://issues.dlang.org/show_bug.cgi?id=17801
9238     @safe unittest
9239     {
9240         import core.time;
9241         import std.conv : to;
9242         import std.meta : AliasSeq;
9243         static foreach (C; AliasSeq!(char, wchar, dchar))
9244         {
9245             static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
9246             {
9247                 assert(SysTime.fromISOExtString(to!S("2012-12-21T14:15:16Z")) ==
9248                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
9249             }
9250         }
9251     }
9252 
9253 
9254     /++
9255         Creates a $(LREF SysTime) from a string with the format
9256         YYYY-MM-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds is the
9257         time zone). Whitespace is stripped from the given string.
9258 
9259         The exact format is exactly as described in `toSimpleString` except
9260         that trailing zeroes are permitted - including having fractional seconds
9261         with all zeroes. However, a decimal point with nothing following it is
9262         invalid. Also, while $(LREF toSimpleString) will never generate a
9263         string with more than 7 digits in the fractional seconds (because that's
9264         the limit with hecto-nanosecond precision), it will allow more than 7
9265         digits in order to read strings from other sources that have higher
9266         precision (however, any digits beyond 7 will be truncated).
9267 
9268         If there is no time zone in the string, then
9269         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
9270         then `UTC` is used. Otherwise, a
9271         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
9272         given offset from UTC is used. To get the returned $(LREF SysTime) to be
9273         a particular time zone, pass in that time zone and the $(LREF SysTime)
9274         to be returned will be converted to that time zone (though it will still
9275         be read in as whatever time zone is in its string).
9276 
9277         The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and
9278         -HH:MM.
9279 
9280         Params:
9281             simpleString = A string formatted in the way that
9282                            `toSimpleString` formats dates and times.
9283             tz           = The time zone to convert the given time to (no
9284                            conversion occurs if null).
9285 
9286         Throws:
9287             $(REF DateTimeException,std,datetime,date) if the given string is
9288             not in the ISO format or if the resulting $(LREF SysTime) would not
9289             be valid.
9290       +/
9291     static SysTime fromSimpleString(S)(scope const S simpleString, immutable TimeZone tz = null) @safe
9292         if (isSomeString!(S))
9293     {
9294         import std.algorithm.searching : find;
9295         import std.conv : to;
9296         import std.string : strip, indexOf;
9297 
9298         auto str = strip(simpleString);
9299 
9300         auto spaceIndex = str.indexOf(' ');
9301         enforce(spaceIndex != -1, new DateTimeException(format("Invalid Simple String: %s", simpleString)));
9302 
9303         auto found = str[spaceIndex + 1 .. $].find('.', 'Z', '+', '-');
9304         auto dateTimeStr = str[0 .. $ - found[0].length];
9305 
9306         typeof(str) foundTZ;  // needs to have longer lifetime than zoneStr
9307         typeof(str) fracSecStr;
9308         typeof(str) zoneStr;
9309 
9310         if (found[1] != 0)
9311         {
9312             if (found[1] == 1)
9313             {
9314                 foundTZ = found[0].find('Z', '+', '-')[0];
9315 
9316                 if (foundTZ.length != 0)
9317                 {
9318                     fracSecStr = found[0][0 .. $ - foundTZ.length];
9319                     zoneStr = foundTZ;
9320                 }
9321                 else
9322                     fracSecStr = found[0];
9323             }
9324             else
9325                 zoneStr = found[0];
9326         }
9327 
9328         try
9329         {
9330             auto dateTime = DateTime.fromSimpleString(dateTimeStr);
9331             auto fracSec = fracSecsFromISOString(fracSecStr);
9332             Rebindable!(immutable TimeZone) parsedZone;
9333 
9334             if (zoneStr.empty)
9335                 parsedZone = LocalTime();
9336             else if (zoneStr == "Z")
9337                 parsedZone = UTC();
9338             else
9339                 parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
9340 
9341             auto retval = SysTime(dateTime, fracSec, parsedZone);
9342 
9343             if (tz !is null)
9344                 retval.timezone = tz;
9345 
9346             return retval;
9347         }
9348         catch (DateTimeException dte)
9349             throw new DateTimeException(format("Invalid Simple String: %s", simpleString));
9350     }
9351 
9352     ///
9353     @safe unittest
9354     {
9355         import core.time : hours, msecs, usecs, hnsecs;
9356         import std.datetime.date : DateTime;
9357         import std.datetime.timezone : SimpleTimeZone, UTC;
9358 
9359         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12") ==
9360                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9361 
9362         assert(SysTime.fromSimpleString("1998-Dec-25 02:15:00.007") ==
9363                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
9364 
9365         assert(SysTime.fromSimpleString("0000-Jan-05 23:09:59.00002") ==
9366                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
9367 
9368         assert(SysTime.fromSimpleString("2013-Feb-07 04:39:37.000050392") ==
9369                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
9370 
9371         assert(SysTime.fromSimpleString("-0004-Jan-05 00:00:02") ==
9372                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
9373 
9374         assert(SysTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") ==
9375                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9376 
9377         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12Z") ==
9378                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
9379 
9380         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12-08:00") ==
9381                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9382                        new immutable SimpleTimeZone(hours(-8))));
9383 
9384         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12+08:00") ==
9385                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9386                        new immutable SimpleTimeZone(hours(8))));
9387     }
9388 
9389     @safe unittest
9390     {
9391         import core.time;
9392         foreach (str; ["", "20100704000000", "20100704 000000",
9393                        "20100704t000000", "20100704T000000.", "20100704T000000.0",
9394                        "2010-07-0400:00:00", "2010-07-04 00:00:00", "2010-07-04t00:00:00",
9395                        "2010-07-04T00:00:00.", "2010-07-04T00:00:00.0",
9396                        "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00", "2010-Jul-04T00:00:00",
9397                        "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.A", "2010-Jul-04 00:00:00.Z",
9398                        "2010-Jul-04 00:00:00.0000000A", "2010-Jul-04 00:00:00.00000000A",
9399                        "2010-Jul-04 00:00:00+", "2010-Jul-04 00:00:00-",
9400                        "2010-Jul-04 00:00:00:", "2010-Jul-04 00:00:00-:",
9401                        "2010-Jul-04 00:00:00+:", "2010-Jul-04 00:00:00-1:",
9402                        "2010-Jul-04 00:00:00+1:", "2010-Jul-04 00:00:00+1:0",
9403                        "2010-Jul-04 00:00:00-12.00", "2010-Jul-04 00:00:00+12.00",
9404                        "2010-Jul-04 00:00:00-8", "2010-Jul-04 00:00:00+8",
9405                        "20100704T000000-800", "20100704T000000+800",
9406                        "20100704T000000-080", "20100704T000000+080",
9407                        "20100704T000000-2400", "20100704T000000+2400",
9408                        "20100704T000000-1260", "20100704T000000+1260",
9409                        "20100704T000000.0-800", "20100704T000000.0+800",
9410                        "20100704T000000.0-8", "20100704T000000.0+8",
9411                        "20100704T000000.0-080", "20100704T000000.0+080",
9412                        "20100704T000000.0-2400", "20100704T000000.0+2400",
9413                        "20100704T000000.0-1260", "20100704T000000.0+1260",
9414                        "2010-Jul-04 00:00:00-8:00", "2010-Jul-04 00:00:00+8:00",
9415                        "2010-Jul-04 00:00:00-08:0", "2010-Jul-04 00:00:00+08:0",
9416                        "2010-Jul-04 00:00:00-24:00", "2010-Jul-04 00:00:00+24:00",
9417                        "2010-Jul-04 00:00:00-12:60", "2010-Jul-04 00:00:00+24:60",
9418                        "2010-Jul-04 00:00:00.0-8:00", "2010-Jul-04 00:00:00+8:00",
9419                        "2010-Jul-04 00:00:00.0-8", "2010-Jul-04 00:00:00.0+8",
9420                        "2010-Jul-04 00:00:00.0-08:0", "2010-Jul-04 00:00:00.0+08:0",
9421                        "2010-Jul-04 00:00:00.0-24:00", "2010-Jul-04 00:00:00.0+24:00",
9422                        "2010-Jul-04 00:00:00.0-12:60", "2010-Jul-04 00:00:00.0+24:60",
9423                        "20101222T172201", "2010-12-22T172201"])
9424         {
9425             assertThrown!DateTimeException(SysTime.fromSimpleString(str), format("[%s]", str));
9426         }
9427 
9428         static void test(string str, SysTime st, size_t line = __LINE__)
9429         {
9430             if (SysTime.fromSimpleString(str) != st)
9431                 throw new AssertError("unittest failure", __FILE__, line);
9432         }
9433 
9434         test("2010-Dec-22 17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 1)));
9435         test("1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9436         test("-1999-Jul-06 12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
9437         test("+01999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9438         test("1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9439         test(" 1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9440         test(" 1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9441 
9442         test("1907-Jul-07 12:12:12.0", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9443         test("1907-Jul-07 12:12:12.0000000", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9444         test("2010-Jul-04 00:00:00.00000000", SysTime(Date(2010, 7, 4)));
9445         test("2010-Jul-04 00:00:00.00000009", SysTime(Date(2010, 7, 4)));
9446         test("2010-Jul-04 00:00:00.00000019", SysTime(DateTime(2010, 7, 4), hnsecs(1)));
9447         test("1907-Jul-07 12:12:12.0000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), hnsecs(1)));
9448         test("1907-Jul-07 12:12:12.000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9449         test("1907-Jul-07 12:12:12.0000010", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9450         test("1907-Jul-07 12:12:12.001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9451         test("1907-Jul-07 12:12:12.0010000", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9452 
9453         auto west60 = new immutable SimpleTimeZone(hours(-1));
9454         auto west90 = new immutable SimpleTimeZone(minutes(-90));
9455         auto west480 = new immutable SimpleTimeZone(hours(-8));
9456         auto east60 = new immutable SimpleTimeZone(hours(1));
9457         auto east90 = new immutable SimpleTimeZone(minutes(90));
9458         auto east480 = new immutable SimpleTimeZone(hours(8));
9459 
9460         test("2010-Dec-22 17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), UTC()));
9461         test("2010-Dec-22 17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9462         test("2010-Dec-22 17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9463         test("2010-Dec-22 17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
9464         test("2010-Dec-22 17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
9465         test("2010-Dec-22 17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9466         test("2010-Dec-22 17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9467         test("2010-Dec-22 17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9468         test("2010-Dec-22 17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
9469 
9470         test("2010-Nov-03 06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
9471         test("2010-Dec-22 17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_341_200), UTC()));
9472         test("2010-Dec-22 17:22:01.23112-01:00",
9473              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9474         test("2010-Dec-22 17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), west60));
9475         test("2010-Dec-22 17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
9476         test("2010-Dec-22 17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
9477         test("2010-Dec-22 17:22:01.1234567+01:00",
9478              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
9479         test("2010-Dec-22 17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9480         test("2010-Dec-22 17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9481         test("2010-Dec-22 17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
9482 
9483         static void testScope(scope ref string str) @safe
9484         {
9485             auto result = SysTime.fromSimpleString(str);
9486         }
9487     }
9488 
9489     // https://issues.dlang.org/show_bug.cgi?id=17801
9490     @safe unittest
9491     {
9492         import core.time;
9493         import std.conv : to;
9494         import std.meta : AliasSeq;
9495         static foreach (C; AliasSeq!(char, wchar, dchar))
9496         {
9497             static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
9498             {
9499                 assert(SysTime.fromSimpleString(to!S("2012-Dec-21 14:15:16Z")) ==
9500                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
9501             }
9502         }
9503     }
9504 
9505 
9506     /++
9507         Returns the $(LREF SysTime) farthest in the past which is representable
9508         by $(LREF SysTime).
9509 
9510         The $(LREF SysTime) which is returned is in UTC.
9511       +/
9512     @property static SysTime min() @safe pure nothrow
9513     {
9514         return SysTime(long.min, UTC());
9515     }
9516 
9517     @safe unittest
9518     {
9519         assert(SysTime.min.year < 0);
9520         assert(SysTime.min < SysTime.max);
9521     }
9522 
9523 
9524     /++
9525         Returns the $(LREF SysTime) farthest in the future which is representable
9526         by $(LREF SysTime).
9527 
9528         The $(LREF SysTime) which is returned is in UTC.
9529       +/
9530     @property static SysTime max() @safe pure nothrow
9531     {
9532         return SysTime(long.max, UTC());
9533     }
9534 
9535     @safe unittest
9536     {
9537         assert(SysTime.max.year > 0);
9538         assert(SysTime.max > SysTime.min);
9539     }
9540 
9541 
9542 private:
9543 
9544     /+
9545         Returns `stdTime` converted to $(LREF SysTime)'s time zone.
9546       +/
9547     @property long adjTime() @safe const nothrow scope
9548     {
9549         return _timezone.utcToTZ(_stdTime);
9550     }
9551 
9552 
9553     /+
9554         Converts the given hnsecs from $(LREF SysTime)'s time zone to std time.
9555       +/
9556     @property void adjTime(long adjTime) @safe nothrow scope
9557     {
9558         _stdTime = _timezone.tzToUTC(adjTime);
9559     }
9560 
9561 
9562     final class InitTimeZone : TimeZone
9563     {
9564     public:
9565 
9566         static immutable(InitTimeZone) opCall() @safe pure nothrow @nogc { return _initTimeZone; }
9567 
9568         @property override bool hasDST() @safe const nothrow @nogc { return false; }
9569 
9570         override bool dstInEffect(long stdTime) @safe const nothrow @nogc { return false; }
9571 
9572         override long utcToTZ(long stdTime) @safe const nothrow @nogc { return 0; }
9573 
9574         override long tzToUTC(long adjTime) @safe const nothrow @nogc { return 0; }
9575 
9576         override Duration utcOffsetAt(long stdTime) @safe const nothrow @nogc { return Duration.zero; }
9577 
9578     private:
9579 
9580         this() @safe immutable pure
9581         {
9582             super("SysTime.init's timezone", "SysTime.init's timezone", "SysTime.init's timezone");
9583         }
9584 
9585         static immutable InitTimeZone _initTimeZone = new immutable(InitTimeZone);
9586     }
9587 
9588     // https://issues.dlang.org/show_bug.cgi?id=17732
9589     @safe unittest
9590     {
9591         assert(SysTime.init.timezone is InitTimeZone());
9592         assert(SysTime.init.toISOString() == "00010101T000000+00:00");
9593         assert(SysTime.init.toISOExtString() == "0001-01-01T00:00:00+00:00");
9594         assert(SysTime.init.toSimpleString() == "0001-Jan-01 00:00:00+00:00");
9595         assert(SysTime.init.toString() == "0001-Jan-01 00:00:00+00:00");
9596     }
9597 
9598     // Assigning a value to _timezone in SysTime.init currently doesn't work due
9599     // to https://issues.dlang.org/show_bug.cgi?id=17740. So, to hack around
9600     // that problem, these accessors have been added so that we can insert a
9601     // runtime check for null and then use InitTimeZone for SysTime.init (which
9602     // which is the only case where _timezone would be null). This thus fixes
9603     // the problem with segfaulting when using SysTime.init but at the cost of
9604     // what should be an unnecessary null check. Once 17740 has finally been
9605     // fixed, _timezoneStorage should be removed, these accessors should be
9606     // removed, and the _timezone variable declaration should be restored.
9607     pragma(inline, true) @property _timezone() @safe const pure nothrow @nogc
9608     {
9609         return _timezoneStorage is null ? InitTimeZone() : _timezoneStorage;
9610     }
9611 
9612     pragma(inline, true) @property void _timezone(immutable TimeZone tz) @safe pure nothrow @nogc scope
9613     {
9614         _timezoneStorage = tz;
9615     }
9616 
9617 
9618     long  _stdTime;
9619     Rebindable!(immutable TimeZone) _timezoneStorage;
9620     //Rebindable!(immutable TimeZone) _timezone = InitTimeZone();
9621 }
9622 
9623 ///
9624 @safe unittest
9625 {
9626     import core.time : days, hours, seconds;
9627     import std.datetime.date : DateTime;
9628     import std.datetime.timezone : SimpleTimeZone, UTC;
9629 
9630     // make a specific point in time in the UTC timezone
9631     auto st = SysTime(DateTime(2018, 1, 1, 10, 30, 0), UTC());
9632     // make a specific point in time in the New York timezone
9633     auto ny = SysTime(
9634         DateTime(2018, 1, 1, 10, 30, 0),
9635         new immutable SimpleTimeZone(-5.hours, "America/New_York")
9636     );
9637 
9638     // ISO standard time strings
9639     assert(st.toISOString() == "20180101T103000Z");
9640     assert(st.toISOExtString() == "2018-01-01T10:30:00Z");
9641 
9642     // add two days and 30 seconds
9643     st += 2.days + 30.seconds;
9644     assert(st.toISOExtString() == "2018-01-03T10:30:30Z");
9645 }
9646 
9647 
9648 /++
9649     Converts from unix time (which uses midnight, January 1st, 1970 UTC as its
9650     epoch and seconds as its units) to "std time" (which uses midnight,
9651     January 1st, 1 A.D. UTC and hnsecs as its units).
9652 
9653     The C standard does not specify the representation of time_t, so it is
9654     implementation defined. On POSIX systems, unix time is equivalent to
9655     time_t, but that's not necessarily true on other systems (e.g. it is
9656     not true for the Digital Mars C runtime). So, be careful when using unix
9657     time with C functions on non-POSIX systems.
9658 
9659     "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO
9660     8601 and is what $(LREF SysTime) uses internally. However, holding the time
9661     as an integer in hnsecs since that epoch technically isn't actually part of
9662     the standard, much as it's based on it, so the name "std time" isn't
9663     particularly good, but there isn't an official name for it. C# uses "ticks"
9664     for the same thing, but they aren't actually clock ticks, and the term
9665     "ticks" $(I is) used for actual clock ticks for $(REF MonoTime, core,time),
9666     so it didn't make sense to use the term ticks here. So, for better or worse,
9667     std.datetime uses the term "std time" for this.
9668 
9669     Params:
9670         unixTime = The unix time to convert.
9671 
9672     See_Also:
9673         SysTime.fromUnixTime
9674   +/
unixTimeToStdTime(long unixTime)9675 long unixTimeToStdTime(long unixTime) @safe pure nothrow @nogc
9676 {
9677     return 621_355_968_000_000_000L + convert!("seconds", "hnsecs")(unixTime);
9678 }
9679 
9680 ///
9681 @safe unittest
9682 {
9683     import std.datetime.date : DateTime;
9684     import std.datetime.timezone : UTC;
9685 
9686     // Midnight, January 1st, 1970
9687     assert(unixTimeToStdTime(0) == 621_355_968_000_000_000L);
9688     assert(SysTime(unixTimeToStdTime(0)) ==
9689            SysTime(DateTime(1970, 1, 1), UTC()));
9690 
9691     assert(unixTimeToStdTime(int.max) == 642_830_804_470_000_000L);
9692     assert(SysTime(unixTimeToStdTime(int.max)) ==
9693            SysTime(DateTime(2038, 1, 19, 3, 14, 7), UTC()));
9694 
9695     assert(unixTimeToStdTime(-127_127) == 621_354_696_730_000_000L);
9696     assert(SysTime(unixTimeToStdTime(-127_127)) ==
9697            SysTime(DateTime(1969, 12, 30, 12, 41, 13), UTC()));
9698 }
9699 
9700 @safe unittest
9701 {
9702     // Midnight, January 2nd, 1970
9703     assert(unixTimeToStdTime(86_400) == 621_355_968_000_000_000L + 864_000_000_000L);
9704     // Midnight, December 31st, 1969
9705     assert(unixTimeToStdTime(-86_400) == 621_355_968_000_000_000L - 864_000_000_000L);
9706 
9707     assert(unixTimeToStdTime(0) == (Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs");
9708     assert(unixTimeToStdTime(0) == (DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs");
9709 
9710     foreach (dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)])
9711         assert(unixTimeToStdTime((dt - DateTime(1970, 1, 1)).total!"seconds") == (dt - DateTime.init).total!"hnsecs");
9712 }
9713 
9714 
9715 /++
9716     Converts std time (which uses midnight, January 1st, 1 A.D. UTC as its epoch
9717     and hnsecs as its units) to unix time (which uses midnight, January 1st,
9718     1970 UTC as its epoch and seconds as its units).
9719 
9720     The C standard does not specify the representation of time_t, so it is
9721     implementation defined. On POSIX systems, unix time is equivalent to
9722     time_t, but that's not necessarily true on other systems (e.g. it is
9723     not true for the Digital Mars C runtime). So, be careful when using unix
9724     time with C functions on non-POSIX systems.
9725 
9726     "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO
9727     8601 and is what $(LREF SysTime) uses internally. However, holding the time
9728     as an integer in hnescs since that epoch technically isn't actually part of
9729     the standard, much as it's based on it, so the name "std time" isn't
9730     particularly good, but there isn't an official name for it. C# uses "ticks"
9731     for the same thing, but they aren't actually clock ticks, and the term
9732     "ticks" $(I is) used for actual clock ticks for $(REF MonoTime, core,time),
9733     so it didn't make sense to use the term ticks here. So, for better or worse,
9734     std.datetime uses the term "std time" for this.
9735 
9736     By default, the return type is time_t (which is normally an alias for
9737     int on 32-bit systems and long on 64-bit systems), but if a different
9738     size is required than either int or long can be passed as a template
9739     argument to get the desired size.
9740 
9741     If the return type is int, and the result can't fit in an int, then the
9742     closest value that can be held in 32 bits will be used (so `int.max`
9743     if it goes over and `int.min` if it goes under). However, no attempt
9744     is made to deal with integer overflow if the return type is long.
9745 
9746     Params:
9747         T = The return type (int or long). It defaults to time_t, which is
9748             normally 32 bits on a 32-bit system and 64 bits on a 64-bit
9749             system.
9750         stdTime = The std time to convert.
9751 
9752     Returns:
9753         A signed integer representing the unix time which is equivalent to
9754         the given std time.
9755 
9756     See_Also:
9757         SysTime.toUnixTime
9758   +/
9759 T stdTimeToUnixTime(T = time_t)(long stdTime) @safe pure nothrow
9760 if (is(T == int) || is(T == long))
9761 {
9762     immutable unixTime = convert!("hnsecs", "seconds")(stdTime - 621_355_968_000_000_000L);
9763 
9764     static assert(is(time_t == int) || is(time_t == long),
9765                   "Currently, std.datetime only supports systems where time_t is int or long");
9766 
9767     static if (is(T == long))
9768         return unixTime;
9769     else static if (is(T == int))
9770     {
9771         if (unixTime > int.max)
9772             return int.max;
9773         return unixTime < int.min ? int.min : cast(int) unixTime;
9774     }
9775     else
9776         static assert(0, "Bug in template constraint. Only int and long allowed.");
9777 }
9778 
9779 ///
9780 @safe unittest
9781 {
9782     // Midnight, January 1st, 1970 UTC
9783     assert(stdTimeToUnixTime(621_355_968_000_000_000L) == 0);
9784 
9785     // 2038-01-19 03:14:07 UTC
9786     assert(stdTimeToUnixTime(642_830_804_470_000_000L) == int.max);
9787 }
9788 
9789 @safe unittest
9790 {
9791     enum unixEpochAsStdTime = (Date(1970, 1, 1) - Date.init).total!"hnsecs";
9792 
9793     assert(stdTimeToUnixTime(unixEpochAsStdTime) == 0);  // Midnight, January 1st, 1970
9794     assert(stdTimeToUnixTime(unixEpochAsStdTime + 864_000_000_000L) == 86_400);  // Midnight, January 2nd, 1970
9795     assert(stdTimeToUnixTime(unixEpochAsStdTime - 864_000_000_000L) == -86_400);  // Midnight, December 31st, 1969
9796 
9797     assert(stdTimeToUnixTime((Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs") == 0);
9798     assert(stdTimeToUnixTime((DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs") == 0);
9799 
9800     foreach (dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)])
9801         assert(stdTimeToUnixTime((dt - DateTime.init).total!"hnsecs") == (dt - DateTime(1970, 1, 1)).total!"seconds");
9802 
9803     enum max = convert!("seconds", "hnsecs")(int.max);
9804     enum min = convert!("seconds", "hnsecs")(int.min);
9805     enum one = convert!("seconds", "hnsecs")(1);
9806 
9807     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max) == int.max);
9808     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max) == int.max);
9809 
9810     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + one) == int.max + 1L);
9811     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + one) == int.max);
9812     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + 9_999_999) == int.max);
9813     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + 9_999_999) == int.max);
9814 
9815     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min) == int.min);
9816     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min) == int.min);
9817 
9818     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - one) == int.min - 1L);
9819     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - one) == int.min);
9820     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - 9_999_999) == int.min);
9821     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - 9_999_999) == int.min);
9822 }
9823 
9824 
version(StdDdoc)9825 version (StdDdoc)
9826 {
9827     version (Windows)
9828     {}
9829     else
9830     {
9831         alias SYSTEMTIME = void*;
9832         alias FILETIME = void*;
9833     }
9834 
9835     /++
9836         $(BLUE This function is Windows-Only.)
9837 
9838         Converts a `SYSTEMTIME` struct to a $(LREF SysTime).
9839 
9840         Params:
9841             st = The `SYSTEMTIME` struct to convert.
9842             tz = The time zone that the time in the `SYSTEMTIME` struct is
9843                  assumed to be (if the `SYSTEMTIME` was supplied by a Windows
9844                  system call, the `SYSTEMTIME` will either be in local time
9845                  or UTC, depending on the call).
9846 
9847         Throws:
9848             $(REF DateTimeException,std,datetime,date) if the given
9849             `SYSTEMTIME` will not fit in a $(LREF SysTime), which is highly
9850             unlikely to happen given that `SysTime.max` is in 29,228 A.D. and
9851             the maximum `SYSTEMTIME` is in 30,827 A.D.
9852       +/
9853     SysTime SYSTEMTIMEToSysTime(const scope SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe;
9854 
9855 
9856     /++
9857         $(BLUE This function is Windows-Only.)
9858 
9859         Converts a $(LREF SysTime) to a `SYSTEMTIME` struct.
9860 
9861         The `SYSTEMTIME` which is returned will be set using the given
9862         $(LREF SysTime)'s time zone, so to get the `SYSTEMTIME` in
9863         UTC, set the $(LREF SysTime)'s time zone to UTC.
9864 
9865         Params:
9866             sysTime = The $(LREF SysTime) to convert.
9867 
9868         Throws:
9869             $(REF DateTimeException,std,datetime,date) if the given
9870             $(LREF SysTime) will not fit in a `SYSTEMTIME`. This will only
9871             happen if the $(LREF SysTime)'s date is prior to 1601 A.D.
9872       +/
9873     SYSTEMTIME SysTimeToSYSTEMTIME(scope SysTime sysTime) @safe;
9874 
9875 
9876     /++
9877         $(BLUE This function is Windows-Only.)
9878 
9879         Converts a `FILETIME` struct to the number of hnsecs since midnight,
9880         January 1st, 1 A.D.
9881 
9882         Params:
9883             ft = The `FILETIME` struct to convert.
9884 
9885         Throws:
9886             $(REF DateTimeException,std,datetime,date) if the given
9887             `FILETIME` cannot be represented as the return value.
9888       +/
9889     long FILETIMEToStdTime(scope const FILETIME* ft) @safe;
9890 
9891 
9892     /++
9893         $(BLUE This function is Windows-Only.)
9894 
9895         Converts a `FILETIME` struct to a $(LREF SysTime).
9896 
9897         Params:
9898             ft = The `FILETIME` struct to convert.
9899             tz = The time zone that the $(LREF SysTime) will be in
9900                  (`FILETIME`s are in UTC).
9901 
9902         Throws:
9903             $(REF DateTimeException,std,datetime,date) if the given
9904             `FILETIME` will not fit in a $(LREF SysTime).
9905       +/
9906     SysTime FILETIMEToSysTime(scope const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe;
9907 
9908 
9909     /++
9910         $(BLUE This function is Windows-Only.)
9911 
9912         Converts a number of hnsecs since midnight, January 1st, 1 A.D. to a
9913         `FILETIME` struct.
9914 
9915         Params:
9916             stdTime = The number of hnsecs since midnight, January 1st, 1 A.D.
9917                       UTC.
9918 
9919         Throws:
9920             $(REF DateTimeException,std,datetime,date) if the given value will
9921             not fit in a `FILETIME`.
9922       +/
9923     FILETIME stdTimeToFILETIME(long stdTime) @safe;
9924 
9925 
9926     /++
9927         $(BLUE This function is Windows-Only.)
9928 
9929         Converts a $(LREF SysTime) to a `FILETIME` struct.
9930 
9931         `FILETIME`s are always in UTC.
9932 
9933         Params:
9934             sysTime = The $(LREF SysTime) to convert.
9935 
9936         Throws:
9937             $(REF DateTimeException,std,datetime,date) if the given
9938             $(LREF SysTime) will not fit in a `FILETIME`.
9939       +/
9940     FILETIME SysTimeToFILETIME(scope SysTime sysTime) @safe;
9941 }
version(Windows)9942 else version (Windows)
9943 {
9944     SysTime SYSTEMTIMEToSysTime(const scope SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe
9945     {
9946         const max = SysTime.max;
9947 
9948         static void throwLaterThanMax()
9949         {
9950             throw new DateTimeException("The given SYSTEMTIME is for a date greater than SysTime.max.");
9951         }
9952 
9953         if (st.wYear > max.year)
9954             throwLaterThanMax();
9955         else if (st.wYear == max.year)
9956         {
9957             if (st.wMonth > max.month)
9958                 throwLaterThanMax();
9959             else if (st.wMonth == max.month)
9960             {
9961                 if (st.wDay > max.day)
9962                     throwLaterThanMax();
9963                 else if (st.wDay == max.day)
9964                 {
9965                     if (st.wHour > max.hour)
9966                         throwLaterThanMax();
9967                     else if (st.wHour == max.hour)
9968                     {
9969                         if (st.wMinute > max.minute)
9970                             throwLaterThanMax();
9971                         else if (st.wMinute == max.minute)
9972                         {
9973                             if (st.wSecond > max.second)
9974                                 throwLaterThanMax();
9975                             else if (st.wSecond == max.second)
9976                             {
9977                                 if (st.wMilliseconds > max.fracSecs.total!"msecs")
9978                                     throwLaterThanMax();
9979                             }
9980                         }
9981                     }
9982                 }
9983             }
9984         }
9985 
9986         auto dt = DateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
9987 
9988         import core.time : msecs;
9989         return SysTime(dt, msecs(st.wMilliseconds), tz);
9990     }
9991 
9992     @system unittest
9993     {
9994         auto sysTime = Clock.currTime(UTC());
9995         SYSTEMTIME st = void;
9996         GetSystemTime(&st);
9997         auto converted = SYSTEMTIMEToSysTime(&st, UTC());
9998         import core.time : abs;
9999         assert(abs((converted - sysTime)) <= dur!"seconds"(2));
10000 
10001         static void testScope(scope SYSTEMTIME* st) @safe
10002         {
10003             auto result = SYSTEMTIMEToSysTime(st);
10004         }
10005     }
10006 
10007 
10008     SYSTEMTIME SysTimeToSYSTEMTIME(scope SysTime sysTime) @safe
10009     {
10010         immutable dt = cast(DateTime) sysTime;
10011 
10012         if (dt.year < 1601)
10013             throw new DateTimeException("SYSTEMTIME cannot hold dates prior to the year 1601.");
10014 
10015         SYSTEMTIME st;
10016 
10017         st.wYear = dt.year;
10018         st.wMonth = dt.month;
10019         st.wDayOfWeek = dt.dayOfWeek;
10020         st.wDay = dt.day;
10021         st.wHour = dt.hour;
10022         st.wMinute = dt.minute;
10023         st.wSecond = dt.second;
10024         st.wMilliseconds = cast(ushort) sysTime.fracSecs.total!"msecs";
10025 
10026         return st;
10027     }
10028 
10029     @system unittest
10030     {
10031         SYSTEMTIME st = void;
10032         GetSystemTime(&st);
10033         auto sysTime = SYSTEMTIMEToSysTime(&st, UTC());
10034 
10035         SYSTEMTIME result = SysTimeToSYSTEMTIME(sysTime);
10036 
10037         assert(st.wYear == result.wYear);
10038         assert(st.wMonth == result.wMonth);
10039         assert(st.wDayOfWeek == result.wDayOfWeek);
10040         assert(st.wDay == result.wDay);
10041         assert(st.wHour == result.wHour);
10042         assert(st.wMinute == result.wMinute);
10043         assert(st.wSecond == result.wSecond);
10044         assert(st.wMilliseconds == result.wMilliseconds);
10045 
10046         static void testScope(scope ref SysTime st) @safe
10047         {
10048             auto result = SysTimeToSYSTEMTIME(st);
10049         }
10050     }
10051 
10052     private enum hnsecsFrom1601 = 504_911_232_000_000_000L;
10053 
10054     long FILETIMEToStdTime(scope const FILETIME* ft) @safe
10055     {
10056         ULARGE_INTEGER ul;
10057         ul.HighPart = ft.dwHighDateTime;
10058         ul.LowPart = ft.dwLowDateTime;
10059         ulong tempHNSecs = ul.QuadPart;
10060 
10061         if (tempHNSecs > long.max - hnsecsFrom1601)
10062             throw new DateTimeException("The given FILETIME cannot be represented as a stdTime value.");
10063 
10064         return cast(long) tempHNSecs + hnsecsFrom1601;
10065     }
10066 
10067     SysTime FILETIMEToSysTime(scope const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe
10068     {
10069         auto sysTime = SysTime(FILETIMEToStdTime(ft), UTC());
10070         sysTime.timezone = tz;
10071         return sysTime;
10072     }
10073 
10074     @system unittest
10075     {
10076         auto sysTime = Clock.currTime(UTC());
10077         SYSTEMTIME st = void;
10078         GetSystemTime(&st);
10079 
10080         FILETIME ft = void;
10081         SystemTimeToFileTime(&st, &ft);
10082 
10083         auto converted = FILETIMEToSysTime(&ft);
10084 
10085         import core.time : abs;
10086         assert(abs((converted - sysTime)) <= dur!"seconds"(2));
10087 
10088         static void testScope(scope FILETIME* ft) @safe
10089         {
10090             auto result = FILETIMEToSysTime(ft);
10091         }
10092     }
10093 
10094 
10095     FILETIME stdTimeToFILETIME(long stdTime) @safe
10096     {
10097         if (stdTime < hnsecsFrom1601)
10098             throw new DateTimeException("The given stdTime value cannot be represented as a FILETIME.");
10099 
10100         ULARGE_INTEGER ul;
10101         ul.QuadPart = cast(ulong) stdTime - hnsecsFrom1601;
10102 
10103         FILETIME ft;
10104         ft.dwHighDateTime = ul.HighPart;
10105         ft.dwLowDateTime = ul.LowPart;
10106 
10107         return ft;
10108     }
10109 
10110     FILETIME SysTimeToFILETIME(scope SysTime sysTime) @safe
10111     {
10112         return stdTimeToFILETIME(sysTime.stdTime);
10113     }
10114 
10115     @system unittest
10116     {
10117         SYSTEMTIME st = void;
10118         GetSystemTime(&st);
10119 
10120         FILETIME ft = void;
10121         SystemTimeToFileTime(&st, &ft);
10122         auto sysTime = FILETIMEToSysTime(&ft, UTC());
10123 
10124         FILETIME result = SysTimeToFILETIME(sysTime);
10125 
10126         assert(ft.dwLowDateTime == result.dwLowDateTime);
10127         assert(ft.dwHighDateTime == result.dwHighDateTime);
10128 
10129         static void testScope(scope ref SysTime st) @safe
10130         {
10131             auto result = SysTimeToFILETIME(st);
10132         }
10133     }
10134 }
10135 
10136 
10137 /++
10138     Type representing the DOS file date/time format.
10139   +/
10140 alias DosFileTime = uint;
10141 
10142 /++
10143     Converts from DOS file date/time to $(LREF SysTime).
10144 
10145     Params:
10146         dft = The DOS file time to convert.
10147         tz  = The time zone which the DOS file time is assumed to be in.
10148 
10149     Throws:
10150         $(REF DateTimeException,std,datetime,date) if the `DosFileTime` is
10151         invalid.
10152   +/
10153 SysTime DosFileTimeToSysTime(DosFileTime dft, immutable TimeZone tz = LocalTime()) @safe
10154 {
10155     uint dt = cast(uint) dft;
10156 
10157     if (dt == 0)
10158         throw new DateTimeException("Invalid DosFileTime.");
10159 
10160     int year = ((dt >> 25) & 0x7F) + 1980;
10161     int month = ((dt >> 21) & 0x0F);       // 1 .. 12
10162     int dayOfMonth = ((dt >> 16) & 0x1F);  // 1 .. 31
10163     int hour = (dt >> 11) & 0x1F;          // 0 .. 23
10164     int minute = (dt >> 5) & 0x3F;         // 0 .. 59
10165     int second = (dt << 1) & 0x3E;         // 0 .. 58 (in 2 second increments)
10166 
10167     try
10168         return SysTime(DateTime(year, month, dayOfMonth, hour, minute, second), tz);
10169     catch (DateTimeException dte)
10170         throw new DateTimeException("Invalid DosFileTime", __FILE__, __LINE__, dte);
10171 }
10172 
10173 ///
10174 @safe unittest
10175 {
10176     import std.datetime.date : DateTime;
10177 
10178     assert(DosFileTimeToSysTime(0b00000000001000010000000000000000) == SysTime(DateTime(1980, 1, 1, 0, 0, 0)));
10179     assert(DosFileTimeToSysTime(0b11111111100111111011111101111101) == SysTime(DateTime(2107, 12, 31, 23, 59, 58)));
10180     assert(DosFileTimeToSysTime(0x3E3F8456) == SysTime(DateTime(2011, 1, 31, 16, 34, 44)));
10181 }
10182 
10183 @safe unittest
10184 {
testScope(scope ref DosFileTime dft)10185     static void testScope(scope ref DosFileTime dft) @safe
10186     {
10187         auto result = DosFileTimeToSysTime(dft);
10188     }
10189 }
10190 
10191 
10192 /++
10193     Converts from $(LREF SysTime) to DOS file date/time.
10194 
10195     Params:
10196         sysTime = The $(LREF SysTime) to convert.
10197 
10198     Throws:
10199         $(REF DateTimeException,std,datetime,date) if the given
10200         $(LREF SysTime) cannot be converted to a `DosFileTime`.
10201   +/
SysTimeToDosFileTime(scope SysTime sysTime)10202 DosFileTime SysTimeToDosFileTime(scope SysTime sysTime) @safe
10203 {
10204     auto dateTime = cast(DateTime) sysTime;
10205 
10206     if (dateTime.year < 1980)
10207         throw new DateTimeException("DOS File Times cannot hold dates prior to 1980.");
10208 
10209     if (dateTime.year > 2107)
10210         throw new DateTimeException("DOS File Times cannot hold dates past 2107.");
10211 
10212     uint retval = 0;
10213     retval = (dateTime.year - 1980) << 25;
10214     retval |= (dateTime.month & 0x0F) << 21;
10215     retval |= (dateTime.day & 0x1F) << 16;
10216     retval |= (dateTime.hour & 0x1F) << 11;
10217     retval |= (dateTime.minute & 0x3F) << 5;
10218     retval |= (dateTime.second >> 1) & 0x1F;
10219 
10220     return cast(DosFileTime) retval;
10221 }
10222 
10223 ///
10224 @safe unittest
10225 {
10226     import std.datetime.date : DateTime;
10227 
10228     assert(SysTimeToDosFileTime(SysTime(DateTime(1980, 1, 1, 0, 0, 0))) == 0b00000000001000010000000000000000);
10229     assert(SysTimeToDosFileTime(SysTime(DateTime(2107, 12, 31, 23, 59, 58))) == 0b11111111100111111011111101111101);
10230     assert(SysTimeToDosFileTime(SysTime(DateTime(2011, 1, 31, 16, 34, 44))) == 0x3E3F8456);
10231 }
10232 
10233 @safe unittest
10234 {
testScope(scope ref SysTime st)10235     static void testScope(scope ref SysTime st) @safe
10236     {
10237         auto result = SysTimeToDosFileTime(st);
10238     }
10239 }
10240 
10241 
10242 /++
10243     The given array of `char` or random-access range of `char` or
10244     `ubyte` is expected to be in the format specified in
10245     $(HTTP tools.ietf.org/html/rfc5322, RFC 5322) section 3.3 with the
10246     grammar rule $(I date-time). It is the date-time format commonly used in
10247     internet messages such as e-mail and HTTP. The corresponding
10248     $(LREF SysTime) will be returned.
10249 
10250     RFC 822 was the original spec (hence the function's name), whereas RFC 5322
10251     is the current spec.
10252 
10253     The day of the week is ignored beyond verifying that it's a valid day of the
10254     week, as the day of the week can be inferred from the date. It is not
10255     checked whether the given day of the week matches the actual day of the week
10256     of the given date (though it is technically invalid per the spec if the
10257     day of the week doesn't match the actual day of the week of the given date).
10258 
10259     If the time zone is `"-0000"` (or considered to be equivalent to
10260     `"-0000"` by section 4.3 of the spec), a
10261     $(REF SimpleTimeZone,std,datetime,timezone) with a utc offset of `0` is
10262     used rather than $(REF UTC,std,datetime,timezone), whereas `"+0000"` uses
10263     $(REF UTC,std,datetime,timezone).
10264 
10265     Note that because $(LREF SysTime) does not currently support having a second
10266     value of 60 (as is sometimes done for leap seconds), if the date-time value
10267     does have a value of 60 for the seconds, it is treated as 59.
10268 
10269     The one area in which this function violates RFC 5322 is that it accepts
10270     `"\n"` in folding whitespace in the place of `"\r\n"`, because the
10271     HTTP spec requires it.
10272 
10273     Throws:
10274         $(REF DateTimeException,std,datetime,date) if the given string doesn't
10275         follow the grammar for a date-time field or if the resulting
10276         $(LREF SysTime) is invalid.
10277   +/
parseRFC822DateTime()10278 SysTime parseRFC822DateTime()(scope const char[] value) @safe
10279 {
10280     import std.string : representation;
10281     return parseRFC822DateTime(value.representation);
10282 }
10283 
10284 /++ Ditto +/
10285 SysTime parseRFC822DateTime(R)(scope R value)
10286 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
10287     (is(immutable ElementType!R == immutable char) || is(immutable ElementType!R == immutable ubyte)))
10288 {
10289     import std.algorithm.searching : find, all;
10290     import std.ascii : isDigit, isAlpha, isPrintable;
10291     import std.conv : to;
10292     import std.functional : not;
10293     import std.string : capitalize, format;
10294     import std.traits : EnumMembers, isArray;
10295     import std.typecons : Rebindable;
10296 
10297     void stripAndCheckLen(R valueBefore, size_t minLen, size_t line = __LINE__)
10298     {
10299         value = _stripCFWS(valueBefore);
10300         if (value.length < minLen)
10301             throw new DateTimeException("date-time value too short", __FILE__, line);
10302     }
10303     stripAndCheckLen(value, "7Dec1200:00A".length);
10304 
10305     static if (isArray!R && (is(ElementEncodingType!R == char) || is(ElementEncodingType!R == ubyte)))
10306     {
sliceAsString(R str)10307         static string sliceAsString(R str) @trusted
10308         {
10309             return cast(string) str;
10310         }
10311     }
10312     else
10313     {
10314         char[4] temp;
sliceAsString(R str)10315         char[] sliceAsString(R str) @trusted
10316         {
10317             size_t i = 0;
10318             foreach (c; str)
10319                 temp[i++] = cast(char) c;
10320             return temp[0 .. str.length];
10321         }
10322     }
10323 
10324     // day-of-week
10325     if (isAlpha(value[0]))
10326     {
10327         auto dowStr = sliceAsString(value[0 .. 3]);
10328         switch (dowStr)
10329         {
10330             foreach (dow; EnumMembers!DayOfWeek)
10331             {
10332                 enum dowC = capitalize(to!string(dow));
10333                 case dowC:
10334                     goto afterDoW;
10335             }
10336             default: throw new DateTimeException(format("Invalid day-of-week: %s", dowStr));
10337         }
10338 afterDoW: stripAndCheckLen(value[3 .. value.length], ",7Dec1200:00A".length);
10339         if (value[0] != ',')
10340             throw new DateTimeException("day-of-week missing comma");
10341         stripAndCheckLen(value[1 .. value.length], "7Dec1200:00A".length);
10342     }
10343 
10344     // day
10345     immutable digits = isDigit(value[1]) ? 2 : 1;
10346     immutable day = _convDigits!short(value[0 .. digits]);
10347     if (day == -1)
10348         throw new DateTimeException("Invalid day");
10349     stripAndCheckLen(value[digits .. value.length], "Dec1200:00A".length);
10350 
10351     // month
10352     Month month;
10353     {
10354         auto monStr = sliceAsString(value[0 .. 3]);
10355         switch (monStr)
10356         {
10357             foreach (mon; EnumMembers!Month)
10358             {
10359                 enum monC = capitalize(to!string(mon));
10360                 case monC:
10361                 {
10362                     month = mon;
10363                     goto afterMon;
10364                 }
10365             }
10366             default: throw new DateTimeException(format("Invalid month: %s", monStr));
10367         }
10368 afterMon: stripAndCheckLen(value[3 .. value.length], "1200:00A".length);
10369     }
10370 
10371     // year
10372     auto found = value[2 .. value.length].find!(not!(isDigit))();
10373     size_t yearLen = value.length - found.length;
10374     if (found.length == 0)
10375         throw new DateTimeException("Invalid year");
10376     if (found[0] == ':')
10377         yearLen -= 2;
10378     auto year = _convDigits!short(value[0 .. yearLen]);
10379     if (year < 1900)
10380     {
10381         if (year == -1)
10382             throw new DateTimeException("Invalid year");
10383         if (yearLen < 4)
10384         {
10385             if (yearLen == 3)
10386                 year += 1900;
10387             else if (yearLen == 2)
10388                 year += year < 50 ? 2000 : 1900;
10389             else
10390                 throw new DateTimeException("Invalid year. Too few digits.");
10391         }
10392         else
10393             throw new DateTimeException("Invalid year. Cannot be earlier than 1900.");
10394     }
10395     stripAndCheckLen(value[yearLen .. value.length], "00:00A".length);
10396 
10397     // hour
10398     immutable hour = _convDigits!short(value[0 .. 2]);
10399     stripAndCheckLen(value[2 .. value.length], ":00A".length);
10400     if (value[0] != ':')
10401         throw new DateTimeException("Invalid hour");
10402     stripAndCheckLen(value[1 .. value.length], "00A".length);
10403 
10404     // minute
10405     immutable minute = _convDigits!short(value[0 .. 2]);
10406     stripAndCheckLen(value[2 .. value.length], "A".length);
10407 
10408     // second
10409     short second;
10410     if (value[0] == ':')
10411     {
10412         stripAndCheckLen(value[1 .. value.length], "00A".length);
10413         second = _convDigits!short(value[0 .. 2]);
10414         // this is just if/until SysTime is sorted out to fully support leap seconds
10415         if (second == 60)
10416             second = 59;
10417         stripAndCheckLen(value[2 .. value.length], "A".length);
10418     }
10419 
parseTZ(int sign)10420     immutable(TimeZone) parseTZ(int sign)
10421     {
10422         if (value.length < 5)
10423             throw new DateTimeException("Invalid timezone");
10424         immutable zoneHours = _convDigits!short(value[1 .. 3]);
10425         immutable zoneMinutes = _convDigits!short(value[3 .. 5]);
10426         if (zoneHours == -1 || zoneMinutes == -1 || zoneMinutes > 59)
10427             throw new DateTimeException("Invalid timezone");
10428         value = value[5 .. value.length];
10429         immutable utcOffset = (dur!"hours"(zoneHours) + dur!"minutes"(zoneMinutes)) * sign;
10430         if (utcOffset == Duration.zero)
10431         {
10432             return sign == 1 ? cast(immutable(TimeZone))UTC()
10433                              : cast(immutable(TimeZone))new immutable SimpleTimeZone(Duration.zero);
10434         }
10435         return new immutable(SimpleTimeZone)(utcOffset);
10436     }
10437 
10438     // zone
10439     Rebindable!(immutable TimeZone) tz;
10440     if (value[0] == '-')
10441         tz = parseTZ(-1);
10442     else if (value[0] == '+')
10443         tz = parseTZ(1);
10444     else
10445     {
10446         // obs-zone
10447         immutable tzLen = value.length - find(value, ' ', '\t', '(')[0].length;
10448         switch (sliceAsString(value[0 .. tzLen <= 4 ? tzLen : 4]))
10449         {
10450             case "UT": case "GMT": tz = UTC(); break;
10451             case "EST": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
10452             case "EDT": tz = new immutable SimpleTimeZone(dur!"hours"(-4)); break;
10453             case "CST": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
10454             case "CDT": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
10455             case "MST": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
10456             case "MDT": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
10457             case "PST": tz = new immutable SimpleTimeZone(dur!"hours"(-8)); break;
10458             case "PDT": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
10459             case "J": case "j": throw new DateTimeException("Invalid timezone");
10460             default:
10461             {
10462                 if (all!(isAlpha)(value[0 .. tzLen]))
10463                 {
10464                     tz = new immutable SimpleTimeZone(Duration.zero);
10465                     break;
10466                 }
10467                 throw new DateTimeException("Invalid timezone");
10468             }
10469         }
10470         value = value[tzLen .. value.length];
10471     }
10472 
10473     // This is kind of arbitrary. Technically, nothing but CFWS is legal past
10474     // the end of the timezone, but we don't want to be picky about that in a
10475     // function that's just parsing rather than validating. So, the idea here is
10476     // that if the next character is printable (and not part of CFWS), then it
10477     // might be part of the timezone and thus affect what the timezone was
10478     // supposed to be, so we'll throw, but otherwise, we'll just ignore it.
10479     if (!value.empty && isPrintable(value[0]) && value[0] != ' ' && value[0] != '(')
10480         throw new DateTimeException("Invalid timezone");
10481 
10482     try
10483         return SysTime(DateTime(year, month, day, hour, minute, second), tz);
10484     catch (DateTimeException dte)
10485         throw new DateTimeException("date-time format is correct, but the resulting SysTime is invalid.", dte);
10486 }
10487 
10488 ///
10489 @safe unittest
10490 {
10491     import core.time : hours;
10492     import std.datetime.date : DateTime, DateTimeException;
10493     import std.datetime.timezone : SimpleTimeZone, UTC;
10494     import std.exception : assertThrown;
10495 
10496     auto tz = new immutable SimpleTimeZone(hours(-8));
10497     assert(parseRFC822DateTime("Sat, 6 Jan 1990 12:14:19 -0800") ==
10498            SysTime(DateTime(1990, 1, 6, 12, 14, 19), tz));
10499 
10500     assert(parseRFC822DateTime("9 Jul 2002 13:11 +0000") ==
10501            SysTime(DateTime(2002, 7, 9, 13, 11, 0), UTC()));
10502 
10503     auto badStr = "29 Feb 2001 12:17:16 +0200";
10504     assertThrown!DateTimeException(parseRFC822DateTime(badStr));
10505 }
10506 
version(StdUnittest)10507 version (StdUnittest) private void testParse822(alias cr)(string str, SysTime expected, size_t line = __LINE__)
10508 {
10509     import std.format : format;
10510     auto value = cr(str);
10511     auto result = parseRFC822DateTime(value);
10512     if (result != expected)
10513         throw new AssertError(format("wrong result. expected [%s], actual[%s]", expected, result), __FILE__, line);
10514 }
10515 
version(StdUnittest)10516 version (StdUnittest) private void testBadParse822(alias cr)(string str, size_t line = __LINE__)
10517 {
10518     try
10519         parseRFC822DateTime(cr(str));
10520     catch (DateTimeException)
10521         return;
10522     throw new AssertError("No DateTimeException was thrown", __FILE__, line);
10523 }
10524 
10525 @system unittest
10526 {
10527     import core.time;
10528     import std.algorithm.iteration : filter, map;
10529     import std.algorithm.searching : canFind;
10530     import std.array : array;
10531     import std.ascii : letters;
10532     import std.format : format;
10533     import std.meta : AliasSeq;
10534     import std.range : chain, iota, take;
10535     import std.stdio : writefln, writeln;
10536     import std.string : representation;
10537 
10538     static struct Rand3Letters
10539     {
10540         enum empty = false;
frontRand3Letters10541         @property auto front() { return _mon; }
popFrontRand3Letters10542         void popFront()
10543         {
10544             import std.exception : assumeUnique;
10545             import std.random : rndGen;
10546             _mon = rndGen.map!(a => letters[a % letters.length])().take(3).array().assumeUnique();
10547         }
10548         string _mon;
startRand3Letters10549         static auto start() { Rand3Letters retval; retval.popFront(); return retval; }
10550     }
10551 
10552     static foreach (cr; AliasSeq!(function(string a){return cast(char[]) a;},
10553                            function(string a){return cast(ubyte[]) a;},
10554                            function(string a){return a;},
10555                            function(string a){return map!(b => cast(char) b)(a.representation);}))
10556     {(){ // workaround slow optimizations for large functions
10557          // https://issues.dlang.org/show_bug.cgi?id=2396
10558         scope(failure) writeln(typeof(cr).stringof);
10559         alias test = testParse822!cr;
10560         alias testBad = testBadParse822!cr;
10561 
10562         immutable std1 = DateTime(2012, 12, 21, 13, 14, 15);
10563         immutable std2 = DateTime(2012, 12, 21, 13, 14, 0);
10564         immutable dst1 = DateTime(1976, 7, 4, 5, 4, 22);
10565         immutable dst2 = DateTime(1976, 7, 4, 5, 4, 0);
10566 
10567         test("21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
10568         test("21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
10569         test("Fri, 21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
10570         test("Fri, 21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
10571 
10572         test("04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10573         test("04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10574         test("Sun, 04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10575         test("Sun, 04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10576 
10577         test("4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10578         test("4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10579         test("Sun, 4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10580         test("Sun, 4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10581 
10582         auto badTZ = new immutable SimpleTimeZone(Duration.zero);
10583         test("21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
10584         test("21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
10585         test("Fri, 21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
10586         test("Fri, 21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
10587 
10588         test("04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10589         test("04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10590         test("Sun, 04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10591         test("Sun, 04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10592 
10593         test("4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10594         test("4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10595         test("Sun, 4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10596         test("Sun, 4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10597 
10598         auto pst = new immutable SimpleTimeZone(dur!"hours"(-8));
10599         auto pdt = new immutable SimpleTimeZone(dur!"hours"(-7));
10600         test("21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
10601         test("21 Dec 2012 13:14 -0800", SysTime(std2, pst));
10602         test("Fri, 21 Dec 2012 13:14 -0800", SysTime(std2, pst));
10603         test("Fri, 21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
10604 
10605         test("04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10606         test("04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10607         test("Sun, 04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10608         test("Sun, 04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10609 
10610         test("4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10611         test("4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10612         test("Sun, 4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10613         test("Sun, 4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10614 
10615         auto cet = new immutable SimpleTimeZone(dur!"hours"(1));
10616         auto cest = new immutable SimpleTimeZone(dur!"hours"(2));
10617         test("21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
10618         test("21 Dec 2012 13:14 +0100", SysTime(std2, cet));
10619         test("Fri, 21 Dec 2012 13:14 +0100", SysTime(std2, cet));
10620         test("Fri, 21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
10621 
10622         test("04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10623         test("04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10624         test("Sun, 04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10625         test("Sun, 04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10626 
10627         test("4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10628         test("4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10629         test("Sun, 4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10630         test("Sun, 4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10631 
10632         // dst and std times are switched in the Southern Hemisphere which is why the
10633         // time zone names and DateTime variables don't match.
10634         auto cstStd = new immutable SimpleTimeZone(dur!"hours"(9) + dur!"minutes"(30));
10635         auto cstDST = new immutable SimpleTimeZone(dur!"hours"(10) + dur!"minutes"(30));
10636         test("21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
10637         test("21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
10638         test("Fri, 21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
10639         test("Fri, 21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
10640 
10641         test("04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10642         test("04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10643         test("Sun, 04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10644         test("Sun, 04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10645 
10646         test("4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10647         test("4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10648         test("Sun, 4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10649         test("Sun, 4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10650 
foreach(int i,mon;_monthNames)10651         foreach (int i, mon; _monthNames)
10652         {
10653             test(format("17 %s 2012 00:05:02 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 2), UTC()));
10654             test(format("17 %s 2012 00:05 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 0), UTC()));
10655         }
10656 
10657         import std.uni : toLower, toUpper;
10658         foreach (mon; chain(_monthNames[].map!(a => toLower(a))(),
10659                             _monthNames[].map!(a => toUpper(a))(),
10660                             ["Jam", "Jen", "Fec", "Fdb", "Mas", "Mbr", "Aps", "Aqr", "Mai", "Miy",
10661                              "Jum", "Jbn", "Jup", "Jal", "Aur", "Apg", "Sem", "Sap", "Ocm", "Odt",
10662                              "Nom", "Nav", "Dem", "Dac"],
10663                             Rand3Letters.start().filter!(a => !_monthNames[].canFind(a)).take(20)))
10664         {
10665             scope(failure) writefln("Month: %s", mon);
10666             testBad(format("17 %s 2012 00:05:02 +0000", mon));
10667             testBad(format("17 %s 2012 00:05 +0000", mon));
10668         }
10669 
10670         immutable string[7] daysOfWeekNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
10671 
10672         {
10673             auto start = SysTime(DateTime(2012, 11, 11, 9, 42, 0), UTC());
10674             int day = 11;
10675 
foreach(int i,dow;daysOfWeekNames)10676             foreach (int i, dow; daysOfWeekNames)
10677             {
10678                 auto curr = start + dur!"days"(i);
10679                 test(format("%s, %s Nov 2012 09:42:00 +0000", dow, day), curr);
10680                 test(format("%s, %s Nov 2012 09:42 +0000", dow, day++), curr);
10681 
10682                 // Whether the day of the week matches the date is ignored.
10683                 test(format("%s, 11 Nov 2012 09:42:00 +0000", dow), start);
10684                 test(format("%s, 11 Nov 2012 09:42 +0000", dow), start);
10685             }
10686         }
10687 
10688         foreach (dow; chain(daysOfWeekNames[].map!(a => toLower(a))(),
10689                             daysOfWeekNames[].map!(a => toUpper(a))(),
10690                             ["Sum", "Spn", "Mom", "Man", "Tuf", "Tae", "Wem", "Wdd", "The", "Tur",
10691                              "Fro", "Fai", "San", "Sut"],
10692                             Rand3Letters.start().filter!(a => !daysOfWeekNames[].canFind(a)).take(20)))
10693         {
10694             scope(failure) writefln("Day of Week: %s", dow);
10695             testBad(format("%s, 11 Nov 2012 09:42:00 +0000", dow));
10696             testBad(format("%s, 11 Nov 2012 09:42 +0000", dow));
10697         }
10698 
10699         testBad("31 Dec 1899 23:59:59 +0000");
10700         test("01 Jan 1900 00:00:00 +0000", SysTime(Date(1900, 1, 1), UTC()));
10701         test("01 Jan 1900 00:00:00 -0000", SysTime(Date(1900, 1, 1),
10702                                                    new immutable SimpleTimeZone(Duration.zero)));
10703         test("01 Jan 1900 00:00:00 -0700", SysTime(Date(1900, 1, 1),
10704                                                    new immutable SimpleTimeZone(dur!"hours"(-7))));
10705 
10706         {
10707             auto st1 = SysTime(Date(1900, 1, 1), UTC());
10708             auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
10709             foreach (i; 1900 .. 2102)
10710             {
10711                 test(format("1 Jan %05d 00:00 +0000", i), st1);
10712                 test(format("1 Jan %05d 00:00 -1100", i), st2);
10713                 st1.add!"years"(1);
10714                 st2.add!"years"(1);
10715             }
10716             st1.year = 9998;
10717             st2.year = 9998;
10718             foreach (i; 9998 .. 11_002)
10719             {
10720                 test(format("1 Jan %05d 00:00 +0000", i), st1);
10721                 test(format("1 Jan %05d 00:00 -1100", i), st2);
10722                 st1.add!"years"(1);
10723                 st2.add!"years"(1);
10724             }
10725         }
10726 
10727         testBad("12 Feb 1907 23:17:09 0000");
10728         testBad("12 Feb 1907 23:17:09 +000");
10729         testBad("12 Feb 1907 23:17:09 -000");
10730         testBad("12 Feb 1907 23:17:09 +00000");
10731         testBad("12 Feb 1907 23:17:09 -00000");
10732         testBad("12 Feb 1907 23:17:09 +A");
10733         testBad("12 Feb 1907 23:17:09 +PST");
10734         testBad("12 Feb 1907 23:17:09 -A");
10735         testBad("12 Feb 1907 23:17:09 -PST");
10736 
10737         // test trailing stuff that gets ignored
10738         {
10739             foreach (c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
10740             {
10741                 scope(failure) writefln("c: %d", c);
10742                 test(format("21 Dec 2012 13:14:15 +0000%c", cast(char) c), SysTime(std1, UTC()));
10743                 test(format("21 Dec 2012 13:14:15 +0000%c  ", cast(char) c), SysTime(std1, UTC()));
10744                 test(format("21 Dec 2012 13:14:15 +0000%chello", cast(char) c), SysTime(std1, UTC()));
10745             }
10746         }
10747 
10748         // test trailing stuff that doesn't get ignored
10749         {
10750             foreach (c; chain(iota(33, '('), iota('(' + 1, 127)))
10751             {
10752                 scope(failure) writefln("c: %d", c);
10753                 testBad(format("21 Dec 2012 13:14:15 +0000%c", cast(char) c));
10754                 testBad(format("21 Dec 2012 13:14:15 +0000%c   ", cast(char) c));
10755                 testBad(format("21 Dec 2012 13:14:15 +0000%chello", cast(char) c));
10756             }
10757         }
10758 
10759         testBad("32 Jan 2012 12:13:14 -0800");
10760         testBad("31 Jan 2012 24:13:14 -0800");
10761         testBad("31 Jan 2012 12:60:14 -0800");
10762         testBad("31 Jan 2012 12:13:61 -0800");
10763         testBad("31 Jan 2012 12:13:14 -0860");
10764         test("31 Jan 2012 12:13:14 -0859",
10765              SysTime(DateTime(2012, 1, 31, 12, 13, 14),
10766                      new immutable SimpleTimeZone(dur!"hours"(-8) + dur!"minutes"(-59))));
10767 
10768         // leap-seconds
10769         test("21 Dec 2012 15:59:60 -0800", SysTime(DateTime(2012, 12, 21, 15, 59, 59), pst));
10770 
10771         // FWS
10772         test("Sun,4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10773         test("Sun,4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10774         test("Sun,4 Jul 1976 05:04 +0930 (foo)", SysTime(dst2, cstStd));
10775         test("Sun,4 Jul 1976 05:04:22 +0930 (foo)", SysTime(dst1, cstStd));
10776         test("Sun,4  \r\n  Jul  \r\n  1976  \r\n  05:04  \r\n  +0930  \r\n  (foo)", SysTime(dst2, cstStd));
10777         test("Sun,4  \r\n  Jul  \r\n  1976  \r\n  05:04:22  \r\n  +0930  \r\n  (foo)", SysTime(dst1, cstStd));
10778 
10779         auto str = "01 Jan 2012 12:13:14 -0800 ";
10780         test(str, SysTime(DateTime(2012, 1, 1, 12, 13, 14), new immutable SimpleTimeZone(hours(-8))));
10781         foreach (i; 0 .. str.length)
10782         {
10783             auto currStr = str.dup;
10784             currStr[i] = 'x';
10785             scope(failure) writefln("failed: %s", currStr);
10786             testBad(cast(string) currStr);
10787         }
10788         foreach (i; 2 .. str.length)
10789         {
10790             auto currStr = str[0 .. $ - i];
10791             scope(failure) writefln("failed: %s", currStr);
10792             testBad(cast(string) currStr);
10793             testBad((cast(string) currStr) ~ "                                    ");
10794         }
10795     }();}
10796 
testScope(scope ref string str)10797     static void testScope(scope ref string str) @safe
10798     {
10799         auto result = parseRFC822DateTime(str);
10800     }
10801 }
10802 
10803 // Obsolete Format per section 4.3 of RFC 5322.
10804 @system unittest
10805 {
10806     import std.algorithm.iteration : filter, map;
10807     import std.ascii : letters;
10808     import std.exception : collectExceptionMsg;
10809     import std.format : format;
10810     import std.meta : AliasSeq;
10811     import std.range : chain, iota;
10812     import std.stdio : writefln, writeln;
10813     import std.string : representation;
10814 
10815     auto std1 = SysTime(DateTime(2012, 12, 21, 13, 14, 15), UTC());
10816     auto std2 = SysTime(DateTime(2012, 12, 21, 13, 14, 0), UTC());
10817     auto std3 = SysTime(DateTime(1912, 12, 21, 13, 14, 15), UTC());
10818     auto std4 = SysTime(DateTime(1912, 12, 21, 13, 14, 0), UTC());
10819     auto dst1 = SysTime(DateTime(1976, 7, 4, 5, 4, 22), UTC());
10820     auto dst2 = SysTime(DateTime(1976, 7, 4, 5, 4, 0), UTC());
10821     auto tooLate1 = SysTime(Date(10_000, 1, 1), UTC());
10822     auto tooLate2 = SysTime(DateTime(12_007, 12, 31, 12, 22, 19), UTC());
10823 
10824     static foreach (cr; AliasSeq!(function(string a){return cast(char[]) a;},
10825                            function(string a){return cast(ubyte[]) a;},
10826                            function(string a){return a;},
10827                            function(string a){return map!(b => cast(char) b)(a.representation);}))
10828     {(){ // workaround slow optimizations for large functions
10829          // https://issues.dlang.org/show_bug.cgi?id=2396
10830         scope(failure) writeln(typeof(cr).stringof);
10831         alias test = testParse822!cr;
10832         {
10833             auto list = ["", " ", " \r\n\t", "\t\r\n (hello world( frien(dog)) silly \r\n )  \t\t \r\n ()",
10834                          " \n ", "\t\n\t", " \n\t (foo) \n (bar) \r\n (baz) \n "];
10835 
foreach(i,cfws;list)10836             foreach (i, cfws; list)
10837             {
10838                 scope(failure) writefln("i: %s", i);
10839 
10840                 test(format("%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10841                 test(format("%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
10842                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
10843                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10844 
10845                 test(format("%1$s04%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10846                 test(format("%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10847                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10848                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04:22 +0000%1$s", cfws), dst1);
10849 
10850                 test(format("%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10851                 test(format("%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10852                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10853                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10854 
10855                 test(format("%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10856                 test(format("%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
10857                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
10858                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10859 
10860                 test(format("%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10861                 test(format("%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10862                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10863                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10864 
10865                 test(format("%1$s4%1$sJul%1$s76 05:04:22%1$s+0000%1$s", cfws), dst1);
10866                 test(format("%1$s4%1$sJul%1$s76 05:04%1$s+0000%1$s", cfws), dst2);
10867                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10868                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10869 
10870                 test(format("%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
10871                 test(format("%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
10872                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
10873                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
10874 
10875                 test(format("%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10876                 test(format("%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10877                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10878                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10879 
10880                 test(format("%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10881                 test(format("%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10882                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10883                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10884 
10885                 test(format("%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
10886                 test(format("%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
10887                 test(format("%1$sSat%1$s,%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
10888                 test(format("%1$sSun%1$s,%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
10889             }
10890         }
10891 
10892         // test years of 1, 2, and 3 digits.
10893         {
10894             auto st1 = SysTime(Date(2000, 1, 1), UTC());
10895             auto st2 = SysTime(Date(2000, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
10896             foreach (i; 0 .. 50)
10897             {
10898                 test(format("1 Jan %02d 00:00 GMT", i), st1);
10899                 test(format("1 Jan %02d 00:00 -1200", i), st2);
10900                 st1.add!"years"(1);
10901                 st2.add!"years"(1);
10902             }
10903         }
10904 
10905         {
10906             auto st1 = SysTime(Date(1950, 1, 1), UTC());
10907             auto st2 = SysTime(Date(1950, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
10908             foreach (i; 50 .. 100)
10909             {
10910                 test(format("1 Jan %02d 00:00 GMT", i), st1);
10911                 test(format("1 Jan %02d 00:00 -1200", i), st2);
10912                 st1.add!"years"(1);
10913                 st2.add!"years"(1);
10914             }
10915         }
10916 
10917         {
10918             auto st1 = SysTime(Date(1900, 1, 1), UTC());
10919             auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
10920             foreach (i; 0 .. 1000)
10921             {
10922                 test(format("1 Jan %03d 00:00 GMT", i), st1);
10923                 test(format("1 Jan %03d 00:00 -1100", i), st2);
10924                 st1.add!"years"(1);
10925                 st2.add!"years"(1);
10926             }
10927         }
10928 
10929         foreach (i; 0 .. 10)
10930         {
10931             auto str1 = cr(format("1 Jan %d 00:00 GMT", i));
10932             auto str2 = cr(format("1 Jan %d 00:00 -1200", i));
10933             assertThrown!DateTimeException(parseRFC822DateTime(str1));
10934             assertThrown!DateTimeException(parseRFC822DateTime(str1));
10935         }
10936 
10937         // test time zones
10938         {
10939             auto dt = DateTime(1982, 5, 3, 12, 22, 4);
10940             test("Wed, 03 May 1982 12:22:04 UT", SysTime(dt, UTC()));
10941             test("Wed, 03 May 1982 12:22:04 GMT", SysTime(dt, UTC()));
10942             test("Wed, 03 May 1982 12:22:04 EST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
10943             test("Wed, 03 May 1982 12:22:04 EDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-4))));
10944             test("Wed, 03 May 1982 12:22:04 CST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
10945             test("Wed, 03 May 1982 12:22:04 CDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
10946             test("Wed, 03 May 1982 12:22:04 MST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
10947             test("Wed, 03 May 1982 12:22:04 MDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
10948             test("Wed, 03 May 1982 12:22:04 PST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-8))));
10949             test("Wed, 03 May 1982 12:22:04 PDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
10950 
10951             auto badTZ = new immutable SimpleTimeZone(Duration.zero);
10952             foreach (dchar c; filter!(a => a != 'j' && a != 'J')(letters))
10953             {
10954                 scope(failure) writefln("c: %s", c);
10955                 test(format("Wed, 03 May 1982 12:22:04 %s", c), SysTime(dt, badTZ));
10956                 test(format("Wed, 03 May 1982 12:22:04%s", c), SysTime(dt, badTZ));
10957             }
10958 
foreach(dchar c;['j','J'])10959             foreach (dchar c; ['j', 'J'])
10960             {
10961                 scope(failure) writefln("c: %s", c);
10962                 assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04 %s", c))));
10963                 assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04%s", c))));
10964             }
10965 
foreach(string s;["AAA","GQW","DDT","PDA","GT","GM"])10966             foreach (string s; ["AAA", "GQW", "DDT", "PDA", "GT", "GM"])
10967             {
10968                 scope(failure) writefln("s: %s", s);
10969                 test(format("Wed, 03 May 1982 12:22:04 %s", s), SysTime(dt, badTZ));
10970             }
10971 
10972             // test trailing stuff that gets ignored
10973             {
10974                 foreach (c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
10975                 {
10976                     scope(failure) writefln("c: %d", c);
10977                     test(format("21Dec1213:14:15+0000%c", cast(char) c), std1);
10978                     test(format("21Dec1213:14:15+0000%c  ", cast(char) c), std1);
10979                     test(format("21Dec1213:14:15+0000%chello", cast(char) c), std1);
10980                 }
10981             }
10982 
10983             // test trailing stuff that doesn't get ignored
10984             {
10985                 foreach (c; chain(iota(33, '('), iota('(' + 1, 127)))
10986                 {
10987                     scope(failure) writefln("c: %d", c);
10988                     assertThrown!DateTimeException(
10989                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c", cast(char) c))));
10990                     assertThrown!DateTimeException(
10991                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c  ", cast(char) c))));
10992                     assertThrown!DateTimeException(
10993                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%chello", cast(char) c))));
10994                 }
10995             }
10996         }
10997 
10998         // test that the checks for minimum length work correctly and avoid
10999         // any RangeErrors.
11000         test("7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11001                                      new immutable SimpleTimeZone(Duration.zero)));
11002         test("Fri,7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11003                                          new immutable SimpleTimeZone(Duration.zero)));
11004         test("7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11005                                         new immutable SimpleTimeZone(Duration.zero)));
11006         test("Fri,7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11007                                             new immutable SimpleTimeZone(Duration.zero)));
11008 
11009         auto tooShortMsg = collectExceptionMsg!DateTimeException(parseRFC822DateTime(""));
foreach(str;["Fri,7Dec1200:00:00","7Dec1200:00:00"])11010         foreach (str; ["Fri,7Dec1200:00:00", "7Dec1200:00:00"])
11011         {
11012             foreach (i; 0 .. str.length)
11013             {
11014                 auto value = str[0 .. $ - i];
11015                 scope(failure) writeln(value);
11016                 assert(collectExceptionMsg!DateTimeException(parseRFC822DateTime(value)) == tooShortMsg);
11017             }
11018         }
11019     }();}
11020 }
11021 
11022 
11023 private:
11024 
11025 /+
11026     Returns the given hnsecs as an ISO string of fractional seconds.
11027   +/
fracSecsToISOString(int hnsecs)11028 string fracSecsToISOString(int hnsecs) @safe pure nothrow
11029 {
11030     import std.array : appender;
11031     auto w = appender!string();
11032     try
11033         fracSecsToISOString(w, hnsecs);
11034     catch (Exception e)
11035         assert(0, "fracSecsToISOString() threw.");
11036     return w.data;
11037 }
11038 
fracSecsToISOString(W)11039 void fracSecsToISOString(W)(ref W writer, int hnsecs)
11040 {
11041     import std.conv : toChars;
11042     import std.range : padLeft;
11043 
11044     assert(hnsecs >= 0);
11045 
11046     if (hnsecs == 0)
11047         return;
11048 
11049     put(writer, '.');
11050     auto chars = hnsecs.toChars.padLeft('0', 7);
11051     while (chars.back == '0')
11052         chars.popBack();
11053     put(writer, chars);
11054 }
11055 
11056 @safe unittest
11057 {
11058     assert(fracSecsToISOString(0) == "");
11059     assert(fracSecsToISOString(1) == ".0000001");
11060     assert(fracSecsToISOString(10) == ".000001");
11061     assert(fracSecsToISOString(100) == ".00001");
11062     assert(fracSecsToISOString(1000) == ".0001");
11063     assert(fracSecsToISOString(10_000) == ".001");
11064     assert(fracSecsToISOString(100_000) == ".01");
11065     assert(fracSecsToISOString(1_000_000) == ".1");
11066     assert(fracSecsToISOString(1_000_001) == ".1000001");
11067     assert(fracSecsToISOString(1_001_001) == ".1001001");
11068     assert(fracSecsToISOString(1_071_601) == ".1071601");
11069     assert(fracSecsToISOString(1_271_641) == ".1271641");
11070     assert(fracSecsToISOString(9_999_999) == ".9999999");
11071     assert(fracSecsToISOString(9_999_990) == ".999999");
11072     assert(fracSecsToISOString(9_999_900) == ".99999");
11073     assert(fracSecsToISOString(9_999_000) == ".9999");
11074     assert(fracSecsToISOString(9_990_000) == ".999");
11075     assert(fracSecsToISOString(9_900_000) == ".99");
11076     assert(fracSecsToISOString(9_000_000) == ".9");
11077     assert(fracSecsToISOString(999) == ".0000999");
11078     assert(fracSecsToISOString(9990) == ".000999");
11079     assert(fracSecsToISOString(99_900) == ".00999");
11080     assert(fracSecsToISOString(999_000) == ".0999");
11081 }
11082 
11083 
11084 /+
11085     Returns a Duration corresponding to to the given ISO string of
11086     fractional seconds.
11087   +/
11088 static Duration fracSecsFromISOString(S)(scope const S isoString) @safe pure
11089 if (isSomeString!S)
11090 {
11091     import std.algorithm.searching : all;
11092     import std.ascii : isDigit;
11093     import std.conv : to;
11094     import std.string : representation;
11095 
11096     if (isoString.empty)
11097         return Duration.zero;
11098 
11099     auto str = isoString.representation;
11100 
11101     enforce(str[0] == '.', new DateTimeException("Invalid ISO String"));
11102     str.popFront();
11103 
11104     enforce(!str.empty && all!isDigit(str), new DateTimeException("Invalid ISO String"));
11105 
11106     dchar[7] fullISOString = void;
foreach(i,ref dchar c;fullISOString)11107     foreach (i, ref dchar c; fullISOString)
11108     {
11109         if (i < str.length)
11110             c = str[i];
11111         else
11112             c = '0';
11113     }
11114 
11115     return hnsecs(to!int(fullISOString[]));
11116 }
11117 
11118 @safe unittest
11119 {
11120     import core.time;
testFSInvalid(string isoString)11121     static void testFSInvalid(string isoString)
11122     {
11123         fracSecsFromISOString(isoString);
11124     }
11125 
11126     assertThrown!DateTimeException(testFSInvalid("."));
11127     assertThrown!DateTimeException(testFSInvalid("0."));
11128     assertThrown!DateTimeException(testFSInvalid("0"));
11129     assertThrown!DateTimeException(testFSInvalid("0000000"));
11130     assertThrown!DateTimeException(testFSInvalid("T"));
11131     assertThrown!DateTimeException(testFSInvalid("T."));
11132     assertThrown!DateTimeException(testFSInvalid(".T"));
11133     assertThrown!DateTimeException(testFSInvalid(".00000Q0"));
11134     assertThrown!DateTimeException(testFSInvalid(".000000Q"));
11135     assertThrown!DateTimeException(testFSInvalid(".0000000Q"));
11136     assertThrown!DateTimeException(testFSInvalid(".0000000000Q"));
11137 
11138     assert(fracSecsFromISOString("") == Duration.zero);
11139     assert(fracSecsFromISOString(".0000001") == hnsecs(1));
11140     assert(fracSecsFromISOString(".000001") == hnsecs(10));
11141     assert(fracSecsFromISOString(".00001") == hnsecs(100));
11142     assert(fracSecsFromISOString(".0001") == hnsecs(1000));
11143     assert(fracSecsFromISOString(".001") == hnsecs(10_000));
11144     assert(fracSecsFromISOString(".01") == hnsecs(100_000));
11145     assert(fracSecsFromISOString(".1") == hnsecs(1_000_000));
11146     assert(fracSecsFromISOString(".1000001") == hnsecs(1_000_001));
11147     assert(fracSecsFromISOString(".1001001") == hnsecs(1_001_001));
11148     assert(fracSecsFromISOString(".1071601") == hnsecs(1_071_601));
11149     assert(fracSecsFromISOString(".1271641") == hnsecs(1_271_641));
11150     assert(fracSecsFromISOString(".9999999") == hnsecs(9_999_999));
11151     assert(fracSecsFromISOString(".9999990") == hnsecs(9_999_990));
11152     assert(fracSecsFromISOString(".999999") == hnsecs(9_999_990));
11153     assert(fracSecsFromISOString(".9999900") == hnsecs(9_999_900));
11154     assert(fracSecsFromISOString(".99999") == hnsecs(9_999_900));
11155     assert(fracSecsFromISOString(".9999000") == hnsecs(9_999_000));
11156     assert(fracSecsFromISOString(".9999") == hnsecs(9_999_000));
11157     assert(fracSecsFromISOString(".9990000") == hnsecs(9_990_000));
11158     assert(fracSecsFromISOString(".999") == hnsecs(9_990_000));
11159     assert(fracSecsFromISOString(".9900000") == hnsecs(9_900_000));
11160     assert(fracSecsFromISOString(".9900") == hnsecs(9_900_000));
11161     assert(fracSecsFromISOString(".99") == hnsecs(9_900_000));
11162     assert(fracSecsFromISOString(".9000000") == hnsecs(9_000_000));
11163     assert(fracSecsFromISOString(".9") == hnsecs(9_000_000));
11164     assert(fracSecsFromISOString(".0000999") == hnsecs(999));
11165     assert(fracSecsFromISOString(".0009990") == hnsecs(9990));
11166     assert(fracSecsFromISOString(".000999") == hnsecs(9990));
11167     assert(fracSecsFromISOString(".0099900") == hnsecs(99_900));
11168     assert(fracSecsFromISOString(".00999") == hnsecs(99_900));
11169     assert(fracSecsFromISOString(".0999000") == hnsecs(999_000));
11170     assert(fracSecsFromISOString(".0999") == hnsecs(999_000));
11171     assert(fracSecsFromISOString(".00000000") == Duration.zero);
11172     assert(fracSecsFromISOString(".00000001") == Duration.zero);
11173     assert(fracSecsFromISOString(".00000009") == Duration.zero);
11174     assert(fracSecsFromISOString(".1234567890") == hnsecs(1_234_567));
11175     assert(fracSecsFromISOString(".12345678901234567890") == hnsecs(1_234_567));
11176 }
11177 
11178 
11179 /+
11180     This function is used to split out the units without getting the remaining
11181     hnsecs.
11182 
11183     Params:
11184         units  = The units to split out.
11185         hnsecs = The current total hnsecs.
11186 
11187     Returns:
11188         The split out value.
11189   +/
11190 long getUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
11191 if (validTimeUnits(units) &&
11192     CmpTimeUnits!(units, "months") < 0)
11193 {
11194     return convert!("hnsecs", units)(hnsecs);
11195 }
11196 
11197 @safe unittest
11198 {
11199     auto hnsecs = 2595000000007L;
11200     immutable days = getUnitsFromHNSecs!"days"(hnsecs);
11201     assert(days == 3);
11202     assert(hnsecs == 2595000000007L);
11203 }
11204 
11205 
11206 /+
11207     This function is used to split out the units without getting the units but
11208     just the remaining hnsecs.
11209 
11210     Params:
11211         units  = The units to split out.
11212         hnsecs = The current total hnsecs.
11213 
11214     Returns:
11215         The remaining hnsecs.
11216   +/
11217 long removeUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
11218 if (validTimeUnits(units) &&
11219     CmpTimeUnits!(units, "months") < 0)
11220 {
11221     immutable value = convert!("hnsecs", units)(hnsecs);
11222     return hnsecs - convert!(units, "hnsecs")(value);
11223 }
11224 
11225 @safe unittest
11226 {
11227     auto hnsecs = 2595000000007L;
11228     auto returned = removeUnitsFromHNSecs!"days"(hnsecs);
11229     assert(returned == 3000000007);
11230     assert(hnsecs == 2595000000007L);
11231 }
11232 
11233 
11234 /+
11235     Strips what RFC 5322, section 3.2.2 refers to as CFWS from the left-hand
11236     side of the given range (it strips comments delimited by $(D '(') and
11237     `'`') as well as folding whitespace).
11238 
11239     It is assumed that the given range contains the value of a header field and
11240     no terminating CRLF for the line (though the CRLF for folding whitespace is
11241     of course expected and stripped) and thus that the only case of CR or LF is
11242     in folding whitespace.
11243 
11244     If a comment does not terminate correctly (e.g. mismatched parens) or if the
11245     the FWS is malformed, then the range will be empty when stripCWFS is done.
11246     However, only minimal validation of the content is done (e.g. quoted pairs
11247     within a comment aren't validated beyond \$LPAREN or \$RPAREN, because
11248     they're inside a comment, and thus their value doesn't matter anyway). It's
11249     only when the content does not conform to the grammar rules for FWS and thus
11250     literally cannot be parsed that content is considered invalid, and an empty
11251     range is returned.
11252 
11253     Note that _stripCFWS is eager, not lazy. It does not create a new range.
11254     Rather, it pops off the CFWS from the range and returns it.
11255   +/
11256 R _stripCFWS(R)(R range)
11257 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
11258     (is(immutable ElementType!R == immutable char) || is(immutable ElementType!R == immutable ubyte)))
11259 {
11260     immutable e = range.length;
11261     outer: for (size_t i = 0; i < e; )
11262     {
11263         switch (range[i])
11264         {
11265             case ' ': case '\t':
11266             {
11267                 ++i;
11268                 break;
11269             }
11270             case '\r':
11271             {
11272                 if (i + 2 < e && range[i + 1] == '\n' && (range[i + 2] == ' ' || range[i + 2] == '\t'))
11273                 {
11274                     i += 3;
11275                     break;
11276                 }
11277                 break outer;
11278             }
11279             case '\n':
11280             {
11281                 if (i + 1 < e && (range[i + 1] == ' ' || range[i + 1] == '\t'))
11282                 {
11283                     i += 2;
11284                     break;
11285                 }
11286                 break outer;
11287             }
11288             case '(':
11289             {
11290                 ++i;
11291                 size_t commentLevel = 1;
11292                 while (i < e)
11293                 {
11294                     if (range[i] == '(')
11295                         ++commentLevel;
11296                     else if (range[i] == ')')
11297                     {
11298                         ++i;
11299                         if (--commentLevel == 0)
11300                             continue outer;
11301                         continue;
11302                     }
11303                     else if (range[i] == '\\')
11304                     {
11305                         if (++i == e)
11306                             break outer;
11307                     }
11308                     ++i;
11309                 }
11310                 break outer;
11311             }
11312             default: return range[i .. e];
11313         }
11314     }
11315     return range[e .. e];
11316 }
11317 
11318 @system unittest
11319 {
11320     import std.algorithm.comparison : equal;
11321     import std.algorithm.iteration : map;
11322     import std.meta : AliasSeq;
11323     import std.stdio : writeln;
11324     import std.string : representation;
11325 
11326     static foreach (cr; AliasSeq!(function(string a){return cast(ubyte[]) a;},
11327                            function(string a){return map!(b => cast(char) b)(a.representation);}))
11328     {
11329         scope(failure) writeln(typeof(cr).stringof);
11330 
11331         assert(_stripCFWS(cr("")).empty);
11332         assert(_stripCFWS(cr("\r")).empty);
11333         assert(_stripCFWS(cr("\r\n")).empty);
11334         assert(_stripCFWS(cr("\r\n ")).empty);
11335         assert(_stripCFWS(cr(" \t\r\n")).empty);
11336         assert(equal(_stripCFWS(cr(" \t\r\n hello")), cr("hello")));
11337         assert(_stripCFWS(cr(" \t\r\nhello")).empty);
11338         assert(_stripCFWS(cr(" \t\r\n\v")).empty);
11339         assert(equal(_stripCFWS(cr("\v \t\r\n\v")), cr("\v \t\r\n\v")));
11340         assert(_stripCFWS(cr("()")).empty);
11341         assert(_stripCFWS(cr("(hello world)")).empty);
11342         assert(_stripCFWS(cr("(hello world)(hello world)")).empty);
11343         assert(_stripCFWS(cr("(hello world\r\n foo\r where's\nwaldo)")).empty);
11344         assert(_stripCFWS(cr(" \t (hello \tworld\r\n foo\r where's\nwaldo)\t\t ")).empty);
11345         assert(_stripCFWS(cr("      ")).empty);
11346         assert(_stripCFWS(cr("\t\t\t")).empty);
11347         assert(_stripCFWS(cr("\t \r\n\r \n")).empty);
11348         assert(_stripCFWS(cr("(hello world) (can't find waldo) (he's lost)")).empty);
11349         assert(_stripCFWS(cr("(hello\\) world) (can't \\(find waldo) (he's \\(\\)lost)")).empty);
11350         assert(_stripCFWS(cr("(((((")).empty);
11351         assert(_stripCFWS(cr("(((()))")).empty);
11352         assert(_stripCFWS(cr("(((())))")).empty);
11353         assert(equal(_stripCFWS(cr("(((()))))")), cr(")")));
11354         assert(equal(_stripCFWS(cr(")))))")), cr(")))))")));
11355         assert(equal(_stripCFWS(cr("()))))")), cr("))))")));
11356         assert(equal(_stripCFWS(cr(" hello hello ")), cr("hello hello ")));
11357         assert(equal(_stripCFWS(cr("\thello (world)")), cr("hello (world)")));
11358         assert(equal(_stripCFWS(cr(" \r\n \\((\\))  foo")), cr("\\((\\))  foo")));
11359         assert(equal(_stripCFWS(cr(" \r\n (\\((\\)))  foo")), cr("foo")));
11360         assert(equal(_stripCFWS(cr(" \r\n (\\(()))  foo")), cr(")  foo")));
11361         assert(_stripCFWS(cr(" \r\n (((\\)))  foo")).empty);
11362 
11363         assert(_stripCFWS(cr("(hello)(hello)")).empty);
11364         assert(_stripCFWS(cr(" \r\n (hello)\r\n (hello)")).empty);
11365         assert(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n ")).empty);
11366         assert(_stripCFWS(cr("\t\t\t\t(hello)\t\t\t\t(hello)\t\t\t\t")).empty);
11367         assert(equal(_stripCFWS(cr(" \r\n (hello)\r\n (hello) \r\n hello")), cr("hello")));
11368         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n hello")), cr("hello")));
11369         assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\r\n\t(hello)\t\r\n hello")), cr("hello")));
11370         assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\t\r\n\t(hello)\t\r\n hello")), cr("hello")));
11371         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n \r\n (hello) \r\n hello")), cr("hello")));
11372         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n \r\n hello")), cr("hello")));
11373         assert(equal(_stripCFWS(cr(" \r\n \r\n (hello)\t\r\n (hello) \r\n hello")), cr("hello")));
11374         assert(equal(_stripCFWS(cr(" \r\n\t\r\n\t(hello)\t\r\n (hello) \r\n hello")), cr("hello")));
11375 
11376         assert(equal(_stripCFWS(cr(" (\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
11377         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) foo")), cr("foo")));
11378         assert(equal(_stripCFWS(cr(" (\t\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
11379         assert(equal(_stripCFWS(cr(" (\r\n\t( \r\n ) \r\n ) foo")), cr("foo")));
11380         assert(equal(_stripCFWS(cr(" ( \r\n (\t\r\n ) \r\n ) foo")), cr("foo")));
11381         assert(equal(_stripCFWS(cr(" ( \r\n (\r\n ) \r\n ) foo")), cr("foo")));
11382         assert(equal(_stripCFWS(cr(" ( \r\n (\r\n\t) \r\n ) foo")), cr("foo")));
11383         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n) \r\n ) foo")), cr("foo")));
11384         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\t\r\n ) foo")), cr("foo")));
11385         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\r\n ) foo")), cr("foo")));
11386         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n) foo")), cr("foo")));
11387         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n\t) foo")), cr("foo")));
11388         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) \r\n foo")), cr("foo")));
11389         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\t\r\n foo")), cr("foo")));
11390         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\r\n foo")), cr("foo")));
11391 
11392         assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11393         assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11394         assert(equal(_stripCFWS(cr(" (\t\r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11395         assert(equal(_stripCFWS(cr(" (\r\n \r\n\t( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11396         assert(equal(_stripCFWS(cr(" (\r\n \r\n( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11397         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n\t) \r\n ) foo")), cr("foo")));
11398         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\t\r\n ) foo")), cr("foo")));
11399         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\r\n ) foo")), cr("foo")));
11400 
11401         assert(equal(_stripCFWS(cr(" ( \r\n bar \r\n ( \r\n bar \r\n ) \r\n ) foo")), cr("foo")));
11402         assert(equal(_stripCFWS(cr(" ( \r\n () \r\n ( \r\n () \r\n ) \r\n ) foo")), cr("foo")));
11403         assert(equal(_stripCFWS(cr(" ( \r\n \\\\ \r\n ( \r\n \\\\ \r\n ) \r\n ) foo")), cr("foo")));
11404 
11405         assert(_stripCFWS(cr("(hello)(hello)")).empty);
11406         assert(_stripCFWS(cr(" \n (hello)\n (hello) \n ")).empty);
11407         assert(_stripCFWS(cr(" \n (hello) \n (hello) \n ")).empty);
11408         assert(equal(_stripCFWS(cr(" \n (hello)\n (hello) \n hello")), cr("hello")));
11409         assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n hello")), cr("hello")));
11410         assert(equal(_stripCFWS(cr("\t\n\t(hello)\n\t(hello)\t\n hello")), cr("hello")));
11411         assert(equal(_stripCFWS(cr("\t\n\t(hello)\t\n\t(hello)\t\n hello")), cr("hello")));
11412         assert(equal(_stripCFWS(cr(" \n (hello) \n \n (hello) \n hello")), cr("hello")));
11413         assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n \n hello")), cr("hello")));
11414         assert(equal(_stripCFWS(cr(" \n \n (hello)\t\n (hello) \n hello")), cr("hello")));
11415         assert(equal(_stripCFWS(cr(" \n\t\n\t(hello)\t\n (hello) \n hello")), cr("hello")));
11416     }
11417 }
11418 
11419 // This is so that we don't have to worry about std.conv.to throwing. It also
11420 // doesn't have to worry about quite as many cases as std.conv.to, since it
11421 // doesn't have to worry about a sign on the value or about whether it fits.
11422 T _convDigits(T, R)(R str)
11423 if (isIntegral!T && isSigned!T) // The constraints on R were already covered by parseRFC822DateTime.
11424 {
11425     import std.ascii : isDigit;
11426 
11427     assert(!str.empty);
11428     T num = 0;
11429     foreach (i; 0 .. str.length)
11430     {
11431         if (i != 0)
11432             num *= 10;
11433         if (!isDigit(str[i]))
11434             return -1;
11435         num += str[i] - '0';
11436     }
11437     return num;
11438 }
11439 
11440 @safe unittest
11441 {
11442     import std.conv : to;
11443     import std.range : chain, iota;
11444     foreach (i; chain(iota(0, 101), [250, 999, 1000, 1001, 2345, 9999]))
11445     {
11446         assert(_convDigits!int(to!string(i)) == i, i.to!string);
11447     }
foreach(str;["-42","+42","1a","1 "," "," 42 "])11448     foreach (str; ["-42", "+42", "1a", "1 ", " ", " 42 "])
11449     {
11450         assert(_convDigits!int(str) == -1, str);
11451     }
11452 }
11453 
11454 
11455 // NOTE: all the non-simple array literals are wrapped in functions, because
11456 // otherwise importing causes re-evaluation of the static initializers using
11457 // CTFE with unittests enabled
version(StdUnittest)11458 version (StdUnittest)
11459 {
11460 private @safe:
11461     // Variables to help in testing.
11462     Duration currLocalDiffFromUTC;
11463     immutable (TimeZone)[] testTZs;
11464 
11465     // All of these helper arrays are sorted in ascending order.
11466     auto testYearsBC = [-1999, -1200, -600, -4, -1, 0];
11467     auto testYearsAD = [1, 4, 1000, 1999, 2000, 2012];
11468 
11469     // I'd use a Tuple, but I get forward reference errors if I try.
11470     struct MonthDay
11471     {
11472         Month month;
11473         short day;
11474 
11475         this(int m, short d)
11476         {
11477             month = cast(Month) m;
11478             day = d;
11479         }
11480     }
11481 
11482     MonthDay[] testMonthDays()
11483     {
11484        static result = [MonthDay(1, 1),
11485                                 MonthDay(1, 2),
11486                                 MonthDay(3, 17),
11487                                 MonthDay(7, 4),
11488                                 MonthDay(10, 27),
11489                                 MonthDay(12, 30),
11490                                 MonthDay(12, 31)];
11491        return result;
11492     }
11493 
11494     auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31];
11495 
11496     TimeOfDay[] testTODs()
11497     {
11498        static result = [TimeOfDay(0, 0, 0),
11499                      TimeOfDay(0, 0, 1),
11500                      TimeOfDay(0, 1, 0),
11501                      TimeOfDay(1, 0, 0),
11502                      TimeOfDay(13, 13, 13),
11503                      TimeOfDay(23, 59, 59)];
11504        return result;
11505     }
11506 
11507     auto testHours = [0, 1, 12, 22, 23];
11508     auto testMinSecs = [0, 1, 30, 58, 59];
11509 
11510     // Throwing exceptions is incredibly expensive, so we want to use a smaller
11511     // set of values for tests using assertThrown.
11512     TimeOfDay[] testTODsThrown()
11513     {
11514        static result = [TimeOfDay(0, 0, 0),
11515                            TimeOfDay(13, 13, 13),
11516                            TimeOfDay(23, 59, 59)];
11517        return result;
11518     }
11519 
11520     Date[] testDatesBC;
11521     Date[] testDatesAD;
11522 
11523     DateTime[] testDateTimesBC;
11524     DateTime[] testDateTimesAD;
11525 
11526     Duration[] testFracSecs;
11527 
11528     SysTime[] testSysTimesBC;
11529     SysTime[] testSysTimesAD;
11530 
11531     // I'd use a Tuple, but I get forward reference errors if I try.
11532     struct GregDay { int day; Date date; }
11533     GregDay[] testGregDaysBC()
11534     {
11535        static result = [GregDay(-1_373_427, Date(-3760, 9, 7)), // Start of the Hebrew Calendar
11536                            GregDay(-735_233, Date(-2012, 1, 1)),
11537                            GregDay(-735_202, Date(-2012, 2, 1)),
11538                            GregDay(-735_175, Date(-2012, 2, 28)),
11539                            GregDay(-735_174, Date(-2012, 2, 29)),
11540                            GregDay(-735_173, Date(-2012, 3, 1)),
11541                            GregDay(-734_502, Date(-2010, 1, 1)),
11542                            GregDay(-734_472, Date(-2010, 1, 31)),
11543                            GregDay(-734_471, Date(-2010, 2, 1)),
11544                            GregDay(-734_444, Date(-2010, 2, 28)),
11545                            GregDay(-734_443, Date(-2010, 3, 1)),
11546                            GregDay(-734_413, Date(-2010, 3, 31)),
11547                            GregDay(-734_412, Date(-2010, 4, 1)),
11548                            GregDay(-734_383, Date(-2010, 4, 30)),
11549                            GregDay(-734_382, Date(-2010, 5, 1)),
11550                            GregDay(-734_352, Date(-2010, 5, 31)),
11551                            GregDay(-734_351, Date(-2010, 6, 1)),
11552                            GregDay(-734_322, Date(-2010, 6, 30)),
11553                            GregDay(-734_321, Date(-2010, 7, 1)),
11554                            GregDay(-734_291, Date(-2010, 7, 31)),
11555                            GregDay(-734_290, Date(-2010, 8, 1)),
11556                            GregDay(-734_260, Date(-2010, 8, 31)),
11557                            GregDay(-734_259, Date(-2010, 9, 1)),
11558                            GregDay(-734_230, Date(-2010, 9, 30)),
11559                            GregDay(-734_229, Date(-2010, 10, 1)),
11560                            GregDay(-734_199, Date(-2010, 10, 31)),
11561                            GregDay(-734_198, Date(-2010, 11, 1)),
11562                            GregDay(-734_169, Date(-2010, 11, 30)),
11563                            GregDay(-734_168, Date(-2010, 12, 1)),
11564                            GregDay(-734_139, Date(-2010, 12, 30)),
11565                            GregDay(-734_138, Date(-2010, 12, 31)),
11566                            GregDay(-731_215, Date(-2001, 1, 1)),
11567                            GregDay(-730_850, Date(-2000, 1, 1)),
11568                            GregDay(-730_849, Date(-2000, 1, 2)),
11569                            GregDay(-730_486, Date(-2000, 12, 30)),
11570                            GregDay(-730_485, Date(-2000, 12, 31)),
11571                            GregDay(-730_484, Date(-1999, 1, 1)),
11572                            GregDay(-694_690, Date(-1901, 1, 1)),
11573                            GregDay(-694_325, Date(-1900, 1, 1)),
11574                            GregDay(-585_118, Date(-1601, 1, 1)),
11575                            GregDay(-584_753, Date(-1600, 1, 1)),
11576                            GregDay(-584_388, Date(-1600, 12, 31)),
11577                            GregDay(-584_387, Date(-1599, 1, 1)),
11578                            GregDay(-365_972, Date(-1001, 1, 1)),
11579                            GregDay(-365_607, Date(-1000, 1, 1)),
11580                            GregDay(-183_351, Date(-501, 1, 1)),
11581                            GregDay(-182_986, Date(-500, 1, 1)),
11582                            GregDay(-182_621, Date(-499, 1, 1)),
11583                            GregDay(-146_827, Date(-401, 1, 1)),
11584                            GregDay(-146_462, Date(-400, 1, 1)),
11585                            GregDay(-146_097, Date(-400, 12, 31)),
11586                            GregDay(-110_302, Date(-301, 1, 1)),
11587                            GregDay(-109_937, Date(-300, 1, 1)),
11588                            GregDay(-73_778, Date(-201, 1, 1)),
11589                            GregDay(-73_413, Date(-200, 1, 1)),
11590                            GregDay(-38_715, Date(-105, 1, 1)),
11591                            GregDay(-37_254, Date(-101, 1, 1)),
11592                            GregDay(-36_889, Date(-100, 1, 1)),
11593                            GregDay(-36_524, Date(-99, 1, 1)),
11594                            GregDay(-36_160, Date(-99, 12, 31)),
11595                            GregDay(-35_794, Date(-97, 1, 1)),
11596                            GregDay(-18_627, Date(-50, 1, 1)),
11597                            GregDay(-18_262, Date(-49, 1, 1)),
11598                            GregDay(-3652, Date(-9, 1, 1)),
11599                            GregDay(-2191, Date(-5, 1, 1)),
11600                            GregDay(-1827, Date(-5, 12, 31)),
11601                            GregDay(-1826, Date(-4, 1, 1)),
11602                            GregDay(-1825, Date(-4, 1, 2)),
11603                            GregDay(-1462, Date(-4, 12, 30)),
11604                            GregDay(-1461, Date(-4, 12, 31)),
11605                            GregDay(-1460, Date(-3, 1, 1)),
11606                            GregDay(-1096, Date(-3, 12, 31)),
11607                            GregDay(-1095, Date(-2, 1, 1)),
11608                            GregDay(-731, Date(-2, 12, 31)),
11609                            GregDay(-730, Date(-1, 1, 1)),
11610                            GregDay(-367, Date(-1, 12, 30)),
11611                            GregDay(-366, Date(-1, 12, 31)),
11612                            GregDay(-365, Date(0, 1, 1)),
11613                            GregDay(-31, Date(0, 11, 30)),
11614                            GregDay(-30, Date(0, 12, 1)),
11615                            GregDay(-1, Date(0, 12, 30)),
11616                            GregDay(0, Date(0, 12, 31))];
11617        return result;
11618     }
11619 
11620     GregDay[] testGregDaysAD()
11621     {
11622        static result = [GregDay(1, Date(1, 1, 1)),
11623                            GregDay(2, Date(1, 1, 2)),
11624                            GregDay(32, Date(1, 2, 1)),
11625                            GregDay(365, Date(1, 12, 31)),
11626                            GregDay(366, Date(2, 1, 1)),
11627                            GregDay(731, Date(3, 1, 1)),
11628                            GregDay(1096, Date(4, 1, 1)),
11629                            GregDay(1097, Date(4, 1, 2)),
11630                            GregDay(1460, Date(4, 12, 30)),
11631                            GregDay(1461, Date(4, 12, 31)),
11632                            GregDay(1462, Date(5, 1, 1)),
11633                            GregDay(17_898, Date(50, 1, 1)),
11634                            GregDay(35_065, Date(97, 1, 1)),
11635                            GregDay(36_160, Date(100, 1, 1)),
11636                            GregDay(36_525, Date(101, 1, 1)),
11637                            GregDay(37_986, Date(105, 1, 1)),
11638                            GregDay(72_684, Date(200, 1, 1)),
11639                            GregDay(73_049, Date(201, 1, 1)),
11640                            GregDay(109_208, Date(300, 1, 1)),
11641                            GregDay(109_573, Date(301, 1, 1)),
11642                            GregDay(145_732, Date(400, 1, 1)),
11643                            GregDay(146_098, Date(401, 1, 1)),
11644                            GregDay(182_257, Date(500, 1, 1)),
11645                            GregDay(182_622, Date(501, 1, 1)),
11646                            GregDay(364_878, Date(1000, 1, 1)),
11647                            GregDay(365_243, Date(1001, 1, 1)),
11648                            GregDay(584_023, Date(1600, 1, 1)),
11649                            GregDay(584_389, Date(1601, 1, 1)),
11650                            GregDay(693_596, Date(1900, 1, 1)),
11651                            GregDay(693_961, Date(1901, 1, 1)),
11652                            GregDay(729_755, Date(1999, 1, 1)),
11653                            GregDay(730_120, Date(2000, 1, 1)),
11654                            GregDay(730_121, Date(2000, 1, 2)),
11655                            GregDay(730_484, Date(2000, 12, 30)),
11656                            GregDay(730_485, Date(2000, 12, 31)),
11657                            GregDay(730_486, Date(2001, 1, 1)),
11658                            GregDay(733_773, Date(2010, 1, 1)),
11659                            GregDay(733_774, Date(2010, 1, 2)),
11660                            GregDay(733_803, Date(2010, 1, 31)),
11661                            GregDay(733_804, Date(2010, 2, 1)),
11662                            GregDay(733_831, Date(2010, 2, 28)),
11663                            GregDay(733_832, Date(2010, 3, 1)),
11664                            GregDay(733_862, Date(2010, 3, 31)),
11665                            GregDay(733_863, Date(2010, 4, 1)),
11666                            GregDay(733_892, Date(2010, 4, 30)),
11667                            GregDay(733_893, Date(2010, 5, 1)),
11668                            GregDay(733_923, Date(2010, 5, 31)),
11669                            GregDay(733_924, Date(2010, 6, 1)),
11670                            GregDay(733_953, Date(2010, 6, 30)),
11671                            GregDay(733_954, Date(2010, 7, 1)),
11672                            GregDay(733_984, Date(2010, 7, 31)),
11673                            GregDay(733_985, Date(2010, 8, 1)),
11674                            GregDay(734_015, Date(2010, 8, 31)),
11675                            GregDay(734_016, Date(2010, 9, 1)),
11676                            GregDay(734_045, Date(2010, 9, 30)),
11677                            GregDay(734_046, Date(2010, 10, 1)),
11678                            GregDay(734_076, Date(2010, 10, 31)),
11679                            GregDay(734_077, Date(2010, 11, 1)),
11680                            GregDay(734_106, Date(2010, 11, 30)),
11681                            GregDay(734_107, Date(2010, 12, 1)),
11682                            GregDay(734_136, Date(2010, 12, 30)),
11683                            GregDay(734_137, Date(2010, 12, 31)),
11684                            GregDay(734_503, Date(2012, 1, 1)),
11685                            GregDay(734_534, Date(2012, 2, 1)),
11686                            GregDay(734_561, Date(2012, 2, 28)),
11687                            GregDay(734_562, Date(2012, 2, 29)),
11688                            GregDay(734_563, Date(2012, 3, 1)),
11689                            GregDay(734_858, Date(2012, 12, 21))];
11690        return result;
11691     }
11692 
11693     // I'd use a Tuple, but I get forward reference errors if I try.
11694     struct DayOfYear { int day; MonthDay md; }
11695     DayOfYear[] testDaysOfYear()
11696     {
11697        static result = [DayOfYear(1, MonthDay(1, 1)),
11698                            DayOfYear(2, MonthDay(1, 2)),
11699                            DayOfYear(3, MonthDay(1, 3)),
11700                            DayOfYear(31, MonthDay(1, 31)),
11701                            DayOfYear(32, MonthDay(2, 1)),
11702                            DayOfYear(59, MonthDay(2, 28)),
11703                            DayOfYear(60, MonthDay(3, 1)),
11704                            DayOfYear(90, MonthDay(3, 31)),
11705                            DayOfYear(91, MonthDay(4, 1)),
11706                            DayOfYear(120, MonthDay(4, 30)),
11707                            DayOfYear(121, MonthDay(5, 1)),
11708                            DayOfYear(151, MonthDay(5, 31)),
11709                            DayOfYear(152, MonthDay(6, 1)),
11710                            DayOfYear(181, MonthDay(6, 30)),
11711                            DayOfYear(182, MonthDay(7, 1)),
11712                            DayOfYear(212, MonthDay(7, 31)),
11713                            DayOfYear(213, MonthDay(8, 1)),
11714                            DayOfYear(243, MonthDay(8, 31)),
11715                            DayOfYear(244, MonthDay(9, 1)),
11716                            DayOfYear(273, MonthDay(9, 30)),
11717                            DayOfYear(274, MonthDay(10, 1)),
11718                            DayOfYear(304, MonthDay(10, 31)),
11719                            DayOfYear(305, MonthDay(11, 1)),
11720                            DayOfYear(334, MonthDay(11, 30)),
11721                            DayOfYear(335, MonthDay(12, 1)),
11722                            DayOfYear(363, MonthDay(12, 29)),
11723                            DayOfYear(364, MonthDay(12, 30)),
11724                            DayOfYear(365, MonthDay(12, 31))];
11725        return result;
11726     }
11727 
11728     DayOfYear[] testDaysOfLeapYear()
11729     {
11730        static result = [DayOfYear(1, MonthDay(1, 1)),
11731                                DayOfYear(2, MonthDay(1, 2)),
11732                                DayOfYear(3, MonthDay(1, 3)),
11733                                DayOfYear(31, MonthDay(1, 31)),
11734                                DayOfYear(32, MonthDay(2, 1)),
11735                                DayOfYear(59, MonthDay(2, 28)),
11736                                DayOfYear(60, MonthDay(2, 29)),
11737                                DayOfYear(61, MonthDay(3, 1)),
11738                                DayOfYear(91, MonthDay(3, 31)),
11739                                DayOfYear(92, MonthDay(4, 1)),
11740                                DayOfYear(121, MonthDay(4, 30)),
11741                                DayOfYear(122, MonthDay(5, 1)),
11742                                DayOfYear(152, MonthDay(5, 31)),
11743                                DayOfYear(153, MonthDay(6, 1)),
11744                                DayOfYear(182, MonthDay(6, 30)),
11745                                DayOfYear(183, MonthDay(7, 1)),
11746                                DayOfYear(213, MonthDay(7, 31)),
11747                                DayOfYear(214, MonthDay(8, 1)),
11748                                DayOfYear(244, MonthDay(8, 31)),
11749                                DayOfYear(245, MonthDay(9, 1)),
11750                                DayOfYear(274, MonthDay(9, 30)),
11751                                DayOfYear(275, MonthDay(10, 1)),
11752                                DayOfYear(305, MonthDay(10, 31)),
11753                                DayOfYear(306, MonthDay(11, 1)),
11754                                DayOfYear(335, MonthDay(11, 30)),
11755                                DayOfYear(336, MonthDay(12, 1)),
11756                                DayOfYear(364, MonthDay(12, 29)),
11757                                DayOfYear(365, MonthDay(12, 30)),
11758                                DayOfYear(366, MonthDay(12, 31))];
11759        return result;
11760     }
11761 
11762     void initializeTests()
11763     {
11764         import std.algorithm.sorting : sort;
11765         import std.typecons : Rebindable;
11766         immutable lt = LocalTime().utcToTZ(0);
11767         currLocalDiffFromUTC = dur!"hnsecs"(lt);
11768 
11769         version (Posix)
11770         {
11771             import std.datetime.timezone : PosixTimeZone;
11772             immutable otherTZ = lt < 0 ? PosixTimeZone.getTimeZone("Australia/Sydney")
11773                                        : PosixTimeZone.getTimeZone("America/Denver");
11774         }
11775         else version (Windows)
11776         {
11777             import std.datetime.timezone : WindowsTimeZone;
11778             immutable otherTZ = lt < 0 ? WindowsTimeZone.getTimeZone("AUS Eastern Standard Time")
11779                                        : WindowsTimeZone.getTimeZone("Mountain Standard Time");
11780         }
11781 
11782         immutable ot = otherTZ.utcToTZ(0);
11783 
11784         auto diffs = [0L, lt, ot];
11785         auto diffAA = [0L : Rebindable!(immutable TimeZone)(UTC())];
11786         diffAA[lt] = Rebindable!(immutable TimeZone)(LocalTime());
11787         diffAA[ot] = Rebindable!(immutable TimeZone)(otherTZ);
11788 
11789         sort(diffs);
11790         testTZs = [diffAA[diffs[0]], diffAA[diffs[1]], diffAA[diffs[2]]];
11791 
11792         testFracSecs = [Duration.zero, hnsecs(1), hnsecs(5007), hnsecs(9_999_999)];
11793 
11794         foreach (year; testYearsBC)
11795         {
11796             foreach (md; testMonthDays)
11797                 testDatesBC ~= Date(year, md.month, md.day);
11798         }
11799 
11800         foreach (year; testYearsAD)
11801         {
11802             foreach (md; testMonthDays)
11803                 testDatesAD ~= Date(year, md.month, md.day);
11804         }
11805 
11806         foreach (dt; testDatesBC)
11807         {
11808             foreach (tod; testTODs)
11809                 testDateTimesBC ~= DateTime(dt, tod);
11810         }
11811 
11812         foreach (dt; testDatesAD)
11813         {
11814             foreach (tod; testTODs)
11815                 testDateTimesAD ~= DateTime(dt, tod);
11816         }
11817 
11818         foreach (dt; testDateTimesBC)
11819         {
11820             foreach (tz; testTZs)
11821             {
11822                 foreach (fs; testFracSecs)
11823                     testSysTimesBC ~= SysTime(dt, fs, tz);
11824             }
11825         }
11826 
11827         foreach (dt; testDateTimesAD)
11828         {
11829             foreach (tz; testTZs)
11830             {
11831                 foreach (fs; testFracSecs)
11832                     testSysTimesAD ~= SysTime(dt, fs, tz);
11833             }
11834         }
11835     }
11836 }
11837