1 // Written in the D programming language
2 
3 /++
4     License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
5     Authors:   Jonathan M Davis
6     Source:    $(PHOBOSSRC std/datetime/_systime.d)
7 +/
8 module std.datetime.systime;
9 
10 import core.time;
11 import std.datetime.date;
12 import std.datetime.timezone;
13 import std.exception : enforce;
14 import std.format : format;
15 import std.range.primitives;
16 import std.traits : isIntegral, isSigned, isSomeString, Unqual;
17 
version(Windows)18 version (Windows)
19 {
20     import core.stdc.time : time_t;
21     import core.sys.windows.windows;
22     import core.sys.windows.winsock2;
23 }
version(Posix)24 else version (Posix)
25 {
26     import core.sys.posix.signal : timespec;
27     import core.sys.posix.sys.types : time_t;
28 }
29 
version(unittest)30 version (unittest)
31 {
32     import core.exception : AssertError;
33     import std.exception : assertThrown;
34 }
35 
36 
37 @safe unittest
38 {
39     initializeTests();
40 }
41 
42 
43 /++
44     Effectively a namespace to make it clear that the methods it contains are
45     getting the time from the system clock. It cannot be instantiated.
46  +/
47 final class Clock
48 {
49 public:
50 
51     /++
52         Returns the current time in the given time zone.
53 
54         Params:
55             clockType = The $(REF ClockType, core,time) indicates which system
56                         clock to use to get the current time. Very few programs
57                         need to use anything other than the default.
58             tz = The time zone for the SysTime that's returned.
59 
60         Throws:
61             $(REF DateTimeException,std,datetime,date) if it fails to get the
62             time.
63       +/
64     static SysTime currTime(ClockType clockType = ClockType.normal)(immutable TimeZone tz = LocalTime()) @safe
65     {
66         return SysTime(currStdTime!clockType, tz);
67     }
68 
69     @safe unittest
70     {
71         import std.format : format;
72         import std.stdio : writefln;
73         assert(currTime().timezone is LocalTime());
74         assert(currTime(UTC()).timezone is UTC());
75 
76         // core.stdc.time.time does not always use unix time on Windows systems.
77         // In particular, dmc does not use unix time. If we can guarantee that
78         // the MS runtime uses unix time, then we may be able run this test
79         // then, but for now, we're just not going to run this test on Windows.
version(Posix)80         version (Posix)
81         {
82             static import core.stdc.time;
83             static import std.math;
84             immutable unixTimeD = currTime().toUnixTime();
85             immutable unixTimeC = core.stdc.time.time(null);
86             assert(std.math.abs(unixTimeC - unixTimeD) <= 2);
87         }
88 
89         auto norm1 = Clock.currTime;
90         auto norm2 = Clock.currTime(UTC());
91         assert(norm1 <= norm2, format("%s %s", norm1, norm2));
92         assert(abs(norm1 - norm2) <= seconds(2));
93 
94         import std.meta : AliasSeq;
95         foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
96         {
97             scope(failure) writefln("ClockType.%s", ct);
98             auto value1 = Clock.currTime!ct;
99             auto value2 = Clock.currTime!ct(UTC());
100             assert(value1 <= value2, format("%s %s", value1, value2));
101             assert(abs(value1 - value2) <= seconds(2));
102         }
103     }
104 
105 
106     /++
107         Returns the number of hnsecs since midnight, January 1st, 1 A.D. for the
108         current time.
109 
110         Params:
111             clockType = The $(REF ClockType, core,time) indicates which system
112                         clock to use to get the current time. Very few programs
113                         need to use anything other than the default.
114 
115         Throws:
116             $(REF DateTimeException,std,datetime,date) if it fails to get the
117             time.
118       +/
119     static @property long currStdTime(ClockType clockType = ClockType.normal)() @trusted
120     {
121         static if (clockType != ClockType.coarse &&
122                    clockType != ClockType.normal &&
123                    clockType != ClockType.precise &&
124                    clockType != ClockType.second)
125         {
126             static assert(0, format("ClockType.%s is not supported by Clock.currTime or Clock.currStdTime", clockType));
127         }
128 
version(Windows)129         version (Windows)
130         {
131             FILETIME fileTime;
132             GetSystemTimeAsFileTime(&fileTime);
133             immutable result = FILETIMEToStdTime(&fileTime);
134             static if (clockType == ClockType.second)
135             {
136                 // Ideally, this would use core.std.time.time, but the C runtime
137                 // has to be using unix time for that to work, and that's not
138                 // guaranteed on Windows. Digital Mars does not use unix time.
139                 // MS may or may not. If it does, then this can be made to use
140                 // core.stdc.time for MS, but for now, we'll leave it like this.
141                 return convert!("seconds", "hnsecs")(convert!("hnsecs", "seconds")(result));
142             }
143             else
144                 return result;
145         }
version(Posix)146         else version (Posix)
147         {
148             static import core.stdc.time;
149             enum hnsecsToUnixEpoch = unixTimeToStdTime(0);
150 
151             version (OSX)
152             {
153                 static if (clockType == ClockType.second)
154                     return unixTimeToStdTime(core.stdc.time.time(null));
155                 else
156                 {
157                     import core.sys.posix.sys.time : gettimeofday, timeval;
158                     timeval tv;
159                     if (gettimeofday(&tv, null) != 0)
160                         throw new TimeException("Call to gettimeofday() failed");
161                     return convert!("seconds", "hnsecs")(tv.tv_sec) +
162                            convert!("usecs", "hnsecs")(tv.tv_usec) +
163                            hnsecsToUnixEpoch;
164                 }
165             }
166             else version (linux)
167             {
168                 static if (clockType == ClockType.second)
169                     return unixTimeToStdTime(core.stdc.time.time(null));
170                 else
171                 {
172                     import core.sys.linux.time : CLOCK_REALTIME_COARSE;
173                     import core.sys.posix.time : clock_gettime, CLOCK_REALTIME;
174                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_COARSE;
175                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
176                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
177                     else static assert(0, "Previous static if is wrong.");
178                     timespec ts;
179                     if (clock_gettime(clockArg, &ts) != 0)
180                         throw new TimeException("Call to clock_gettime() failed");
181                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
182                            ts.tv_nsec / 100 +
183                            hnsecsToUnixEpoch;
184                 }
185             }
186             else version (FreeBSD)
187             {
188                 import core.sys.freebsd.time : clock_gettime, CLOCK_REALTIME,
189                     CLOCK_REALTIME_FAST, CLOCK_REALTIME_PRECISE, CLOCK_SECOND;
190                 static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_FAST;
191                 else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
192                 else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE;
193                 else static if (clockType == ClockType.second)  alias clockArg = CLOCK_SECOND;
194                 else static assert(0, "Previous static if is wrong.");
195                 timespec ts;
196                 if (clock_gettime(clockArg, &ts) != 0)
197                     throw new TimeException("Call to clock_gettime() failed");
198                 return convert!("seconds", "hnsecs")(ts.tv_sec) +
199                        ts.tv_nsec / 100 +
200                        hnsecsToUnixEpoch;
201             }
202             else version (NetBSD)
203             {
204                 static if (clockType == ClockType.second)
205                     return unixTimeToStdTime(core.stdc.time.time(null));
206                 else
207                 {
208                     import core.sys.posix.sys.time : gettimeofday, timeval;
209                     timeval tv;
210                     if (gettimeofday(&tv, null) != 0)
211                         throw new TimeException("Call to gettimeofday() failed");
212                     return convert!("seconds", "hnsecs")(tv.tv_sec) +
213                            convert!("usecs", "hnsecs")(tv.tv_usec) +
214                            hnsecsToUnixEpoch;
215                 }
216             }
217             else version (DragonFlyBSD)
218             {
219                 import core.sys.dragonflybsd.time : clock_gettime, CLOCK_REALTIME,
220                     CLOCK_REALTIME_FAST, CLOCK_REALTIME_PRECISE, CLOCK_SECOND;
221                 static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_FAST;
222                 else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
223                 else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE;
224                 else static if (clockType == ClockType.second)  alias clockArg = CLOCK_SECOND;
225                 else static assert(0, "Previous static if is wrong.");
226                 timespec ts;
227                 if (clock_gettime(clockArg, &ts) != 0)
228                     throw new TimeException("Call to clock_gettime() failed");
229                 return convert!("seconds", "hnsecs")(ts.tv_sec) +
230                        ts.tv_nsec / 100 +
231                        hnsecsToUnixEpoch;
232             }
233             else version (Solaris)
234             {
235                 static if (clockType == ClockType.second)
236                     return unixTimeToStdTime(core.stdc.time.time(null));
237                 else
238                 {
239                     import core.sys.solaris.time : clock_gettime, CLOCK_REALTIME;
240                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME;
241                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
242                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
243                     else static assert(0, "Previous static if is wrong.");
244                     timespec ts;
245                     if (clock_gettime(clockArg, &ts) != 0)
246                         throw new TimeException("Call to clock_gettime() failed");
247                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
248                            ts.tv_nsec / 100 +
249                            hnsecsToUnixEpoch;
250                 }
251             }
252             else static assert(0, "Unsupported OS");
253         }
254         else static assert(0, "Unsupported OS");
255     }
256 
257     @safe unittest
258     {
259         import std.format : format;
260         import std.math : abs;
261         import std.meta : AliasSeq;
262         import std.stdio : writefln;
263         enum limit = convert!("seconds", "hnsecs")(2);
264 
265         auto norm1 = Clock.currStdTime;
266         auto norm2 = Clock.currStdTime;
267         assert(norm1 <= norm2, format("%s %s", norm1, norm2));
268         assert(abs(norm1 - norm2) <= limit);
269 
270         foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
271         {
272             scope(failure) writefln("ClockType.%s", ct);
273             auto value1 = Clock.currStdTime!ct;
274             auto value2 = Clock.currStdTime!ct;
275             assert(value1 <= value2, format("%s %s", value1, value2));
276             assert(abs(value1 - value2) <= limit);
277         }
278     }
279 
280 
281 private:
282 
this()283     @disable this() {}
284 }
285 
286 
287 /++
288     $(D SysTime) is the type used to get the current time from the
289     system or doing anything that involves time zones. Unlike
290     $(REF DateTime,std,datetime,date), the time zone is an integral part of
291     $(D SysTime) (though for local time applications, time zones can be ignored
292     and it will work, since it defaults to using the local time zone). It holds
293     its internal time in std time (hnsecs since midnight, January 1st, 1 A.D.
294     UTC), so it interfaces well with the system time. However, that means that,
295     unlike $(REF DateTime,std,datetime,date), it is not optimized for
296     calendar-based operations, and getting individual units from it such as
297     years or days is going to involve conversions and be less efficient.
298 
299     For calendar-based operations that don't
300     care about time zones, then $(REF DateTime,std,datetime,date) would be
301     the type to use. For system time, use $(D SysTime).
302 
303     $(LREF Clock.currTime) will return the current time as a $(D SysTime).
304     To convert a $(D SysTime) to a $(REF Date,std,datetime,date) or
305     $(REF DateTime,std,datetime,date), simply cast it. To convert a
306     $(REF Date,std,datetime,date) or $(REF DateTime,std,datetime,date) to a
307     $(D SysTime), use $(D SysTime)'s constructor, and pass in the ntended time
308     zone with it (or don't pass in a $(REF TimeZone,std,datetime,timezone), and
309     the local time zone will be used). Be aware, however, that converting from a
310     $(REF DateTime,std,datetime,date) to a $(D SysTime) will not necessarily
311     be 100% accurate due to DST (one hour of the year doesn't exist and another
312     occurs twice). To not risk any conversion errors, keep times as
313     $(D SysTime)s. Aside from DST though, there shouldn't be any conversion
314     problems.
315 
316     For using time zones other than local time or UTC, use
317     $(REF PosixTimeZone,std,datetime,timezone) on Posix systems (or on Windows,
318     if providing the TZ Database files), and use
319     $(REF WindowsTimeZone,std,datetime,timezone) on Windows systems. The time in
320     $(D SysTime) is kept internally in hnsecs from midnight, January 1st, 1 A.D.
321     UTC. Conversion error cannot happen when changing the time zone of a
322     $(D SysTime). $(REF LocalTime,std,datetime,timezone) is the
323     $(REF TimeZone,std,datetime,timezone) class which represents the local time,
324     and $(D UTC) is the $(REF TimeZone,std,datetime,timezone) class which
325     represents UTC. $(D SysTime) uses $(REF LocalTime,std,datetime,timezone) if
326     no $(REF TimeZone,std,datetime,timezone) is provided. For more details on
327     time zones, see the documentation for $(REF TimeZone,std,datetime,timezone),
328     $(REF PosixTimeZone,std,datetime,timezone), and
329     $(REF WindowsTimeZone,std,datetime,timezone).
330 
331     $(D SysTime)'s range is from approximately 29,000 B.C. to approximately
332     29,000 A.D.
333   +/
334 struct SysTime
335 {
336     import core.stdc.time : tm;
337     version (Posix) import core.sys.posix.sys.time : timeval;
338     import std.typecons : Rebindable;
339 
340 public:
341 
342     /++
343         Params:
344             dateTime = The $(REF DateTime,std,datetime,date) to use to set
345                        this $(LREF SysTime)'s internal std time. As
346                        $(REF DateTime,std,datetime,date) has no concept of
347                        time zone, tz is used as its time zone.
348             tz       = The $(REF TimeZone,std,datetime,timezone) to use for this
349                        $(LREF SysTime). If null,
350                        $(REF LocalTime,std,datetime,timezone) will be used. The
351                        given $(REF DateTime,std,datetime,date) is assumed to
352                        be in the given time zone.
353       +/
354     this(in DateTime dateTime, immutable TimeZone tz = null) @safe nothrow
355     {
356         try
357             this(dateTime, Duration.zero, tz);
358         catch (Exception e)
359             assert(0, "SysTime's constructor threw when it shouldn't have.");
360     }
361 
362     @safe unittest
363     {
testSysTime364         static void test(DateTime dt, immutable TimeZone tz, long expected)
365         {
366             auto sysTime = SysTime(dt, tz);
367             assert(sysTime._stdTime == expected);
368             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given DateTime: %s", dt));
369         }
370 
371         test(DateTime.init, UTC(), 0);
372         test(DateTime(1, 1, 1, 12, 30, 33), UTC(), 450_330_000_000L);
373         test(DateTime(0, 12, 31, 12, 30, 33), UTC(), -413_670_000_000L);
374         test(DateTime(1, 1, 1, 0, 0, 0), UTC(), 0);
375         test(DateTime(1, 1, 1, 0, 0, 1), UTC(), 10_000_000L);
376         test(DateTime(0, 12, 31, 23, 59, 59), UTC(), -10_000_000L);
377 
378         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(-60)), 36_000_000_000L);
379         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(Duration.zero), 0);
380         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(60)), -36_000_000_000L);
381     }
382 
383     /++
384         Params:
385             dateTime = The $(REF DateTime,std,datetime,date) to use to set
386                        this $(LREF SysTime)'s internal std time. As
387                        $(REF DateTime,std,datetime,date) has no concept of
388                        time zone, tz is used as its time zone.
389             fracSecs = The fractional seconds portion of the time.
390             tz       = The $(REF TimeZone,std,datetime,timezone) to use for this
391                        $(LREF SysTime). If null,
392                        $(REF LocalTime,std,datetime,timezone) will be used. The
393                        given $(REF DateTime,std,datetime,date) is assumed to
394                        be in the given time zone.
395 
396         Throws:
397             $(REF DateTimeException,std,datetime,date) if $(D fracSecs) is negative or if it's
398             greater than or equal to one second.
399       +/
400     this(in DateTime dateTime, in Duration fracSecs, immutable TimeZone tz = null) @safe
401     {
402         enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
403         enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
404         auto nonNullTZ = tz is null ? LocalTime() : tz;
405 
406         immutable dateDiff = dateTime.date - Date.init;
407         immutable todDiff = dateTime.timeOfDay - TimeOfDay.init;
408 
409         immutable adjustedTime = dateDiff + todDiff + fracSecs;
410         immutable standardTime = nonNullTZ.tzToUTC(adjustedTime.total!"hnsecs");
411 
412         this(standardTime, nonNullTZ);
413     }
414 
415     @safe unittest
416     {
417         static void test(DateTime dt, Duration fracSecs, immutable TimeZone tz, long expected)
418         {
419             auto sysTime = SysTime(dt, fracSecs, tz);
420             assert(sysTime._stdTime == expected);
421             assert(sysTime._timezone is (tz is null ? LocalTime() : tz),
422                    format("Given DateTime: %s, Given Duration: %s", dt, fracSecs));
423         }
424 
425         test(DateTime.init, Duration.zero, UTC(), 0);
426         test(DateTime(1, 1, 1, 12, 30, 33), Duration.zero, UTC(), 450_330_000_000L);
427         test(DateTime(0, 12, 31, 12, 30, 33), Duration.zero, UTC(), -413_670_000_000L);
428         test(DateTime(1, 1, 1, 0, 0, 0), msecs(1), UTC(), 10_000L);
429         test(DateTime(0, 12, 31, 23, 59, 59), msecs(999), UTC(), -10_000L);
430 
431         test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC(), -1);
432         test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC(), -9_999_999);
433         test(DateTime(0, 12, 31, 23, 59, 59), Duration.zero, UTC(), -10_000_000);
434 
435         assertThrown!DateTimeException(SysTime(DateTime.init, hnsecs(-1), UTC()));
436         assertThrown!DateTimeException(SysTime(DateTime.init, seconds(1), UTC()));
437     }
438 
439     /++
440         Params:
441             date = The $(REF Date,std,datetime,date) to use to set this
442                    $(LREF SysTime)'s internal std time. As
443                    $(REF Date,std,datetime,date) has no concept of time zone, tz
444                    is used as its time zone.
445             tz   = The $(REF TimeZone,std,datetime,timezone) to use for this
446                    $(LREF SysTime). If null,
447                    $(REF LocalTime,std,datetime,timezone) will be used. The
448                    given $(REF Date,std,datetime,date) is assumed to be in the
449                    given time zone.
450       +/
451     this(in Date date, immutable TimeZone tz = null) @safe nothrow
452     {
453         _timezone = tz is null ? LocalTime() : tz;
454 
455         try
456         {
457             immutable adjustedTime = (date - Date(1, 1, 1)).total!"hnsecs";
458             immutable standardTime = _timezone.tzToUTC(adjustedTime);
459 
460             this(standardTime, _timezone);
461         }
462         catch (Exception e)
463             assert(0, "Date's constructor through when it shouldn't have.");
464     }
465 
466     @safe unittest
467     {
testSysTime468         static void test(Date d, immutable TimeZone tz, long expected)
469         {
470             auto sysTime = SysTime(d, tz);
471             assert(sysTime._stdTime == expected);
472             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given Date: %s", d));
473         }
474 
475         test(Date.init, UTC(), 0);
476         test(Date(1, 1, 1), UTC(), 0);
477         test(Date(1, 1, 2), UTC(), 864000000000);
478         test(Date(0, 12, 31), UTC(), -864000000000);
479     }
480 
481     /++
482         Note:
483             Whereas the other constructors take in the given date/time, assume
484             that it's in the given time zone, and convert it to hnsecs in UTC
485             since midnight, January 1st, 1 A.D. UTC - i.e. std time - this
486             constructor takes a std time, which is specifically already in UTC,
487             so no conversion takes place. Of course, the various getter
488             properties and functions will use the given time zone's conversion
489             function to convert the results to that time zone, but no conversion
490             of the arguments to this constructor takes place.
491 
492         Params:
493             stdTime = The number of hnsecs since midnight, January 1st, 1 A.D.
494                       UTC.
495             tz      = The $(REF TimeZone,std,datetime,timezone) to use for this
496                       $(LREF SysTime). If null,
497                       $(REF LocalTime,std,datetime,timezone) will be used.
498       +/
499     this(long stdTime, immutable TimeZone tz = null) @safe pure nothrow
500     {
501         _stdTime = stdTime;
502         _timezone = tz is null ? LocalTime() : tz;
503     }
504 
505     @safe unittest
506     {
testSysTime507         static void test(long stdTime, immutable TimeZone tz)
508         {
509             auto sysTime = SysTime(stdTime, tz);
510             assert(sysTime._stdTime == stdTime);
511             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given stdTime: %s", stdTime));
512         }
513 
foreachSysTime514         foreach (stdTime; [-1234567890L, -250, 0, 250, 1235657390L])
515         {
516             foreach (tz; testTZs)
517                 test(stdTime, tz);
518         }
519     }
520 
521     /++
522         Params:
523             rhs = The $(LREF SysTime) to assign to this one.
524       +/
525     ref SysTime opAssign(const ref SysTime rhs) return @safe pure nothrow
526     {
527         _stdTime = rhs._stdTime;
528         _timezone = rhs._timezone;
529         return this;
530     }
531 
532     /++
533         Params:
534             rhs = The $(LREF SysTime) to assign to this one.
535       +/
536     ref SysTime opAssign(SysTime rhs) scope return @safe pure nothrow
537     {
538         _stdTime = rhs._stdTime;
539         _timezone = rhs._timezone;
540         return this;
541     }
542 
543     /++
544         Checks for equality between this $(LREF SysTime) and the given
545         $(LREF SysTime).
546 
547         Note that the time zone is ignored. Only the internal
548         std times (which are in UTC) are compared.
549      +/
550     bool opEquals(const SysTime rhs) @safe const pure nothrow
551     {
552         return opEquals(rhs);
553     }
554 
555     /// ditto
556     bool opEquals(const ref SysTime rhs) @safe const pure nothrow
557     {
558         return _stdTime == rhs._stdTime;
559     }
560 
561     @safe unittest
562     {
563         import std.range : chain;
564 
565         assert(SysTime(DateTime.init, UTC()) == SysTime(0, UTC()));
566         assert(SysTime(DateTime.init, UTC()) == SysTime(0));
567         assert(SysTime(Date.init, UTC()) == SysTime(0));
568         assert(SysTime(0) == SysTime(0));
569 
570         static void test(DateTime dt, immutable TimeZone tz1, immutable TimeZone tz2)
571         {
572             auto st1 = SysTime(dt);
573             st1.timezone = tz1;
574 
575             auto st2 = SysTime(dt);
576             st2.timezone = tz2;
577 
578             assert(st1 == st2);
579         }
580 
581         foreach (tz1; testTZs)
582         {
583             foreach (tz2; testTZs)
584             {
585                 foreach (dt; chain(testDateTimesBC, testDateTimesAD))
586                     test(dt, tz1, tz2);
587             }
588         }
589 
590         auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
591         const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
592         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
593         assert(st == st);
594         assert(st == cst);
595         //assert(st == ist);
596         assert(cst == st);
597         assert(cst == cst);
598         //assert(cst == ist);
599         //assert(ist == st);
600         //assert(ist == cst);
601         //assert(ist == ist);
602     }
603 
604     /++
605         Compares this $(LREF SysTime) with the given $(LREF SysTime).
606 
607         Time zone is irrelevant when comparing $(LREF SysTime)s.
608 
609         Returns:
610             $(BOOKTABLE,
611             $(TR $(TD this &lt; rhs) $(TD &lt; 0))
612             $(TR $(TD this == rhs) $(TD 0))
613             $(TR $(TD this &gt; rhs) $(TD &gt; 0))
614             )
615      +/
616     int opCmp(in SysTime rhs) @safe const pure nothrow
617     {
618         if (_stdTime < rhs._stdTime)
619             return -1;
620         if (_stdTime > rhs._stdTime)
621             return 1;
622         return 0;
623     }
624 
625     @safe unittest
626     {
627         import std.algorithm.iteration : map;
628         import std.array : array;
629         import std.range : chain;
630 
631         assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0, UTC())) == 0);
632         assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0)) == 0);
633         assert(SysTime(Date.init, UTC()).opCmp(SysTime(0)) == 0);
634         assert(SysTime(0).opCmp(SysTime(0)) == 0);
635 
636         static void testEqual(SysTime st, immutable TimeZone tz1, immutable TimeZone tz2)
637         {
638             auto st1 = st;
639             st1.timezone = tz1;
640 
641             auto st2 = st;
642             st2.timezone = tz2;
643 
644             assert(st1.opCmp(st2) == 0);
645         }
646 
647         auto sts = array(map!SysTime(chain(testDateTimesBC, testDateTimesAD)));
648 
649         foreach (st; sts)
650         {
651             foreach (tz1; testTZs)
652             {
653                 foreach (tz2; testTZs)
654                     testEqual(st, tz1, tz2);
655             }
656         }
657 
658         static void testCmp(SysTime st1, immutable TimeZone tz1, SysTime st2, immutable TimeZone tz2)
659         {
660             st1.timezone = tz1;
661             st2.timezone = tz2;
662             assert(st1.opCmp(st2) < 0);
663             assert(st2.opCmp(st1) > 0);
664         }
665 
666         foreach (si, st1; sts)
667         {
668             foreach (st2; sts[si + 1 .. $])
669             {
670                 foreach (tz1; testTZs)
671                 {
672                     foreach (tz2; testTZs)
673                         testCmp(st1, tz1, st2, tz2);
674                 }
675             }
676         }
677 
678         auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
679         const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
680         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
681         assert(st.opCmp(st) == 0);
682         assert(st.opCmp(cst) == 0);
683         //assert(st.opCmp(ist) == 0);
684         assert(cst.opCmp(st) == 0);
685         assert(cst.opCmp(cst) == 0);
686         //assert(cst.opCmp(ist) == 0);
687         //assert(ist.opCmp(st) == 0);
688         //assert(ist.opCmp(cst) == 0);
689         //assert(ist.opCmp(ist) == 0);
690     }
691 
692     /**
693      * Returns: A hash of the $(LREF SysTime)
694      */
695     size_t toHash() const @nogc pure nothrow @safe
696     {
697         static if (is(size_t == ulong))
698             return _stdTime;
699         else
700         {
701             // MurmurHash2
702             enum ulong m = 0xc6a4a7935bd1e995UL;
703             enum ulong n = m * 16;
704             enum uint r = 47;
705 
706             ulong k = _stdTime;
707             k *= m;
708             k ^= k >> r;
709             k *= m;
710 
711             ulong h = n;
712             h ^= k;
713             h *= m;
714 
715             return cast(size_t) h;
716         }
717     }
718 
719     @safe unittest
720     {
721         assert(SysTime(0).toHash == SysTime(0).toHash);
722         assert(SysTime(DateTime(2000, 1, 1)).toHash == SysTime(DateTime(2000, 1, 1)).toHash);
723         assert(SysTime(DateTime(2000, 1, 1)).toHash != SysTime(DateTime(2000, 1, 2)).toHash);
724 
725         // test that timezones aren't taken into account
726         assert(SysTime(0, LocalTime()).toHash == SysTime(0, LocalTime()).toHash);
727         assert(SysTime(0, LocalTime()).toHash == SysTime(0, UTC()).toHash);
728         assert(SysTime(DateTime(2000, 1, 1), LocalTime()).toHash == SysTime(DateTime(2000, 1, 1), LocalTime()).toHash);
729         immutable zone = new SimpleTimeZone(dur!"minutes"(60));
730         assert(SysTime(DateTime(2000, 1, 1, 1), zone).toHash == SysTime(DateTime(2000, 1, 1), UTC()).toHash);
731         assert(SysTime(DateTime(2000, 1, 1), zone).toHash != SysTime(DateTime(2000, 1, 1), UTC()).toHash);
732     }
733 
734     /++
735         Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
736         are B.C.
737      +/
738     @property short year() @safe const nothrow
739     {
740         return (cast(Date) this).year;
741     }
742 
743     @safe unittest
744     {
745         import std.range : chain;
746         static void test(SysTime sysTime, long expected)
747         {
748             assert(sysTime.year == expected, format("Value given: %s", sysTime));
749         }
750 
751         test(SysTime(0, UTC()), 1);
752         test(SysTime(1, UTC()), 1);
753         test(SysTime(-1, UTC()), 0);
754 
755         foreach (year; chain(testYearsBC, testYearsAD))
756         {
757             foreach (md; testMonthDays)
758             {
759                 foreach (tod; testTODs)
760                 {
761                     auto dt = DateTime(Date(year, md.month, md.day), tod);
762                     foreach (tz; testTZs)
763                     {
764                         foreach (fs; testFracSecs)
765                             test(SysTime(dt, fs, tz), year);
766                     }
767                 }
768             }
769         }
770 
771         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
772         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
773         assert(cst.year == 1999);
774         //assert(ist.year == 1999);
775     }
776 
777     /++
778         Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
779         are B.C.
780 
781         Params:
782             year = The year to set this $(LREF SysTime)'s year to.
783 
784         Throws:
785             $(REF DateTimeException,std,datetime,date) if the new year is not
786             a leap year and the resulting date would be on February 29th.
787      +/
788     @property void year(int year) @safe
789     {
790         auto hnsecs = adjTime;
791         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
792 
793         if (hnsecs < 0)
794         {
795             hnsecs += convert!("hours", "hnsecs")(24);
796             --days;
797         }
798 
799         auto date = Date(cast(int) days);
800         date.year = year;
801 
802         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
803         adjTime = newDaysHNSecs + hnsecs;
804     }
805 
806     ///
807     @safe unittest
808     {
809         import std.datetime.date : DateTime;
810 
811         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).year == 1999);
812         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).year == 2010);
813         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).year == -7);
814     }
815 
816     @safe unittest
817     {
818         import std.range : chain;
819 
820         static void test(SysTime st, int year, in SysTime expected)
821         {
822             st.year = year;
823             assert(st == expected);
824         }
825 
826         foreach (st; chain(testSysTimesBC, testSysTimesAD))
827         {
828             auto dt = cast(DateTime) st;
829 
830             foreach (year; chain(testYearsBC, testYearsAD))
831             {
832                 auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
833                                  st.fracSecs,
834                                  st.timezone);
835                 test(st, year, e);
836             }
837         }
838 
839         foreach (fs; testFracSecs)
840         {
841             foreach (tz; testTZs)
842             {
843                 foreach (tod; testTODs)
844                 {
845                     test(SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz), 2000,
846                          SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz));
847                     test(SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz), 1999,
848                          SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz));
849                 }
850 
851                 foreach (tod; testTODsThrown)
852                 {
853                     auto st = SysTime(DateTime(Date(2000, 2, 29), tod), fs, tz);
854                     assertThrown!DateTimeException(st.year = 1999);
855                 }
856             }
857         }
858 
859         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
860         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
861         static assert(!__traits(compiles, cst.year = 7));
862         //static assert(!__traits(compiles, ist.year = 7));
863     }
864 
865     /++
866         Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
867 
868         Throws:
869             $(REF DateTimeException,std,datetime,date) if $(D isAD) is true.
870      +/
871     @property ushort yearBC() @safe const
872     {
873         return (cast(Date) this).yearBC;
874     }
875 
876     ///
877     @safe unittest
878     {
879         import std.datetime.date : DateTime;
880 
881         assert(SysTime(DateTime(0, 1, 1, 12, 30, 33)).yearBC == 1);
882         assert(SysTime(DateTime(-1, 1, 1, 10, 7, 2)).yearBC == 2);
883         assert(SysTime(DateTime(-100, 1, 1, 4, 59, 0)).yearBC == 101);
884     }
885 
886     @safe unittest
887     {
888         import std.exception : assertNotThrown;
889         foreach (st; testSysTimesBC)
890         {
891             auto msg = format("SysTime: %s", st);
892             assertNotThrown!DateTimeException(st.yearBC, msg);
893             assert(st.yearBC == (st.year * -1) + 1, msg);
894         }
895 
896         foreach (st; [testSysTimesAD[0], testSysTimesAD[$/2], testSysTimesAD[$-1]])
897             assertThrown!DateTimeException(st.yearBC, format("SysTime: %s", st));
898 
899         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
900         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
901         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
902         st.year = 12;
903         assert(st.year == 12);
904         static assert(!__traits(compiles, cst.year = 12));
905         //static assert(!__traits(compiles, ist.year = 12));
906     }
907 
908 
909     /++
910         Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
911 
912         Params:
913             year = The year B.C. to set this $(LREF SysTime)'s year to.
914 
915         Throws:
916             $(REF DateTimeException,std,datetime,date) if a non-positive value
917             is given.
918      +/
919     @property void yearBC(int year) @safe
920     {
921         auto hnsecs = adjTime;
922         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
923 
924         if (hnsecs < 0)
925         {
926             hnsecs += convert!("hours", "hnsecs")(24);
927             --days;
928         }
929 
930         auto date = Date(cast(int) days);
931         date.yearBC = year;
932 
933         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
934         adjTime = newDaysHNSecs + hnsecs;
935     }
936 
937     @safe unittest
938     {
939         auto st = SysTime(DateTime(2010, 1, 1, 7, 30, 0));
940         st.yearBC = 1;
941         assert(st == SysTime(DateTime(0, 1, 1, 7, 30, 0)));
942 
943         st.yearBC = 10;
944         assert(st == SysTime(DateTime(-9, 1, 1, 7, 30, 0)));
945     }
946 
947     @safe unittest
948     {
949         import std.range : chain;
950         static void test(SysTime st, int year, in SysTime expected)
951         {
952             st.yearBC = year;
953             assert(st == expected, format("SysTime: %s", st));
954         }
955 
956         foreach (st; chain(testSysTimesBC, testSysTimesAD))
957         {
958             auto dt = cast(DateTime) st;
959 
960             foreach (year; testYearsBC)
961             {
962                 auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
963                                  st.fracSecs,
964                                  st.timezone);
965                 test(st, (year * -1) + 1, e);
966             }
967         }
968 
969         foreach (st; [testSysTimesBC[0], testSysTimesBC[$ - 1], testSysTimesAD[0], testSysTimesAD[$ - 1]])
970         {
971             foreach (year; testYearsBC)
972                 assertThrown!DateTimeException(st.yearBC = year);
973         }
974 
975         foreach (fs; testFracSecs)
976         {
977             foreach (tz; testTZs)
978             {
979                 foreach (tod; testTODs)
980                 {
981                     test(SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz), 2001,
982                          SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz));
983                     test(SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz), 2000,
984                          SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz));
985                 }
986 
987                 foreach (tod; testTODsThrown)
988                 {
989                     auto st = SysTime(DateTime(Date(-2000, 2, 29), tod), fs, tz);
990                     assertThrown!DateTimeException(st.year = -1999);
991                 }
992             }
993         }
994 
995         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
996         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
997         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
998         st.yearBC = 12;
999         assert(st.yearBC == 12);
1000         static assert(!__traits(compiles, cst.yearBC = 12));
1001         //static assert(!__traits(compiles, ist.yearBC = 12));
1002     }
1003 
1004     /++
1005         Month of a Gregorian Year.
1006      +/
1007     @property Month month() @safe const nothrow
1008     {
1009         return (cast(Date) this).month;
1010     }
1011 
1012     ///
1013     @safe unittest
1014     {
1015         import std.datetime.date : DateTime;
1016 
1017         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).month == 7);
1018         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).month == 10);
1019         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).month == 4);
1020     }
1021 
1022     @safe unittest
1023     {
1024         import std.range : chain;
1025 
1026         static void test(SysTime sysTime, Month expected)
1027         {
1028             assert(sysTime.month == expected, format("Value given: %s", sysTime));
1029         }
1030 
1031         test(SysTime(0, UTC()), Month.jan);
1032         test(SysTime(1, UTC()), Month.jan);
1033         test(SysTime(-1, UTC()), Month.dec);
1034 
1035         foreach (year; chain(testYearsBC, testYearsAD))
1036         {
1037             foreach (md; testMonthDays)
1038             {
1039                 foreach (tod; testTODs)
1040                 {
1041                     auto dt = DateTime(Date(year, md.month, md.day), tod);
1042                     foreach (fs; testFracSecs)
1043                     {
1044                         foreach (tz; testTZs)
1045                             test(SysTime(dt, fs, tz), md.month);
1046                     }
1047                 }
1048             }
1049         }
1050 
1051         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1052         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1053         assert(cst.month == 7);
1054         //assert(ist.month == 7);
1055     }
1056 
1057 
1058     /++
1059         Month of a Gregorian Year.
1060 
1061         Params:
1062             month = The month to set this $(LREF SysTime)'s month to.
1063 
1064         Throws:
1065             $(REF DateTimeException,std,datetime,date) if the given month is
1066             not a valid month.
1067      +/
1068     @property void month(Month month) @safe
1069     {
1070         auto hnsecs = adjTime;
1071         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1072 
1073         if (hnsecs < 0)
1074         {
1075             hnsecs += convert!("hours", "hnsecs")(24);
1076             --days;
1077         }
1078 
1079         auto date = Date(cast(int) days);
1080         date.month = month;
1081 
1082         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1083         adjTime = newDaysHNSecs + hnsecs;
1084     }
1085 
1086     @safe unittest
1087     {
1088         import std.algorithm.iteration : filter;
1089         import std.range : chain;
1090 
1091         static void test(SysTime st, Month month, in SysTime expected)
1092         {
1093             st.month = cast(Month) month;
1094             assert(st == expected);
1095         }
1096 
1097         foreach (st; chain(testSysTimesBC, testSysTimesAD))
1098         {
1099             auto dt = cast(DateTime) st;
1100 
1101             foreach (md; testMonthDays)
1102             {
1103                 if (st.day > maxDay(dt.year, md.month))
1104                     continue;
1105                 auto e = SysTime(DateTime(dt.year, md.month, dt.day, dt.hour, dt.minute, dt.second),
1106                                  st.fracSecs,
1107                                  st.timezone);
1108                 test(st, md.month, e);
1109             }
1110         }
1111 
1112         foreach (fs; testFracSecs)
1113         {
1114             foreach (tz; testTZs)
1115             {
1116                 foreach (tod; testTODs)
1117                 {
1118                     foreach (year; filter!((a){return yearIsLeapYear(a);}) (chain(testYearsBC, testYearsAD)))
1119                     {
1120                         test(SysTime(DateTime(Date(year, 1, 29), tod), fs, tz),
1121                              Month.feb,
1122                              SysTime(DateTime(Date(year, 2, 29), tod), fs, tz));
1123                     }
1124 
1125                     foreach (year; chain(testYearsBC, testYearsAD))
1126                     {
1127                         test(SysTime(DateTime(Date(year, 1, 28), tod), fs, tz),
1128                              Month.feb,
1129                              SysTime(DateTime(Date(year, 2, 28), tod), fs, tz));
1130                         test(SysTime(DateTime(Date(year, 7, 30), tod), fs, tz),
1131                              Month.jun,
1132                              SysTime(DateTime(Date(year, 6, 30), tod), fs, tz));
1133                     }
1134                 }
1135             }
1136         }
1137 
1138         foreach (fs; [testFracSecs[0], testFracSecs[$-1]])
1139         {
1140             foreach (tz; testTZs)
1141             {
1142                 foreach (tod; testTODsThrown)
1143                 {
1144                     foreach (year; [testYearsBC[$-3], testYearsBC[$-2],
1145                                     testYearsBC[$-2], testYearsAD[0],
1146                                     testYearsAD[$-2], testYearsAD[$-1]])
1147                     {
1148                         auto day = yearIsLeapYear(year) ? 30 : 29;
1149                         auto st1 = SysTime(DateTime(Date(year, 1, day), tod), fs, tz);
1150                         assertThrown!DateTimeException(st1.month = Month.feb);
1151 
1152                         auto st2 = SysTime(DateTime(Date(year, 7, 31), tod), fs, tz);
1153                         assertThrown!DateTimeException(st2.month = Month.jun);
1154                     }
1155                 }
1156             }
1157         }
1158 
1159         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1160         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1161         static assert(!__traits(compiles, cst.month = 12));
1162         //static assert(!__traits(compiles, ist.month = 12));
1163     }
1164 
1165     /++
1166         Day of a Gregorian Month.
1167      +/
1168     @property ubyte day() @safe const nothrow
1169     {
1170         return (cast(Date) this).day;
1171     }
1172 
1173     ///
1174     @safe unittest
1175     {
1176         import std.datetime.date : DateTime;
1177 
1178         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).day == 6);
1179         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).day == 4);
1180         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).day == 5);
1181     }
1182 
1183     @safe unittest
1184     {
1185         import std.range : chain;
1186 
1187         static void test(SysTime sysTime, int expected)
1188         {
1189             assert(sysTime.day == expected, format("Value given: %s", sysTime));
1190         }
1191 
1192         test(SysTime(0, UTC()), 1);
1193         test(SysTime(1, UTC()), 1);
1194         test(SysTime(-1, UTC()), 31);
1195 
1196         foreach (year; chain(testYearsBC, testYearsAD))
1197         {
1198             foreach (md; testMonthDays)
1199             {
1200                 foreach (tod; testTODs)
1201                 {
1202                     auto dt = DateTime(Date(year, md.month, md.day), tod);
1203 
1204                     foreach (tz; testTZs)
1205                     {
1206                         foreach (fs; testFracSecs)
1207                             test(SysTime(dt, fs, tz), md.day);
1208                     }
1209                 }
1210             }
1211         }
1212 
1213         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1214         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1215          assert(cst.day == 6);
1216         //assert(ist.day == 6);
1217     }
1218 
1219 
1220     /++
1221         Day of a Gregorian Month.
1222 
1223         Params:
1224             day = The day of the month to set this $(LREF SysTime)'s day to.
1225 
1226         Throws:
1227             $(REF DateTimeException,std,datetime,date) if the given day is not
1228             a valid day of the current month.
1229      +/
1230     @property void day(int day) @safe
1231     {
1232         auto hnsecs = adjTime;
1233         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1234 
1235         if (hnsecs < 0)
1236         {
1237             hnsecs += convert!("hours", "hnsecs")(24);
1238             --days;
1239         }
1240 
1241         auto date = Date(cast(int) days);
1242         date.day = day;
1243 
1244         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1245         adjTime = newDaysHNSecs + hnsecs;
1246     }
1247 
1248     @safe unittest
1249     {
1250         import std.range : chain;
1251         import std.traits : EnumMembers;
1252 
1253         foreach (day; chain(testDays))
1254         {
1255             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1256             {
1257                 auto dt = cast(DateTime) st;
1258 
1259                 if (day > maxDay(dt.year, dt.month))
1260                     continue;
1261                 auto expected = SysTime(DateTime(dt.year, dt.month, day, dt.hour, dt.minute, dt.second),
1262                                         st.fracSecs,
1263                                         st.timezone);
1264                 st.day = day;
1265                 assert(st == expected, format("[%s] [%s]", st, expected));
1266             }
1267         }
1268 
1269         foreach (tz; testTZs)
1270         {
1271             foreach (tod; testTODs)
1272             {
1273                 foreach (fs; testFracSecs)
1274                 {
1275                     foreach (year; chain(testYearsBC, testYearsAD))
1276                     {
1277                         foreach (month; EnumMembers!Month)
1278                         {
1279                             auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz);
1280                             immutable max = maxDay(year, month);
1281                             auto expected = SysTime(DateTime(Date(year, month, max), tod), fs, tz);
1282 
1283                             st.day = max;
1284                             assert(st == expected, format("[%s] [%s]", st, expected));
1285                         }
1286                     }
1287                 }
1288             }
1289         }
1290 
1291         foreach (tz; testTZs)
1292         {
1293             foreach (tod; testTODsThrown)
1294             {
1295                 foreach (fs; [testFracSecs[0], testFracSecs[$-1]])
1296                 {
1297                     foreach (year; [testYearsBC[$-3], testYearsBC[$-2],
1298                                     testYearsBC[$-2], testYearsAD[0],
1299                                     testYearsAD[$-2], testYearsAD[$-1]])
1300                     {
1301                         foreach (month; EnumMembers!Month)
1302                         {
1303                             auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz);
1304                             immutable max = maxDay(year, month);
1305 
1306                             assertThrown!DateTimeException(st.day = max + 1);
1307                         }
1308                     }
1309                 }
1310             }
1311         }
1312 
1313         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1314         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1315         static assert(!__traits(compiles, cst.day = 27));
1316         //static assert(!__traits(compiles, ist.day = 27));
1317     }
1318 
1319 
1320     /++
1321         Hours past midnight.
1322      +/
1323     @property ubyte hour() @safe const nothrow
1324     {
1325         auto hnsecs = adjTime;
1326         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1327 
1328         if (hnsecs < 0)
1329         {
1330             hnsecs += convert!("hours", "hnsecs")(24);
1331             --days;
1332         }
1333 
1334         return cast(ubyte) getUnitsFromHNSecs!"hours"(hnsecs);
1335     }
1336 
1337     @safe unittest
1338     {
1339         import std.range : chain;
1340 
1341         static void test(SysTime sysTime, int expected)
1342         {
1343             assert(sysTime.hour == expected, format("Value given: %s", sysTime));
1344         }
1345 
1346         test(SysTime(0, UTC()), 0);
1347         test(SysTime(1, UTC()), 0);
1348         test(SysTime(-1, UTC()), 23);
1349 
1350         foreach (tz; testTZs)
1351         {
1352             foreach (year; chain(testYearsBC, testYearsAD))
1353             {
1354                 foreach (md; testMonthDays)
1355                 {
1356                     foreach (hour; testHours)
1357                     {
1358                         foreach (minute; testMinSecs)
1359                         {
1360                             foreach (second; testMinSecs)
1361                             {
1362                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1363                                 foreach (fs; testFracSecs)
1364                                     test(SysTime(dt, fs, tz), hour);
1365                             }
1366                         }
1367                     }
1368                 }
1369             }
1370         }
1371 
1372         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1373         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1374         assert(cst.hour == 12);
1375         //assert(ist.hour == 12);
1376     }
1377 
1378 
1379     /++
1380         Hours past midnight.
1381 
1382         Params:
1383             hour = The hours to set this $(LREF SysTime)'s hour to.
1384 
1385         Throws:
1386             $(REF DateTimeException,std,datetime,date) if the given hour are
1387             not a valid hour of the day.
1388      +/
1389     @property void hour(int hour) @safe
1390     {
1391         enforceValid!"hours"(hour);
1392 
1393         auto hnsecs = adjTime;
1394         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1395         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1396         immutable negative = hnsecs < 0;
1397 
1398         if (negative)
1399             hnsecs += convert!("hours", "hnsecs")(24);
1400 
1401         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1402         hnsecs += convert!("hours", "hnsecs")(hour);
1403 
1404         if (negative)
1405             hnsecs -= convert!("hours", "hnsecs")(24);
1406 
1407         adjTime = daysHNSecs + hnsecs;
1408     }
1409 
1410     @safe unittest
1411     {
1412         import std.range : chain;
1413 
1414         foreach (hour; chain(testHours))
1415         {
1416             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1417             {
1418                 auto dt = cast(DateTime) st;
1419                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, hour, dt.minute, dt.second),
1420                                         st.fracSecs,
1421                                         st.timezone);
1422                 st.hour = hour;
1423                 assert(st == expected, format("[%s] [%s]", st, expected));
1424             }
1425         }
1426 
1427         auto st = testSysTimesAD[0];
1428         assertThrown!DateTimeException(st.hour = -1);
1429         assertThrown!DateTimeException(st.hour = 60);
1430 
1431         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1432         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1433         static assert(!__traits(compiles, cst.hour = 27));
1434         //static assert(!__traits(compiles, ist.hour = 27));
1435     }
1436 
1437 
1438     /++
1439         Minutes past the current hour.
1440      +/
1441     @property ubyte minute() @safe const nothrow
1442     {
1443         auto hnsecs = adjTime;
1444         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1445 
1446         if (hnsecs < 0)
1447         {
1448             hnsecs += convert!("hours", "hnsecs")(24);
1449             --days;
1450         }
1451 
1452         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1453 
1454         return cast(ubyte) getUnitsFromHNSecs!"minutes"(hnsecs);
1455     }
1456 
1457     @safe unittest
1458     {
1459         import std.range : chain;
1460 
1461         static void test(SysTime sysTime, int expected)
1462         {
1463             assert(sysTime.minute == expected, format("Value given: %s", sysTime));
1464         }
1465 
1466         test(SysTime(0, UTC()), 0);
1467         test(SysTime(1, UTC()), 0);
1468         test(SysTime(-1, UTC()), 59);
1469 
1470         foreach (tz; testTZs)
1471         {
1472             foreach (year; chain(testYearsBC, testYearsAD))
1473             {
1474                 foreach (md; testMonthDays)
1475                 {
1476                     foreach (hour; testHours)
1477                     {
1478                         foreach (minute; testMinSecs)
1479                         {
1480                             foreach (second; testMinSecs)
1481                             {
1482                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1483                                 foreach (fs; testFracSecs)
1484                                     test(SysTime(dt, fs, tz), minute);
1485                             }
1486                         }
1487                     }
1488                 }
1489             }
1490         }
1491 
1492         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1493         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1494         assert(cst.minute == 30);
1495         //assert(ist.minute == 30);
1496     }
1497 
1498 
1499     /++
1500         Minutes past the current hour.
1501 
1502         Params:
1503             minute = The minute to set this $(LREF SysTime)'s minute to.
1504 
1505         Throws:
1506             $(REF DateTimeException,std,datetime,date) if the given minute are
1507             not a valid minute of an hour.
1508      +/
1509     @property void minute(int minute) @safe
1510     {
1511         enforceValid!"minutes"(minute);
1512 
1513         auto hnsecs = adjTime;
1514         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1515         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1516         immutable negative = hnsecs < 0;
1517 
1518         if (negative)
1519             hnsecs += convert!("hours", "hnsecs")(24);
1520 
1521         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
1522         hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs);
1523 
1524         hnsecs += convert!("hours", "hnsecs")(hour);
1525         hnsecs += convert!("minutes", "hnsecs")(minute);
1526 
1527         if (negative)
1528             hnsecs -= convert!("hours", "hnsecs")(24);
1529 
1530         adjTime = daysHNSecs + hnsecs;
1531     }
1532 
1533     @safe unittest
1534     {
1535         import std.range : chain;
1536 
1537         foreach (minute; testMinSecs)
1538         {
1539             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1540             {
1541                 auto dt = cast(DateTime) st;
1542                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, minute, dt.second),
1543                                         st.fracSecs,
1544                                         st.timezone);
1545                 st.minute = minute;
1546                 assert(st == expected, format("[%s] [%s]", st, expected));
1547             }
1548         }
1549 
1550         auto st = testSysTimesAD[0];
1551         assertThrown!DateTimeException(st.minute = -1);
1552         assertThrown!DateTimeException(st.minute = 60);
1553 
1554         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1555         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1556         static assert(!__traits(compiles, cst.minute = 27));
1557         //static assert(!__traits(compiles, ist.minute = 27));
1558     }
1559 
1560 
1561     /++
1562         Seconds past the current minute.
1563      +/
1564     @property ubyte second() @safe const nothrow
1565     {
1566         auto hnsecs = adjTime;
1567         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1568 
1569         if (hnsecs < 0)
1570         {
1571             hnsecs += convert!("hours", "hnsecs")(24);
1572             --days;
1573         }
1574 
1575         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1576         hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs);
1577 
1578         return cast(ubyte) getUnitsFromHNSecs!"seconds"(hnsecs);
1579     }
1580 
1581     @safe unittest
1582     {
1583         import std.range : chain;
1584 
1585         static void test(SysTime sysTime, int expected)
1586         {
1587             assert(sysTime.second == expected, format("Value given: %s", sysTime));
1588         }
1589 
1590         test(SysTime(0, UTC()), 0);
1591         test(SysTime(1, UTC()), 0);
1592         test(SysTime(-1, UTC()), 59);
1593 
1594         foreach (tz; testTZs)
1595         {
1596             foreach (year; chain(testYearsBC, testYearsAD))
1597             {
1598                 foreach (md; testMonthDays)
1599                 {
1600                     foreach (hour; testHours)
1601                     {
1602                         foreach (minute; testMinSecs)
1603                         {
1604                             foreach (second; testMinSecs)
1605                             {
1606                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1607                                 foreach (fs; testFracSecs)
1608                                     test(SysTime(dt, fs, tz), second);
1609                             }
1610                         }
1611                     }
1612                 }
1613             }
1614         }
1615 
1616         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1617         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1618         assert(cst.second == 33);
1619         //assert(ist.second == 33);
1620     }
1621 
1622 
1623     /++
1624         Seconds past the current minute.
1625 
1626         Params:
1627             second = The second to set this $(LREF SysTime)'s second to.
1628 
1629         Throws:
1630             $(REF DateTimeException,std,datetime,date) if the given second are
1631             not a valid second of a minute.
1632      +/
1633     @property void second(int second) @safe
1634     {
1635         enforceValid!"seconds"(second);
1636 
1637         auto hnsecs = adjTime;
1638         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1639         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1640         immutable negative = hnsecs < 0;
1641 
1642         if (negative)
1643             hnsecs += convert!("hours", "hnsecs")(24);
1644 
1645         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
1646         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
1647         hnsecs = removeUnitsFromHNSecs!"seconds"(hnsecs);
1648 
1649         hnsecs += convert!("hours", "hnsecs")(hour);
1650         hnsecs += convert!("minutes", "hnsecs")(minute);
1651         hnsecs += convert!("seconds", "hnsecs")(second);
1652 
1653         if (negative)
1654             hnsecs -= convert!("hours", "hnsecs")(24);
1655 
1656         adjTime = daysHNSecs + hnsecs;
1657     }
1658 
1659     @safe unittest
1660     {
1661         import std.range : chain;
1662 
1663         foreach (second; testMinSecs)
1664         {
1665             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1666             {
1667                 auto dt = cast(DateTime) st;
1668                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, second),
1669                                         st.fracSecs,
1670                                         st.timezone);
1671                 st.second = second;
1672                 assert(st == expected, format("[%s] [%s]", st, expected));
1673             }
1674         }
1675 
1676         auto st = testSysTimesAD[0];
1677         assertThrown!DateTimeException(st.second = -1);
1678         assertThrown!DateTimeException(st.second = 60);
1679 
1680         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1681         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1682         static assert(!__traits(compiles, cst.seconds = 27));
1683         //static assert(!__traits(compiles, ist.seconds = 27));
1684     }
1685 
1686 
1687     /++
1688         Fractional seconds past the second (i.e. the portion of a
1689         $(LREF SysTime) which is less than a second).
1690      +/
1691     @property Duration fracSecs() @safe const nothrow
1692     {
1693         auto hnsecs = removeUnitsFromHNSecs!"days"(adjTime);
1694 
1695         if (hnsecs < 0)
1696             hnsecs += convert!("hours", "hnsecs")(24);
1697 
1698         return dur!"hnsecs"(removeUnitsFromHNSecs!"seconds"(hnsecs));
1699     }
1700 
1701     ///
1702     @safe unittest
1703     {
1704         import core.time : msecs, usecs, hnsecs, nsecs;
1705         import std.datetime.date : DateTime;
1706 
1707         auto dt = DateTime(1982, 4, 1, 20, 59, 22);
1708         assert(SysTime(dt, msecs(213)).fracSecs == msecs(213));
1709         assert(SysTime(dt, usecs(5202)).fracSecs == usecs(5202));
1710         assert(SysTime(dt, hnsecs(1234567)).fracSecs == hnsecs(1234567));
1711 
1712         // SysTime and Duration both have a precision of hnsecs (100 ns),
1713         // so nsecs are going to be truncated.
1714         assert(SysTime(dt, nsecs(123456789)).fracSecs == nsecs(123456700));
1715     }
1716 
1717     @safe unittest
1718     {
1719         import std.range : chain;
1720 
1721         assert(SysTime(0, UTC()).fracSecs == Duration.zero);
1722         assert(SysTime(1, UTC()).fracSecs == hnsecs(1));
1723         assert(SysTime(-1, UTC()).fracSecs == hnsecs(9_999_999));
1724 
1725         foreach (tz; testTZs)
1726         {
1727             foreach (year; chain(testYearsBC, testYearsAD))
1728             {
1729                 foreach (md; testMonthDays)
1730                 {
1731                     foreach (hour; testHours)
1732                     {
1733                         foreach (minute; testMinSecs)
1734                         {
1735                             foreach (second; testMinSecs)
1736                             {
1737                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1738                                 foreach (fs; testFracSecs)
1739                                     assert(SysTime(dt, fs, tz).fracSecs == fs);
1740                             }
1741                         }
1742                     }
1743                 }
1744             }
1745         }
1746 
1747         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1748         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1749         assert(cst.fracSecs == Duration.zero);
1750         //assert(ist.fracSecs == Duration.zero);
1751     }
1752 
1753 
1754     /++
1755         Fractional seconds past the second (i.e. the portion of a
1756         $(LREF SysTime) which is less than a second).
1757 
1758         Params:
1759             fracSecs = The duration to set this $(LREF SysTime)'s fractional
1760                        seconds to.
1761 
1762         Throws:
1763             $(REF DateTimeException,std,datetime,date) if the given duration
1764             is negative or if it's greater than or equal to one second.
1765      +/
1766     @property void fracSecs(Duration fracSecs) @safe
1767     {
1768         enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
1769         enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
1770 
1771         auto oldHNSecs = adjTime;
1772         auto days = splitUnitsFromHNSecs!"days"(oldHNSecs);
1773         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1774         immutable negative = oldHNSecs < 0;
1775 
1776         if (negative)
1777             oldHNSecs += convert!("hours", "hnsecs")(24);
1778 
1779         immutable seconds = splitUnitsFromHNSecs!"seconds"(oldHNSecs);
1780         immutable secondsHNSecs = convert!("seconds", "hnsecs")(seconds);
1781         auto newHNSecs = fracSecs.total!"hnsecs" + secondsHNSecs;
1782 
1783         if (negative)
1784             newHNSecs -= convert!("hours", "hnsecs")(24);
1785 
1786         adjTime = daysHNSecs + newHNSecs;
1787     }
1788 
1789     ///
1790     @safe unittest
1791     {
1792         import core.time : Duration, msecs, hnsecs, nsecs;
1793         import std.datetime.date : DateTime;
1794 
1795         auto st = SysTime(DateTime(1982, 4, 1, 20, 59, 22));
1796         assert(st.fracSecs == Duration.zero);
1797 
1798         st.fracSecs = msecs(213);
1799         assert(st.fracSecs == msecs(213));
1800 
1801         st.fracSecs = hnsecs(1234567);
1802         assert(st.fracSecs == hnsecs(1234567));
1803 
1804         // SysTime has a precision of hnsecs (100 ns), so nsecs are
1805         // going to be truncated.
1806         st.fracSecs = nsecs(123456789);
1807         assert(st.fracSecs == hnsecs(1234567));
1808     }
1809 
1810     @safe unittest
1811     {
1812         import std.range : chain;
1813 
1814         foreach (fracSec; testFracSecs)
1815         {
1816             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1817             {
1818                 auto dt = cast(DateTime) st;
1819                 auto expected = SysTime(dt, fracSec, st.timezone);
1820                 st.fracSecs = fracSec;
1821                 assert(st == expected, format("[%s] [%s]", st, expected));
1822             }
1823         }
1824 
1825         auto st = testSysTimesAD[0];
1826         assertThrown!DateTimeException(st.fracSecs = hnsecs(-1));
1827         assertThrown!DateTimeException(st.fracSecs = seconds(1));
1828 
1829         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1830         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1831         static assert(!__traits(compiles, cst.fracSecs = msecs(7)));
1832         //static assert(!__traits(compiles, ist.fracSecs = msecs(7)));
1833     }
1834 
1835 
1836     /++
1837         The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the
1838         internal representation of $(LREF SysTime).
1839      +/
1840     @property long stdTime() @safe const pure nothrow
1841     {
1842         return _stdTime;
1843     }
1844 
1845     @safe unittest
1846     {
1847         assert(SysTime(0).stdTime == 0);
1848         assert(SysTime(1).stdTime == 1);
1849         assert(SysTime(-1).stdTime == -1);
1850         assert(SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC()).stdTime == 330_000_502L);
1851         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC()).stdTime == 621_355_968_000_000_000L);
1852 
1853         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1854         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1855         assert(cst.stdTime > 0);
1856         //assert(ist.stdTime > 0);
1857     }
1858 
1859 
1860     /++
1861         The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the
1862         internal representation of $(LREF SysTime).
1863 
1864         Params:
1865             stdTime = The number of hnsecs since January 1st, 1 A.D. UTC.
1866      +/
1867     @property void stdTime(long stdTime) @safe pure nothrow
1868     {
1869         _stdTime = stdTime;
1870     }
1871 
1872     @safe unittest
1873     {
1874         static void test(long stdTime, in SysTime expected, size_t line = __LINE__)
1875         {
1876             auto st = SysTime(0, UTC());
1877             st.stdTime = stdTime;
1878             assert(st == expected);
1879         }
1880 
1881         test(0, SysTime(Date(1, 1, 1), UTC()));
1882         test(1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()));
1883         test(-1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()));
1884         test(330_000_502L, SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC()));
1885         test(621_355_968_000_000_000L, SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC()));
1886 
1887         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1888         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1889         static assert(!__traits(compiles, cst.stdTime = 27));
1890         //static assert(!__traits(compiles, ist.stdTime = 27));
1891     }
1892 
1893 
1894     /++
1895         The current time zone of this $(LREF SysTime). Its internal time is
1896         always kept in UTC, so there are no conversion issues between time zones
1897         due to DST. Functions which return all or part of the time - such as
1898         hours - adjust the time to this $(LREF SysTime)'s time zone before
1899         returning.
1900       +/
1901     @property immutable(TimeZone) timezone() @safe const pure nothrow
1902     {
1903         return _timezone;
1904     }
1905 
1906 
1907     /++
1908         The current time zone of this $(LREF SysTime). It's internal time is
1909         always kept in UTC, so there are no conversion issues between time zones
1910         due to DST. Functions which return all or part of the time - such as
1911         hours - adjust the time to this $(LREF SysTime)'s time zone before
1912         returning.
1913 
1914         Params:
1915             timezone = The $(REF _TimeZone,std,datetime,_timezone) to set this
1916                        $(LREF SysTime)'s time zone to.
1917       +/
1918     @property void timezone(immutable TimeZone timezone) @safe pure nothrow
1919     {
1920         if (timezone is null)
1921             _timezone = LocalTime();
1922         else
1923             _timezone = timezone;
1924     }
1925 
1926 
1927     /++
1928         Returns whether DST is in effect for this $(LREF SysTime).
1929       +/
1930     @property bool dstInEffect() @safe const nothrow
1931     {
1932         return _timezone.dstInEffect(_stdTime);
1933         // This function's unit testing is done in the time zone classes.
1934     }
1935 
1936 
1937     /++
1938         Returns what the offset from UTC is for this $(LREF SysTime).
1939         It includes the DST offset in effect at that time (if any).
1940       +/
1941     @property Duration utcOffset() @safe const nothrow
1942     {
1943         return _timezone.utcOffsetAt(_stdTime);
1944     }
1945 
1946 
1947     /++
1948         Returns a $(LREF SysTime) with the same std time as this one, but with
1949         $(REF LocalTime,std,datetime,timezone) as its time zone.
1950       +/
1951     SysTime toLocalTime() @safe const pure nothrow
1952     {
1953         return SysTime(_stdTime, LocalTime());
1954     }
1955 
1956     @safe unittest
1957     {
1958         {
1959             auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
1960             assert(sysTime == sysTime.toLocalTime());
1961             assert(sysTime._stdTime == sysTime.toLocalTime()._stdTime);
1962             assert(sysTime.toLocalTime().timezone is LocalTime());
1963             assert(sysTime.toLocalTime().timezone is sysTime.timezone);
1964             assert(sysTime.toLocalTime().timezone !is UTC());
1965         }
1966 
1967         {
1968             auto stz = new immutable SimpleTimeZone(dur!"minutes"(-3 * 60));
1969             auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27), stz);
1970             assert(sysTime == sysTime.toLocalTime());
1971             assert(sysTime._stdTime == sysTime.toLocalTime()._stdTime);
1972             assert(sysTime.toLocalTime().timezone is LocalTime());
1973             assert(sysTime.toLocalTime().timezone !is UTC());
1974             assert(sysTime.toLocalTime().timezone !is stz);
1975         }
1976     }
1977 
1978 
1979     /++
1980         Returns a $(LREF SysTime) with the same std time as this one, but with
1981         $(D UTC) as its time zone.
1982       +/
1983     SysTime toUTC() @safe const pure nothrow
1984     {
1985         return SysTime(_stdTime, UTC());
1986     }
1987 
1988     @safe unittest
1989     {
1990         auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
1991         assert(sysTime == sysTime.toUTC());
1992         assert(sysTime._stdTime == sysTime.toUTC()._stdTime);
1993         assert(sysTime.toUTC().timezone is UTC());
1994         assert(sysTime.toUTC().timezone !is LocalTime());
1995         assert(sysTime.toUTC().timezone !is sysTime.timezone);
1996     }
1997 
1998 
1999     /++
2000         Returns a $(LREF SysTime) with the same std time as this one, but with
2001         given time zone as its time zone.
2002       +/
2003     SysTime toOtherTZ(immutable TimeZone tz) @safe const pure nothrow
2004     {
2005         if (tz is null)
2006             return SysTime(_stdTime, LocalTime());
2007         else
2008             return SysTime(_stdTime, tz);
2009     }
2010 
2011     @safe unittest
2012     {
2013         auto stz = new immutable SimpleTimeZone(dur!"minutes"(11 * 60));
2014         auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2015         assert(sysTime == sysTime.toOtherTZ(stz));
2016         assert(sysTime._stdTime == sysTime.toOtherTZ(stz)._stdTime);
2017         assert(sysTime.toOtherTZ(stz).timezone is stz);
2018         assert(sysTime.toOtherTZ(stz).timezone !is LocalTime());
2019         assert(sysTime.toOtherTZ(stz).timezone !is UTC());
2020     }
2021 
2022 
2023     /++
2024         Converts this $(LREF SysTime) to unix time (i.e. seconds from midnight,
2025         January 1st, 1970 in UTC).
2026 
2027         The C standard does not specify the representation of time_t, so it is
2028         implementation defined. On POSIX systems, unix time is equivalent to
2029         time_t, but that's not necessarily true on other systems (e.g. it is
2030         not true for the Digital Mars C runtime). So, be careful when using unix
2031         time with C functions on non-POSIX systems.
2032 
2033         By default, the return type is time_t (which is normally an alias for
2034         int on 32-bit systems and long on 64-bit systems), but if a different
2035         size is required than either int or long can be passed as a template
2036         argument to get the desired size.
2037 
2038         If the return type is int, and the result can't fit in an int, then the
2039         closest value that can be held in 32 bits will be used (so $(D int.max)
2040         if it goes over and $(D int.min) if it goes under). However, no attempt
2041         is made to deal with integer overflow if the return type is long.
2042 
2043         Params:
2044             T = The return type (int or long). It defaults to time_t, which is
2045                 normally 32 bits on a 32-bit system and 64 bits on a 64-bit
2046                 system.
2047 
2048         Returns:
2049             A signed integer representing the unix time which is equivalent to
2050             this SysTime.
2051       +/
2052     T toUnixTime(T = time_t)() @safe const pure nothrow
2053         if (is(T == int) || is(T == long))
2054     {
2055         return stdTimeToUnixTime!T(_stdTime);
2056     }
2057 
2058     ///
2059     @safe unittest
2060     {
2061         import core.time : hours;
2062         import std.datetime.date : DateTime;
2063         import std.datetime.timezone : SimpleTimeZone, UTC;
2064 
2065         assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0);
2066 
2067         auto pst = new immutable SimpleTimeZone(hours(-8));
2068         assert(SysTime(DateTime(1970, 1, 1), pst).toUnixTime() == 28800);
2069 
2070         auto utc = SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC());
2071         assert(utc.toUnixTime() == 1_198_311_285);
2072 
2073         auto ca = SysTime(DateTime(2007, 12, 22, 8, 14, 45), pst);
2074         assert(ca.toUnixTime() == 1_198_340_085);
2075     }
2076 
2077     @safe unittest
2078     {
2079         import std.meta : AliasSeq;
2080         assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0);
2081         foreach (units; AliasSeq!("hnsecs", "usecs", "msecs"))
2082             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), dur!units(1), UTC()).toUnixTime() == 0);
2083         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toUnixTime() == 1);
2084         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toUnixTime() == 0);
2085         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toUnixTime() == 0);
2086         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toUnixTime() == 0);
2087         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toUnixTime() == -1);
2088     }
2089 
2090 
2091     /++
2092         Converts from unix time (i.e. seconds from midnight, January 1st, 1970
2093         in UTC) to a $(LREF SysTime).
2094 
2095         The C standard does not specify the representation of time_t, so it is
2096         implementation defined. On POSIX systems, unix time is equivalent to
2097         time_t, but that's not necessarily true on other systems (e.g. it is
2098         not true for the Digital Mars C runtime). So, be careful when using unix
2099         time with C functions on non-POSIX systems.
2100 
2101         Params:
2102             unixTime = Seconds from midnight, January 1st, 1970 in UTC.
2103             tz = The time zone for the SysTime that's returned.
2104       +/
2105     static SysTime fromUnixTime(long unixTime, immutable TimeZone tz = LocalTime()) @safe pure nothrow
2106     {
2107         return SysTime(unixTimeToStdTime(unixTime), tz);
2108     }
2109 
2110     ///
2111     @safe unittest
2112     {
2113         import core.time : hours;
2114         import std.datetime.date : DateTime;
2115         import std.datetime.timezone : SimpleTimeZone, UTC;
2116 
2117         assert(SysTime.fromUnixTime(0) ==
2118                SysTime(DateTime(1970, 1, 1), UTC()));
2119 
2120         auto pst = new immutable SimpleTimeZone(hours(-8));
2121         assert(SysTime.fromUnixTime(28800) ==
2122                SysTime(DateTime(1970, 1, 1), pst));
2123 
2124         auto st1 = SysTime.fromUnixTime(1_198_311_285, UTC());
2125         assert(st1 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC()));
2126         assert(st1.timezone is UTC());
2127         assert(st1 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst));
2128 
2129         auto st2 = SysTime.fromUnixTime(1_198_311_285, pst);
2130         assert(st2 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC()));
2131         assert(st2.timezone is pst);
2132         assert(st2 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst));
2133     }
2134 
2135     @safe unittest
2136     {
2137         assert(SysTime.fromUnixTime(0) == SysTime(DateTime(1970, 1, 1), UTC()));
2138         assert(SysTime.fromUnixTime(1) == SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()));
2139         assert(SysTime.fromUnixTime(-1) == SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()));
2140 
2141         auto st = SysTime.fromUnixTime(0);
2142         auto dt = cast(DateTime) st;
2143         assert(dt <= DateTime(1970, 2, 1) && dt >= DateTime(1969, 12, 31));
2144         assert(st.timezone is LocalTime());
2145 
2146         auto aest = new immutable SimpleTimeZone(hours(10));
2147         assert(SysTime.fromUnixTime(-36000) == SysTime(DateTime(1970, 1, 1), aest));
2148     }
2149 
2150 
2151     /++
2152         Returns a $(D timeval) which represents this $(LREF SysTime).
2153 
2154         Note that like all conversions in std.datetime, this is a truncating
2155         conversion.
2156 
2157         If $(D timeval.tv_sec) is int, and the result can't fit in an int, then
2158         the closest value that can be held in 32 bits will be used for
2159         $(D tv_sec). (so $(D int.max) if it goes over and $(D int.min) if it
2160         goes under).
2161       +/
2162     timeval toTimeVal() @safe const pure nothrow
2163     {
2164         immutable tv_sec = toUnixTime!(typeof(timeval.tv_sec))();
2165         immutable fracHNSecs = removeUnitsFromHNSecs!"seconds"(_stdTime - 621_355_968_000_000_000L);
2166         immutable tv_usec = cast(typeof(timeval.tv_usec))convert!("hnsecs", "usecs")(fracHNSecs);
2167         return timeval(tv_sec, tv_usec);
2168     }
2169 
2170     @safe unittest
2171     {
2172         assert(SysTime(DateTime(1970, 1, 1), UTC()).toTimeVal() == timeval(0, 0));
2173         assert(SysTime(DateTime(1970, 1, 1), hnsecs(9), UTC()).toTimeVal() == timeval(0, 0));
2174         assert(SysTime(DateTime(1970, 1, 1), hnsecs(10), UTC()).toTimeVal() == timeval(0, 1));
2175         assert(SysTime(DateTime(1970, 1, 1), usecs(7), UTC()).toTimeVal() == timeval(0, 7));
2176 
2177         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toTimeVal() == timeval(1, 0));
2178         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(9), UTC()).toTimeVal() == timeval(1, 0));
2179         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(10), UTC()).toTimeVal() == timeval(1, 1));
2180         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), usecs(7), UTC()).toTimeVal() == timeval(1, 7));
2181 
2182         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toTimeVal() == timeval(0, 0));
2183         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_990), UTC()).toTimeVal() == timeval(0, -1));
2184 
2185         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toTimeVal() == timeval(0, -1));
2186         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999), UTC()).toTimeVal() == timeval(0, -999_001));
2187         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toTimeVal() == timeval(0, -1000));
2188         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toTimeVal() == timeval(-1, 0));
2189         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 58), usecs(17), UTC()).toTimeVal() == timeval(-1, -999_983));
2190     }
2191 
2192 
2193     version (StdDdoc)
2194     {
2195         private struct timespec {}
2196         /++
2197             Returns a $(D timespec) which represents this $(LREF SysTime).
2198 
2199             $(BLUE This function is Posix-Only.)
2200           +/
2201         timespec toTimeSpec() @safe const pure nothrow;
2202     }
2203     else version (Posix)
2204     {
2205         timespec toTimeSpec() @safe const pure nothrow
2206         {
2207             immutable tv_sec = toUnixTime!(typeof(timespec.tv_sec))();
2208             immutable fracHNSecs = removeUnitsFromHNSecs!"seconds"(_stdTime - 621_355_968_000_000_000L);
2209             immutable tv_nsec = cast(typeof(timespec.tv_nsec))convert!("hnsecs", "nsecs")(fracHNSecs);
2210             return timespec(tv_sec, tv_nsec);
2211         }
2212 
2213         @safe unittest
2214         {
2215             assert(SysTime(DateTime(1970, 1, 1), UTC()).toTimeSpec() == timespec(0, 0));
2216             assert(SysTime(DateTime(1970, 1, 1), hnsecs(9), UTC()).toTimeSpec() == timespec(0, 900));
2217             assert(SysTime(DateTime(1970, 1, 1), hnsecs(10), UTC()).toTimeSpec() == timespec(0, 1000));
2218             assert(SysTime(DateTime(1970, 1, 1), usecs(7), UTC()).toTimeSpec() == timespec(0, 7000));
2219 
2220             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toTimeSpec() == timespec(1, 0));
2221             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(9), UTC()).toTimeSpec() == timespec(1, 900));
2222             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(10), UTC()).toTimeSpec() == timespec(1, 1000));
2223             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), usecs(7), UTC()).toTimeSpec() == timespec(1, 7000));
2224 
2225             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toTimeSpec() ==
2226                    timespec(0, -100));
2227             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_990), UTC()).toTimeSpec() ==
2228                    timespec(0, -1000));
2229 
2230             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toTimeSpec() ==
2231                    timespec(0, -1_000));
2232             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999), UTC()).toTimeSpec() ==
2233                    timespec(0, -999_001_000));
2234             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toTimeSpec() ==
2235                    timespec(0, -1_000_000));
2236             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toTimeSpec() ==
2237                    timespec(-1, 0));
2238             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 58), usecs(17), UTC()).toTimeSpec() ==
2239                    timespec(-1, -999_983_000));
2240         }
2241     }
2242 
2243     /++
2244         Returns a $(D tm) which represents this $(LREF SysTime).
2245       +/
2246     tm toTM() @safe const nothrow
2247     {
2248         auto dateTime = cast(DateTime) this;
2249         tm timeInfo;
2250 
2251         timeInfo.tm_sec = dateTime.second;
2252         timeInfo.tm_min = dateTime.minute;
2253         timeInfo.tm_hour = dateTime.hour;
2254         timeInfo.tm_mday = dateTime.day;
2255         timeInfo.tm_mon = dateTime.month - 1;
2256         timeInfo.tm_year = dateTime.year - 1900;
2257         timeInfo.tm_wday = dateTime.dayOfWeek;
2258         timeInfo.tm_yday = dateTime.dayOfYear - 1;
2259         timeInfo.tm_isdst = _timezone.dstInEffect(_stdTime);
2260 
2261         version (Posix)
2262         {
2263             import std.utf : toUTFz;
2264             timeInfo.tm_gmtoff = cast(int) convert!("hnsecs", "seconds")(adjTime - _stdTime);
2265             auto zone = (timeInfo.tm_isdst ? _timezone.dstName : _timezone.stdName);
2266             timeInfo.tm_zone = zone.toUTFz!(char*)();
2267         }
2268 
2269         return timeInfo;
2270     }
2271 
2272     @system unittest
2273     {
2274         import std.conv : to;
2275 
2276         version (Posix)
2277         {
2278             scope(exit) clearTZEnvVar();
2279             setTZEnvVar("America/Los_Angeles");
2280         }
2281 
2282         {
2283             auto timeInfo = SysTime(DateTime(1970, 1, 1)).toTM();
2284 
2285             assert(timeInfo.tm_sec == 0);
2286             assert(timeInfo.tm_min == 0);
2287             assert(timeInfo.tm_hour == 0);
2288             assert(timeInfo.tm_mday == 1);
2289             assert(timeInfo.tm_mon == 0);
2290             assert(timeInfo.tm_year == 70);
2291             assert(timeInfo.tm_wday == 4);
2292             assert(timeInfo.tm_yday == 0);
2293 
2294             version (Posix)
2295                 assert(timeInfo.tm_isdst == 0);
2296             else version (Windows)
2297                 assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
2298 
2299             version (Posix)
2300             {
2301                 assert(timeInfo.tm_gmtoff == -8 * 60 * 60);
2302                 assert(to!string(timeInfo.tm_zone) == "PST");
2303             }
2304         }
2305 
2306         {
2307             auto timeInfo = SysTime(DateTime(2010, 7, 4, 12, 15, 7), hnsecs(15)).toTM();
2308 
2309             assert(timeInfo.tm_sec == 7);
2310             assert(timeInfo.tm_min == 15);
2311             assert(timeInfo.tm_hour == 12);
2312             assert(timeInfo.tm_mday == 4);
2313             assert(timeInfo.tm_mon == 6);
2314             assert(timeInfo.tm_year == 110);
2315             assert(timeInfo.tm_wday == 0);
2316             assert(timeInfo.tm_yday == 184);
2317 
2318             version (Posix)
2319                 assert(timeInfo.tm_isdst == 1);
2320             else version (Windows)
2321                 assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
2322 
2323             version (Posix)
2324             {
2325                 assert(timeInfo.tm_gmtoff == -7 * 60 * 60);
2326                 assert(to!string(timeInfo.tm_zone) == "PDT");
2327             }
2328         }
2329     }
2330 
2331 
2332     /++
2333         Adds the given number of years or months to this $(LREF SysTime). A
2334         negative number will subtract.
2335 
2336         Note that if day overflow is allowed, and the date with the adjusted
2337         year/month overflows the number of days in the new month, then the month
2338         will be incremented by one, and the day set to the number of days
2339         overflowed. (e.g. if the day were 31 and the new month were June, then
2340         the month would be incremented to July, and the new day would be 1). If
2341         day overflow is not allowed, then the day will be set to the last valid
2342         day in the month (e.g. June 31st would become June 30th).
2343 
2344         Params:
2345             units         = The type of units to add ("years" or "months").
2346             value         = The number of months or years to add to this
2347                             $(LREF SysTime).
2348             allowOverflow = Whether the days should be allowed to overflow,
2349                             causing the month to increment.
2350       +/
2351     ref SysTime add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow
2352         if (units == "years" || units == "months")
2353     {
2354         auto hnsecs = adjTime;
2355         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
2356 
2357         if (hnsecs < 0)
2358         {
2359             hnsecs += convert!("hours", "hnsecs")(24);
2360             --days;
2361         }
2362 
2363         auto date = Date(cast(int) days);
2364         date.add!units(value, allowOverflow);
2365         days = date.dayOfGregorianCal - 1;
2366 
2367         if (days < 0)
2368         {
2369             hnsecs -= convert!("hours", "hnsecs")(24);
2370             ++days;
2371         }
2372 
2373         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
2374 
2375         adjTime = newDaysHNSecs + hnsecs;
2376 
2377         return this;
2378     }
2379 
2380     @safe unittest
2381     {
2382         auto st1 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
2383         st1.add!"months"(11);
2384         assert(st1 == SysTime(DateTime(2010, 12, 1, 12, 30, 33)));
2385 
2386         auto st2 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
2387         st2.add!"months"(-11);
2388         assert(st2 == SysTime(DateTime(2009, 2, 1, 12, 30, 33)));
2389 
2390         auto st3 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
2391         st3.add!"years"(1);
2392         assert(st3 == SysTime(DateTime(2001, 3, 1, 12, 30, 33)));
2393 
2394         auto st4 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
2395         st4.add!"years"(1, AllowDayOverflow.no);
2396         assert(st4 == SysTime(DateTime(2001, 2, 28, 12, 30, 33)));
2397     }
2398 
2399     // Test add!"years"() with AllowDayOverflow.yes
2400     @safe unittest
2401     {
2402         // Test A.D.
2403         {
2404             auto sysTime = SysTime(Date(1999, 7, 6));
2405             sysTime.add!"years"(7);
2406             assert(sysTime == SysTime(Date(2006, 7, 6)));
2407             sysTime.add!"years"(-9);
2408             assert(sysTime == SysTime(Date(1997, 7, 6)));
2409         }
2410 
2411         {
2412             auto sysTime = SysTime(Date(1999, 2, 28));
2413             sysTime.add!"years"(1);
2414             assert(sysTime == SysTime(Date(2000, 2, 28)));
2415         }
2416 
2417         {
2418             auto sysTime = SysTime(Date(2000, 2, 29));
2419             sysTime.add!"years"(-1);
2420             assert(sysTime == SysTime(Date(1999, 3, 1)));
2421         }
2422 
2423         {
2424             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234));
2425             sysTime.add!"years"(7);
2426             assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234)));
2427             sysTime.add!"years"(-9);
2428             assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234)));
2429         }
2430 
2431         {
2432             auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207));
2433             sysTime.add!"years"(1);
2434             assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207)));
2435         }
2436 
2437         {
2438             auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207));
2439             sysTime.add!"years"(-1);
2440             assert(sysTime == SysTime(DateTime(1999, 3, 1, 0, 7, 2), usecs(1207)));
2441         }
2442 
2443         // Test B.C.
2444         {
2445             auto sysTime = SysTime(Date(-1999, 7, 6));
2446             sysTime.add!"years"(-7);
2447             assert(sysTime == SysTime(Date(-2006, 7, 6)));
2448             sysTime.add!"years"(9);
2449             assert(sysTime == SysTime(Date(-1997, 7, 6)));
2450         }
2451 
2452         {
2453             auto sysTime = SysTime(Date(-1999, 2, 28));
2454             sysTime.add!"years"(-1);
2455             assert(sysTime == SysTime(Date(-2000, 2, 28)));
2456         }
2457 
2458         {
2459             auto sysTime = SysTime(Date(-2000, 2, 29));
2460             sysTime.add!"years"(1);
2461             assert(sysTime == SysTime(Date(-1999, 3, 1)));
2462         }
2463 
2464         {
2465             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234));
2466             sysTime.add!"years"(-7);
2467             assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234)));
2468             sysTime.add!"years"(9);
2469             assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234)));
2470         }
2471 
2472         {
2473             auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3));
2474             sysTime.add!"years"(-1);
2475             assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3)));
2476         }
2477 
2478         {
2479             auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3));
2480             sysTime.add!"years"(1);
2481             assert(sysTime == SysTime(DateTime(-1999, 3, 1, 3, 3, 3), hnsecs(3)));
2482         }
2483 
2484         // Test Both
2485         {
2486             auto sysTime = SysTime(Date(4, 7, 6));
2487             sysTime.add!"years"(-5);
2488             assert(sysTime == SysTime(Date(-1, 7, 6)));
2489             sysTime.add!"years"(5);
2490             assert(sysTime == SysTime(Date(4, 7, 6)));
2491         }
2492 
2493         {
2494             auto sysTime = SysTime(Date(-4, 7, 6));
2495             sysTime.add!"years"(5);
2496             assert(sysTime == SysTime(Date(1, 7, 6)));
2497             sysTime.add!"years"(-5);
2498             assert(sysTime == SysTime(Date(-4, 7, 6)));
2499         }
2500 
2501         {
2502             auto sysTime = SysTime(Date(4, 7, 6));
2503             sysTime.add!"years"(-8);
2504             assert(sysTime == SysTime(Date(-4, 7, 6)));
2505             sysTime.add!"years"(8);
2506             assert(sysTime == SysTime(Date(4, 7, 6)));
2507         }
2508 
2509         {
2510             auto sysTime = SysTime(Date(-4, 7, 6));
2511             sysTime.add!"years"(8);
2512             assert(sysTime == SysTime(Date(4, 7, 6)));
2513             sysTime.add!"years"(-8);
2514             assert(sysTime == SysTime(Date(-4, 7, 6)));
2515         }
2516 
2517         {
2518             auto sysTime = SysTime(Date(-4, 2, 29));
2519             sysTime.add!"years"(5);
2520             assert(sysTime == SysTime(Date(1, 3, 1)));
2521         }
2522 
2523         {
2524             auto sysTime = SysTime(Date(4, 2, 29));
2525             sysTime.add!"years"(-5);
2526             assert(sysTime == SysTime(Date(-1, 3, 1)));
2527         }
2528 
2529         {
2530             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
2531             sysTime.add!"years"(-1);
2532             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2533             sysTime.add!"years"(1);
2534             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2535         }
2536 
2537         {
2538             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2539             sysTime.add!"years"(-1);
2540             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2541             sysTime.add!"years"(1);
2542             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2543         }
2544 
2545         {
2546             auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0));
2547             sysTime.add!"years"(1);
2548             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2549             sysTime.add!"years"(-1);
2550             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2551         }
2552 
2553         {
2554             auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2555             sysTime.add!"years"(1);
2556             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2557             sysTime.add!"years"(-1);
2558             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2559         }
2560 
2561         {
2562             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
2563             sysTime.add!"years"(-5);
2564             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
2565             sysTime.add!"years"(5);
2566             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
2567         }
2568 
2569         {
2570             auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329));
2571             sysTime.add!"years"(5);
2572             assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329)));
2573             sysTime.add!"years"(-5);
2574             assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)));
2575         }
2576 
2577         {
2578             auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555));
2579             sysTime.add!"years"(5);
2580             assert(sysTime == SysTime(DateTime(1, 3, 1, 5, 5, 5), msecs(555)));
2581         }
2582 
2583         {
2584             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
2585             sysTime.add!"years"(-5);
2586             assert(sysTime == SysTime(DateTime(-1, 3, 1, 5, 5, 5), msecs(555)));
2587         }
2588 
2589         {
2590             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
2591             sysTime.add!"years"(-5).add!"years"(7);
2592             assert(sysTime == SysTime(DateTime(6, 3, 1, 5, 5, 5), msecs(555)));
2593         }
2594 
2595         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2596         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2597         static assert(!__traits(compiles, cst.add!"years"(4)));
2598         //static assert(!__traits(compiles, ist.add!"years"(4)));
2599     }
2600 
2601     // Test add!"years"() with AllowDayOverflow.no
2602     @safe unittest
2603     {
2604         // Test A.D.
2605         {
2606             auto sysTime = SysTime(Date(1999, 7, 6));
2607             sysTime.add!"years"(7, AllowDayOverflow.no);
2608             assert(sysTime == SysTime(Date(2006, 7, 6)));
2609             sysTime.add!"years"(-9, AllowDayOverflow.no);
2610             assert(sysTime == SysTime(Date(1997, 7, 6)));
2611         }
2612 
2613         {
2614             auto sysTime = SysTime(Date(1999, 2, 28));
2615             sysTime.add!"years"(1, AllowDayOverflow.no);
2616             assert(sysTime == SysTime(Date(2000, 2, 28)));
2617         }
2618 
2619         {
2620             auto sysTime = SysTime(Date(2000, 2, 29));
2621             sysTime.add!"years"(-1, AllowDayOverflow.no);
2622             assert(sysTime == SysTime(Date(1999, 2, 28)));
2623         }
2624 
2625         {
2626             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234));
2627             sysTime.add!"years"(7, AllowDayOverflow.no);
2628             assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234)));
2629             sysTime.add!"years"(-9, AllowDayOverflow.no);
2630             assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234)));
2631         }
2632 
2633         {
2634             auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207));
2635             sysTime.add!"years"(1, AllowDayOverflow.no);
2636             assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207)));
2637         }
2638 
2639         {
2640             auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207));
2641             sysTime.add!"years"(-1, AllowDayOverflow.no);
2642             assert(sysTime == SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207)));
2643         }
2644 
2645         // Test B.C.
2646         {
2647             auto sysTime = SysTime(Date(-1999, 7, 6));
2648             sysTime.add!"years"(-7, AllowDayOverflow.no);
2649             assert(sysTime == SysTime(Date(-2006, 7, 6)));
2650             sysTime.add!"years"(9, AllowDayOverflow.no);
2651             assert(sysTime == SysTime(Date(-1997, 7, 6)));
2652         }
2653 
2654         {
2655             auto sysTime = SysTime(Date(-1999, 2, 28));
2656             sysTime.add!"years"(-1, AllowDayOverflow.no);
2657             assert(sysTime == SysTime(Date(-2000, 2, 28)));
2658         }
2659 
2660         {
2661             auto sysTime = SysTime(Date(-2000, 2, 29));
2662             sysTime.add!"years"(1, AllowDayOverflow.no);
2663             assert(sysTime == SysTime(Date(-1999, 2, 28)));
2664         }
2665 
2666         {
2667             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234));
2668             sysTime.add!"years"(-7, AllowDayOverflow.no);
2669             assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234)));
2670             sysTime.add!"years"(9, AllowDayOverflow.no);
2671             assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234)));
2672         }
2673 
2674         {
2675             auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3));
2676             sysTime.add!"years"(-1, AllowDayOverflow.no);
2677             assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3)));
2678         }
2679 
2680         {
2681             auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3));
2682             sysTime.add!"years"(1, AllowDayOverflow.no);
2683             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3)));
2684         }
2685 
2686         // Test Both
2687         {
2688             auto sysTime = SysTime(Date(4, 7, 6));
2689             sysTime.add!"years"(-5, AllowDayOverflow.no);
2690             assert(sysTime == SysTime(Date(-1, 7, 6)));
2691             sysTime.add!"years"(5, AllowDayOverflow.no);
2692             assert(sysTime == SysTime(Date(4, 7, 6)));
2693         }
2694 
2695         {
2696             auto sysTime = SysTime(Date(-4, 7, 6));
2697             sysTime.add!"years"(5, AllowDayOverflow.no);
2698             assert(sysTime == SysTime(Date(1, 7, 6)));
2699             sysTime.add!"years"(-5, AllowDayOverflow.no);
2700             assert(sysTime == SysTime(Date(-4, 7, 6)));
2701         }
2702 
2703         {
2704             auto sysTime = SysTime(Date(4, 7, 6));
2705             sysTime.add!"years"(-8, AllowDayOverflow.no);
2706             assert(sysTime == SysTime(Date(-4, 7, 6)));
2707             sysTime.add!"years"(8, AllowDayOverflow.no);
2708             assert(sysTime == SysTime(Date(4, 7, 6)));
2709         }
2710 
2711         {
2712             auto sysTime = SysTime(Date(-4, 7, 6));
2713             sysTime.add!"years"(8, AllowDayOverflow.no);
2714             assert(sysTime == SysTime(Date(4, 7, 6)));
2715             sysTime.add!"years"(-8, AllowDayOverflow.no);
2716             assert(sysTime == SysTime(Date(-4, 7, 6)));
2717         }
2718 
2719         {
2720             auto sysTime = SysTime(Date(-4, 2, 29));
2721             sysTime.add!"years"(5, AllowDayOverflow.no);
2722             assert(sysTime == SysTime(Date(1, 2, 28)));
2723         }
2724 
2725         {
2726             auto sysTime = SysTime(Date(4, 2, 29));
2727             sysTime.add!"years"(-5, AllowDayOverflow.no);
2728             assert(sysTime == SysTime(Date(-1, 2, 28)));
2729         }
2730 
2731         {
2732             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
2733             sysTime.add!"years"(-1, AllowDayOverflow.no);
2734             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2735             sysTime.add!"years"(1, AllowDayOverflow.no);
2736             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2737         }
2738 
2739         {
2740             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2741             sysTime.add!"years"(-1, AllowDayOverflow.no);
2742             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2743             sysTime.add!"years"(1, AllowDayOverflow.no);
2744             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2745         }
2746 
2747         {
2748             auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0));
2749             sysTime.add!"years"(1, AllowDayOverflow.no);
2750             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2751             sysTime.add!"years"(-1, AllowDayOverflow.no);
2752             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2753         }
2754 
2755         {
2756             auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2757             sysTime.add!"years"(1, AllowDayOverflow.no);
2758             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2759             sysTime.add!"years"(-1, AllowDayOverflow.no);
2760             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2761         }
2762 
2763         {
2764             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
2765             sysTime.add!"years"(-5);
2766             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
2767             sysTime.add!"years"(5);
2768             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
2769         }
2770 
2771         {
2772             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
2773             sysTime.add!"years"(-5, AllowDayOverflow.no);
2774             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
2775             sysTime.add!"years"(5, AllowDayOverflow.no);
2776             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
2777         }
2778 
2779         {
2780             auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329));
2781             sysTime.add!"years"(5, AllowDayOverflow.no);
2782             assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329)));
2783             sysTime.add!"years"(-5, AllowDayOverflow.no);
2784             assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)));
2785         }
2786 
2787         {
2788             auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555));
2789             sysTime.add!"years"(5, AllowDayOverflow.no);
2790             assert(sysTime == SysTime(DateTime(1, 2, 28, 5, 5, 5), msecs(555)));
2791         }
2792 
2793         {
2794             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
2795             sysTime.add!"years"(-5, AllowDayOverflow.no);
2796             assert(sysTime == SysTime(DateTime(-1, 2, 28, 5, 5, 5), msecs(555)));
2797         }
2798 
2799         {
2800             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
2801             sysTime.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no);
2802             assert(sysTime == SysTime(DateTime(6, 2, 28, 5, 5, 5), msecs(555)));
2803         }
2804     }
2805 
2806     // Test add!"months"() with AllowDayOverflow.yes
2807     @safe unittest
2808     {
2809         // Test A.D.
2810         {
2811             auto sysTime = SysTime(Date(1999, 7, 6));
2812             sysTime.add!"months"(3);
2813             assert(sysTime == SysTime(Date(1999, 10, 6)));
2814             sysTime.add!"months"(-4);
2815             assert(sysTime == SysTime(Date(1999, 6, 6)));
2816         }
2817 
2818         {
2819             auto sysTime = SysTime(Date(1999, 7, 6));
2820             sysTime.add!"months"(6);
2821             assert(sysTime == SysTime(Date(2000, 1, 6)));
2822             sysTime.add!"months"(-6);
2823             assert(sysTime == SysTime(Date(1999, 7, 6)));
2824         }
2825 
2826         {
2827             auto sysTime = SysTime(Date(1999, 7, 6));
2828             sysTime.add!"months"(27);
2829             assert(sysTime == SysTime(Date(2001, 10, 6)));
2830             sysTime.add!"months"(-28);
2831             assert(sysTime == SysTime(Date(1999, 6, 6)));
2832         }
2833 
2834         {
2835             auto sysTime = SysTime(Date(1999, 5, 31));
2836             sysTime.add!"months"(1);
2837             assert(sysTime == SysTime(Date(1999, 7, 1)));
2838         }
2839 
2840         {
2841             auto sysTime = SysTime(Date(1999, 5, 31));
2842             sysTime.add!"months"(-1);
2843             assert(sysTime == SysTime(Date(1999, 5, 1)));
2844         }
2845 
2846         {
2847             auto sysTime = SysTime(Date(1999, 2, 28));
2848             sysTime.add!"months"(12);
2849             assert(sysTime == SysTime(Date(2000, 2, 28)));
2850         }
2851 
2852         {
2853             auto sysTime = SysTime(Date(2000, 2, 29));
2854             sysTime.add!"months"(12);
2855             assert(sysTime == SysTime(Date(2001, 3, 1)));
2856         }
2857 
2858         {
2859             auto sysTime = SysTime(Date(1999, 7, 31));
2860             sysTime.add!"months"(1);
2861             assert(sysTime == SysTime(Date(1999, 8, 31)));
2862             sysTime.add!"months"(1);
2863             assert(sysTime == SysTime(Date(1999, 10, 1)));
2864         }
2865 
2866         {
2867             auto sysTime = SysTime(Date(1998, 8, 31));
2868             sysTime.add!"months"(13);
2869             assert(sysTime == SysTime(Date(1999, 10, 1)));
2870             sysTime.add!"months"(-13);
2871             assert(sysTime == SysTime(Date(1998, 9, 1)));
2872         }
2873 
2874         {
2875             auto sysTime = SysTime(Date(1997, 12, 31));
2876             sysTime.add!"months"(13);
2877             assert(sysTime == SysTime(Date(1999, 1, 31)));
2878             sysTime.add!"months"(-13);
2879             assert(sysTime == SysTime(Date(1997, 12, 31)));
2880         }
2881 
2882         {
2883             auto sysTime = SysTime(Date(1997, 12, 31));
2884             sysTime.add!"months"(14);
2885             assert(sysTime == SysTime(Date(1999, 3, 3)));
2886             sysTime.add!"months"(-14);
2887             assert(sysTime == SysTime(Date(1998, 1, 3)));
2888         }
2889 
2890         {
2891             auto sysTime = SysTime(Date(1998, 12, 31));
2892             sysTime.add!"months"(14);
2893             assert(sysTime == SysTime(Date(2000, 3, 2)));
2894             sysTime.add!"months"(-14);
2895             assert(sysTime == SysTime(Date(1999, 1, 2)));
2896         }
2897 
2898         {
2899             auto sysTime = SysTime(Date(1999, 12, 31));
2900             sysTime.add!"months"(14);
2901             assert(sysTime == SysTime(Date(2001, 3, 3)));
2902             sysTime.add!"months"(-14);
2903             assert(sysTime == SysTime(Date(2000, 1, 3)));
2904         }
2905 
2906         {
2907             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
2908             sysTime.add!"months"(3);
2909             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
2910             sysTime.add!"months"(-4);
2911             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
2912         }
2913 
2914         {
2915             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
2916             sysTime.add!"months"(14);
2917             assert(sysTime == SysTime(DateTime(2000, 3, 2, 7, 7, 7), hnsecs(422202)));
2918             sysTime.add!"months"(-14);
2919             assert(sysTime == SysTime(DateTime(1999, 1, 2, 7, 7, 7), hnsecs(422202)));
2920         }
2921 
2922         {
2923             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
2924             sysTime.add!"months"(14);
2925             assert(sysTime == SysTime(DateTime(2001, 3, 3, 7, 7, 7), hnsecs(422202)));
2926             sysTime.add!"months"(-14);
2927             assert(sysTime == SysTime(DateTime(2000, 1, 3, 7, 7, 7), hnsecs(422202)));
2928         }
2929 
2930         // Test B.C.
2931         {
2932             auto sysTime = SysTime(Date(-1999, 7, 6));
2933             sysTime.add!"months"(3);
2934             assert(sysTime == SysTime(Date(-1999, 10, 6)));
2935             sysTime.add!"months"(-4);
2936             assert(sysTime == SysTime(Date(-1999, 6, 6)));
2937         }
2938 
2939         {
2940             auto sysTime = SysTime(Date(-1999, 7, 6));
2941             sysTime.add!"months"(6);
2942             assert(sysTime == SysTime(Date(-1998, 1, 6)));
2943             sysTime.add!"months"(-6);
2944             assert(sysTime == SysTime(Date(-1999, 7, 6)));
2945         }
2946 
2947         {
2948             auto sysTime = SysTime(Date(-1999, 7, 6));
2949             sysTime.add!"months"(-27);
2950             assert(sysTime == SysTime(Date(-2001, 4, 6)));
2951             sysTime.add!"months"(28);
2952             assert(sysTime == SysTime(Date(-1999, 8, 6)));
2953         }
2954 
2955         {
2956             auto sysTime = SysTime(Date(-1999, 5, 31));
2957             sysTime.add!"months"(1);
2958             assert(sysTime == SysTime(Date(-1999, 7, 1)));
2959         }
2960 
2961         {
2962             auto sysTime = SysTime(Date(-1999, 5, 31));
2963             sysTime.add!"months"(-1);
2964             assert(sysTime == SysTime(Date(-1999, 5, 1)));
2965         }
2966 
2967         {
2968             auto sysTime = SysTime(Date(-1999, 2, 28));
2969             sysTime.add!"months"(-12);
2970             assert(sysTime == SysTime(Date(-2000, 2, 28)));
2971         }
2972 
2973         {
2974             auto sysTime = SysTime(Date(-2000, 2, 29));
2975             sysTime.add!"months"(-12);
2976             assert(sysTime == SysTime(Date(-2001, 3, 1)));
2977         }
2978 
2979         {
2980             auto sysTime = SysTime(Date(-1999, 7, 31));
2981             sysTime.add!"months"(1);
2982             assert(sysTime == SysTime(Date(-1999, 8, 31)));
2983             sysTime.add!"months"(1);
2984             assert(sysTime == SysTime(Date(-1999, 10, 1)));
2985         }
2986 
2987         {
2988             auto sysTime = SysTime(Date(-1998, 8, 31));
2989             sysTime.add!"months"(13);
2990             assert(sysTime == SysTime(Date(-1997, 10, 1)));
2991             sysTime.add!"months"(-13);
2992             assert(sysTime == SysTime(Date(-1998, 9, 1)));
2993         }
2994 
2995         {
2996             auto sysTime = SysTime(Date(-1997, 12, 31));
2997             sysTime.add!"months"(13);
2998             assert(sysTime == SysTime(Date(-1995, 1, 31)));
2999             sysTime.add!"months"(-13);
3000             assert(sysTime == SysTime(Date(-1997, 12, 31)));
3001         }
3002 
3003         {
3004             auto sysTime = SysTime(Date(-1997, 12, 31));
3005             sysTime.add!"months"(14);
3006             assert(sysTime == SysTime(Date(-1995, 3, 3)));
3007             sysTime.add!"months"(-14);
3008             assert(sysTime == SysTime(Date(-1996, 1, 3)));
3009         }
3010 
3011         {
3012             auto sysTime = SysTime(Date(-2002, 12, 31));
3013             sysTime.add!"months"(14);
3014             assert(sysTime == SysTime(Date(-2000, 3, 2)));
3015             sysTime.add!"months"(-14);
3016             assert(sysTime == SysTime(Date(-2001, 1, 2)));
3017         }
3018 
3019         {
3020             auto sysTime = SysTime(Date(-2001, 12, 31));
3021             sysTime.add!"months"(14);
3022             assert(sysTime == SysTime(Date(-1999, 3, 3)));
3023             sysTime.add!"months"(-14);
3024             assert(sysTime == SysTime(Date(-2000, 1, 3)));
3025         }
3026 
3027         {
3028             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
3029             sysTime.add!"months"(3);
3030             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
3031             sysTime.add!"months"(-4);
3032             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
3033         }
3034 
3035         {
3036             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
3037             sysTime.add!"months"(14);
3038             assert(sysTime == SysTime(DateTime(-2000, 3, 2, 7, 7, 7), hnsecs(422202)));
3039             sysTime.add!"months"(-14);
3040             assert(sysTime == SysTime(DateTime(-2001, 1, 2, 7, 7, 7), hnsecs(422202)));
3041         }
3042 
3043         {
3044             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
3045             sysTime.add!"months"(14);
3046             assert(sysTime == SysTime(DateTime(-1999, 3, 3, 7, 7, 7), hnsecs(422202)));
3047             sysTime.add!"months"(-14);
3048             assert(sysTime == SysTime(DateTime(-2000, 1, 3, 7, 7, 7), hnsecs(422202)));
3049         }
3050 
3051         // Test Both
3052         {
3053             auto sysTime = SysTime(Date(1, 1, 1));
3054             sysTime.add!"months"(-1);
3055             assert(sysTime == SysTime(Date(0, 12, 1)));
3056             sysTime.add!"months"(1);
3057             assert(sysTime == SysTime(Date(1, 1, 1)));
3058         }
3059 
3060         {
3061             auto sysTime = SysTime(Date(4, 1, 1));
3062             sysTime.add!"months"(-48);
3063             assert(sysTime == SysTime(Date(0, 1, 1)));
3064             sysTime.add!"months"(48);
3065             assert(sysTime == SysTime(Date(4, 1, 1)));
3066         }
3067 
3068         {
3069             auto sysTime = SysTime(Date(4, 3, 31));
3070             sysTime.add!"months"(-49);
3071             assert(sysTime == SysTime(Date(0, 3, 2)));
3072             sysTime.add!"months"(49);
3073             assert(sysTime == SysTime(Date(4, 4, 2)));
3074         }
3075 
3076         {
3077             auto sysTime = SysTime(Date(4, 3, 31));
3078             sysTime.add!"months"(-85);
3079             assert(sysTime == SysTime(Date(-3, 3, 3)));
3080             sysTime.add!"months"(85);
3081             assert(sysTime == SysTime(Date(4, 4, 3)));
3082         }
3083 
3084         {
3085             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3086             sysTime.add!"months"(-1);
3087             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3088             sysTime.add!"months"(1);
3089             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3090         }
3091 
3092         {
3093             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3094             sysTime.add!"months"(-1);
3095             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3096             sysTime.add!"months"(1);
3097             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3098         }
3099 
3100         {
3101             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
3102             sysTime.add!"months"(1);
3103             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3104             sysTime.add!"months"(-1);
3105             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3106         }
3107 
3108         {
3109             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
3110             sysTime.add!"months"(1);
3111             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3112             sysTime.add!"months"(-1);
3113             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3114         }
3115 
3116         {
3117             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
3118             sysTime.add!"months"(-1);
3119             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17)));
3120             sysTime.add!"months"(1);
3121             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
3122         }
3123 
3124         {
3125             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
3126             sysTime.add!"months"(-85);
3127             assert(sysTime == SysTime(DateTime(-3, 3, 3, 12, 11, 10), msecs(9)));
3128             sysTime.add!"months"(85);
3129             assert(sysTime == SysTime(DateTime(4, 4, 3, 12, 11, 10), msecs(9)));
3130         }
3131 
3132         {
3133             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3134             sysTime.add!"months"(85);
3135             assert(sysTime == SysTime(DateTime(4, 5, 1, 12, 11, 10), msecs(9)));
3136             sysTime.add!"months"(-85);
3137             assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9)));
3138         }
3139 
3140         {
3141             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3142             sysTime.add!"months"(85).add!"months"(-83);
3143             assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), msecs(9)));
3144         }
3145 
3146         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3147         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3148         static assert(!__traits(compiles, cst.add!"months"(4)));
3149         //static assert(!__traits(compiles, ist.add!"months"(4)));
3150     }
3151 
3152     // Test add!"months"() with AllowDayOverflow.no
3153     @safe unittest
3154     {
3155         // Test A.D.
3156         {
3157             auto sysTime = SysTime(Date(1999, 7, 6));
3158             sysTime.add!"months"(3, AllowDayOverflow.no);
3159             assert(sysTime == SysTime(Date(1999, 10, 6)));
3160             sysTime.add!"months"(-4, AllowDayOverflow.no);
3161             assert(sysTime == SysTime(Date(1999, 6, 6)));
3162         }
3163 
3164         {
3165             auto sysTime = SysTime(Date(1999, 7, 6));
3166             sysTime.add!"months"(6, AllowDayOverflow.no);
3167             assert(sysTime == SysTime(Date(2000, 1, 6)));
3168             sysTime.add!"months"(-6, AllowDayOverflow.no);
3169             assert(sysTime == SysTime(Date(1999, 7, 6)));
3170         }
3171 
3172         {
3173             auto sysTime = SysTime(Date(1999, 7, 6));
3174             sysTime.add!"months"(27, AllowDayOverflow.no);
3175             assert(sysTime == SysTime(Date(2001, 10, 6)));
3176             sysTime.add!"months"(-28, AllowDayOverflow.no);
3177             assert(sysTime == SysTime(Date(1999, 6, 6)));
3178         }
3179 
3180         {
3181             auto sysTime = SysTime(Date(1999, 5, 31));
3182             sysTime.add!"months"(1, AllowDayOverflow.no);
3183             assert(sysTime == SysTime(Date(1999, 6, 30)));
3184         }
3185 
3186         {
3187             auto sysTime = SysTime(Date(1999, 5, 31));
3188             sysTime.add!"months"(-1, AllowDayOverflow.no);
3189             assert(sysTime == SysTime(Date(1999, 4, 30)));
3190         }
3191 
3192         {
3193             auto sysTime = SysTime(Date(1999, 2, 28));
3194             sysTime.add!"months"(12, AllowDayOverflow.no);
3195             assert(sysTime == SysTime(Date(2000, 2, 28)));
3196         }
3197 
3198         {
3199             auto sysTime = SysTime(Date(2000, 2, 29));
3200             sysTime.add!"months"(12, AllowDayOverflow.no);
3201             assert(sysTime == SysTime(Date(2001, 2, 28)));
3202         }
3203 
3204         {
3205             auto sysTime = SysTime(Date(1999, 7, 31));
3206             sysTime.add!"months"(1, AllowDayOverflow.no);
3207             assert(sysTime == SysTime(Date(1999, 8, 31)));
3208             sysTime.add!"months"(1, AllowDayOverflow.no);
3209             assert(sysTime == SysTime(Date(1999, 9, 30)));
3210         }
3211 
3212         {
3213             auto sysTime = SysTime(Date(1998, 8, 31));
3214             sysTime.add!"months"(13, AllowDayOverflow.no);
3215             assert(sysTime == SysTime(Date(1999, 9, 30)));
3216             sysTime.add!"months"(-13, AllowDayOverflow.no);
3217             assert(sysTime == SysTime(Date(1998, 8, 30)));
3218         }
3219 
3220         {
3221             auto sysTime = SysTime(Date(1997, 12, 31));
3222             sysTime.add!"months"(13, AllowDayOverflow.no);
3223             assert(sysTime == SysTime(Date(1999, 1, 31)));
3224             sysTime.add!"months"(-13, AllowDayOverflow.no);
3225             assert(sysTime == SysTime(Date(1997, 12, 31)));
3226         }
3227 
3228         {
3229             auto sysTime = SysTime(Date(1997, 12, 31));
3230             sysTime.add!"months"(14, AllowDayOverflow.no);
3231             assert(sysTime == SysTime(Date(1999, 2, 28)));
3232             sysTime.add!"months"(-14, AllowDayOverflow.no);
3233             assert(sysTime == SysTime(Date(1997, 12, 28)));
3234         }
3235 
3236         {
3237             auto sysTime = SysTime(Date(1998, 12, 31));
3238             sysTime.add!"months"(14, AllowDayOverflow.no);
3239             assert(sysTime == SysTime(Date(2000, 2, 29)));
3240             sysTime.add!"months"(-14, AllowDayOverflow.no);
3241             assert(sysTime == SysTime(Date(1998, 12, 29)));
3242         }
3243 
3244         {
3245             auto sysTime = SysTime(Date(1999, 12, 31));
3246             sysTime.add!"months"(14, AllowDayOverflow.no);
3247             assert(sysTime == SysTime(Date(2001, 2, 28)));
3248             sysTime.add!"months"(-14, AllowDayOverflow.no);
3249             assert(sysTime == SysTime(Date(1999, 12, 28)));
3250         }
3251 
3252         {
3253             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
3254             sysTime.add!"months"(3, AllowDayOverflow.no);
3255             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
3256             sysTime.add!"months"(-4, AllowDayOverflow.no);
3257             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
3258         }
3259 
3260         {
3261             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
3262             sysTime.add!"months"(14, AllowDayOverflow.no);
3263             assert(sysTime == SysTime(DateTime(2000, 2, 29, 7, 7, 7), hnsecs(422202)));
3264             sysTime.add!"months"(-14, AllowDayOverflow.no);
3265             assert(sysTime == SysTime(DateTime(1998, 12, 29, 7, 7, 7), hnsecs(422202)));
3266         }
3267 
3268         {
3269             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
3270             sysTime.add!"months"(14, AllowDayOverflow.no);
3271             assert(sysTime == SysTime(DateTime(2001, 2, 28, 7, 7, 7), hnsecs(422202)));
3272             sysTime.add!"months"(-14, AllowDayOverflow.no);
3273             assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202)));
3274         }
3275 
3276         // Test B.C.
3277         {
3278             auto sysTime = SysTime(Date(-1999, 7, 6));
3279             sysTime.add!"months"(3, AllowDayOverflow.no);
3280             assert(sysTime == SysTime(Date(-1999, 10, 6)));
3281             sysTime.add!"months"(-4, AllowDayOverflow.no);
3282             assert(sysTime == SysTime(Date(-1999, 6, 6)));
3283         }
3284 
3285         {
3286             auto sysTime = SysTime(Date(-1999, 7, 6));
3287             sysTime.add!"months"(6, AllowDayOverflow.no);
3288             assert(sysTime == SysTime(Date(-1998, 1, 6)));
3289             sysTime.add!"months"(-6, AllowDayOverflow.no);
3290             assert(sysTime == SysTime(Date(-1999, 7, 6)));
3291         }
3292 
3293         {
3294             auto sysTime = SysTime(Date(-1999, 7, 6));
3295             sysTime.add!"months"(-27, AllowDayOverflow.no);
3296             assert(sysTime == SysTime(Date(-2001, 4, 6)));
3297             sysTime.add!"months"(28, AllowDayOverflow.no);
3298             assert(sysTime == SysTime(Date(-1999, 8, 6)));
3299         }
3300 
3301         {
3302             auto sysTime = SysTime(Date(-1999, 5, 31));
3303             sysTime.add!"months"(1, AllowDayOverflow.no);
3304             assert(sysTime == SysTime(Date(-1999, 6, 30)));
3305         }
3306 
3307         {
3308             auto sysTime = SysTime(Date(-1999, 5, 31));
3309             sysTime.add!"months"(-1, AllowDayOverflow.no);
3310             assert(sysTime == SysTime(Date(-1999, 4, 30)));
3311         }
3312 
3313         {
3314             auto sysTime = SysTime(Date(-1999, 2, 28));
3315             sysTime.add!"months"(-12, AllowDayOverflow.no);
3316             assert(sysTime == SysTime(Date(-2000, 2, 28)));
3317         }
3318 
3319         {
3320             auto sysTime = SysTime(Date(-2000, 2, 29));
3321             sysTime.add!"months"(-12, AllowDayOverflow.no);
3322             assert(sysTime == SysTime(Date(-2001, 2, 28)));
3323         }
3324 
3325         {
3326             auto sysTime = SysTime(Date(-1999, 7, 31));
3327             sysTime.add!"months"(1, AllowDayOverflow.no);
3328             assert(sysTime == SysTime(Date(-1999, 8, 31)));
3329             sysTime.add!"months"(1, AllowDayOverflow.no);
3330             assert(sysTime == SysTime(Date(-1999, 9, 30)));
3331         }
3332 
3333         {
3334             auto sysTime = SysTime(Date(-1998, 8, 31));
3335             sysTime.add!"months"(13, AllowDayOverflow.no);
3336             assert(sysTime == SysTime(Date(-1997, 9, 30)));
3337             sysTime.add!"months"(-13, AllowDayOverflow.no);
3338             assert(sysTime == SysTime(Date(-1998, 8, 30)));
3339         }
3340 
3341         {
3342             auto sysTime = SysTime(Date(-1997, 12, 31));
3343             sysTime.add!"months"(13, AllowDayOverflow.no);
3344             assert(sysTime == SysTime(Date(-1995, 1, 31)));
3345             sysTime.add!"months"(-13, AllowDayOverflow.no);
3346             assert(sysTime == SysTime(Date(-1997, 12, 31)));
3347         }
3348 
3349         {
3350             auto sysTime = SysTime(Date(-1997, 12, 31));
3351             sysTime.add!"months"(14, AllowDayOverflow.no);
3352             assert(sysTime == SysTime(Date(-1995, 2, 28)));
3353             sysTime.add!"months"(-14, AllowDayOverflow.no);
3354             assert(sysTime == SysTime(Date(-1997, 12, 28)));
3355         }
3356 
3357         {
3358             auto sysTime = SysTime(Date(-2002, 12, 31));
3359             sysTime.add!"months"(14, AllowDayOverflow.no);
3360             assert(sysTime == SysTime(Date(-2000, 2, 29)));
3361             sysTime.add!"months"(-14, AllowDayOverflow.no);
3362             assert(sysTime == SysTime(Date(-2002, 12, 29)));
3363         }
3364 
3365         {
3366             auto sysTime = SysTime(Date(-2001, 12, 31));
3367             sysTime.add!"months"(14, AllowDayOverflow.no);
3368             assert(sysTime == SysTime(Date(-1999, 2, 28)));
3369             sysTime.add!"months"(-14, AllowDayOverflow.no);
3370             assert(sysTime == SysTime(Date(-2001, 12, 28)));
3371         }
3372 
3373         {
3374             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
3375             sysTime.add!"months"(3, AllowDayOverflow.no);
3376             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
3377             sysTime.add!"months"(-4, AllowDayOverflow.no);
3378             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
3379         }
3380 
3381         {
3382             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
3383             sysTime.add!"months"(14, AllowDayOverflow.no);
3384             assert(sysTime == SysTime(DateTime(-2000, 2, 29, 7, 7, 7), hnsecs(422202)));
3385             sysTime.add!"months"(-14, AllowDayOverflow.no);
3386             assert(sysTime == SysTime(DateTime(-2002, 12, 29, 7, 7, 7), hnsecs(422202)));
3387         }
3388 
3389         {
3390             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
3391             sysTime.add!"months"(14, AllowDayOverflow.no);
3392             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 7, 7), hnsecs(422202)));
3393             sysTime.add!"months"(-14, AllowDayOverflow.no);
3394             assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202)));
3395         }
3396 
3397         // Test Both
3398         {
3399             auto sysTime = SysTime(Date(1, 1, 1));
3400             sysTime.add!"months"(-1, AllowDayOverflow.no);
3401             assert(sysTime == SysTime(Date(0, 12, 1)));
3402             sysTime.add!"months"(1, AllowDayOverflow.no);
3403             assert(sysTime == SysTime(Date(1, 1, 1)));
3404         }
3405 
3406         {
3407             auto sysTime = SysTime(Date(4, 1, 1));
3408             sysTime.add!"months"(-48, AllowDayOverflow.no);
3409             assert(sysTime == SysTime(Date(0, 1, 1)));
3410             sysTime.add!"months"(48, AllowDayOverflow.no);
3411             assert(sysTime == SysTime(Date(4, 1, 1)));
3412         }
3413 
3414         {
3415             auto sysTime = SysTime(Date(4, 3, 31));
3416             sysTime.add!"months"(-49, AllowDayOverflow.no);
3417             assert(sysTime == SysTime(Date(0, 2, 29)));
3418             sysTime.add!"months"(49, AllowDayOverflow.no);
3419             assert(sysTime == SysTime(Date(4, 3, 29)));
3420         }
3421 
3422         {
3423             auto sysTime = SysTime(Date(4, 3, 31));
3424             sysTime.add!"months"(-85, AllowDayOverflow.no);
3425             assert(sysTime == SysTime(Date(-3, 2, 28)));
3426             sysTime.add!"months"(85, AllowDayOverflow.no);
3427             assert(sysTime == SysTime(Date(4, 3, 28)));
3428         }
3429 
3430         {
3431             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3432             sysTime.add!"months"(-1, AllowDayOverflow.no);
3433             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3434             sysTime.add!"months"(1, AllowDayOverflow.no);
3435             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3436         }
3437 
3438         {
3439             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3440             sysTime.add!"months"(-1, AllowDayOverflow.no);
3441             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3442             sysTime.add!"months"(1, AllowDayOverflow.no);
3443             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3444         }
3445 
3446         {
3447             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
3448             sysTime.add!"months"(1, AllowDayOverflow.no);
3449             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3450             sysTime.add!"months"(-1, AllowDayOverflow.no);
3451             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3452         }
3453 
3454         {
3455             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
3456             sysTime.add!"months"(1, AllowDayOverflow.no);
3457             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3458             sysTime.add!"months"(-1, AllowDayOverflow.no);
3459             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3460         }
3461 
3462         {
3463             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
3464             sysTime.add!"months"(-1, AllowDayOverflow.no);
3465             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17)));
3466             sysTime.add!"months"(1, AllowDayOverflow.no);
3467             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
3468         }
3469 
3470         {
3471             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
3472             sysTime.add!"months"(-85, AllowDayOverflow.no);
3473             assert(sysTime == SysTime(DateTime(-3, 2, 28, 12, 11, 10), msecs(9)));
3474             sysTime.add!"months"(85, AllowDayOverflow.no);
3475             assert(sysTime == SysTime(DateTime(4, 3, 28, 12, 11, 10), msecs(9)));
3476         }
3477 
3478         {
3479             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3480             sysTime.add!"months"(85, AllowDayOverflow.no);
3481             assert(sysTime == SysTime(DateTime(4, 4, 30, 12, 11, 10), msecs(9)));
3482             sysTime.add!"months"(-85, AllowDayOverflow.no);
3483             assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9)));
3484         }
3485 
3486         {
3487             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3488             sysTime.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no);
3489             assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9)));
3490         }
3491     }
3492 
3493 
3494     /++
3495         Adds the given number of years or months to this $(LREF SysTime). A
3496         negative number will subtract.
3497 
3498         The difference between rolling and adding is that rolling does not
3499         affect larger units. Rolling a $(LREF SysTime) 12 months
3500         gets the exact same $(LREF SysTime). However, the days can still be
3501         affected due to the differing number of days in each month.
3502 
3503         Because there are no units larger than years, there is no difference
3504         between adding and rolling years.
3505 
3506         Params:
3507             units         = The type of units to add ("years" or "months").
3508             value         = The number of months or years to add to this
3509                             $(LREF SysTime).
3510             allowOverflow = Whether the days should be allowed to overflow,
3511                             causing the month to increment.
3512       +/
3513     ref SysTime roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow
3514         if (units == "years")
3515     {
3516         return add!"years"(value, allowOverflow);
3517     }
3518 
3519     ///
3520     @safe unittest
3521     {
3522         import std.datetime.date : AllowDayOverflow, DateTime;
3523 
3524         auto st1 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
3525         st1.roll!"months"(1);
3526         assert(st1 == SysTime(DateTime(2010, 2, 1, 12, 33, 33)));
3527 
3528         auto st2 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
3529         st2.roll!"months"(-1);
3530         assert(st2 == SysTime(DateTime(2010, 12, 1, 12, 33, 33)));
3531 
3532         auto st3 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
3533         st3.roll!"months"(1);
3534         assert(st3 == SysTime(DateTime(1999, 3, 1, 12, 33, 33)));
3535 
3536         auto st4 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
3537         st4.roll!"months"(1, AllowDayOverflow.no);
3538         assert(st4 == SysTime(DateTime(1999, 2, 28, 12, 33, 33)));
3539 
3540         auto st5 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
3541         st5.roll!"years"(1);
3542         assert(st5 == SysTime(DateTime(2001, 3, 1, 12, 30, 33)));
3543 
3544         auto st6 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
3545         st6.roll!"years"(1, AllowDayOverflow.no);
3546         assert(st6 == SysTime(DateTime(2001, 2, 28, 12, 30, 33)));
3547     }
3548 
3549     @safe unittest
3550     {
3551         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3552         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3553         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3554         st.roll!"years"(4);
3555         static assert(!__traits(compiles, cst.roll!"years"(4)));
3556         //static assert(!__traits(compiles, ist.roll!"years"(4)));
3557     }
3558 
3559 
3560     // Shares documentation with "years" overload.
3561     ref SysTime roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow
3562         if (units == "months")
3563     {
3564         auto hnsecs = adjTime;
3565         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
3566 
3567         if (hnsecs < 0)
3568         {
3569             hnsecs += convert!("hours", "hnsecs")(24);
3570             --days;
3571         }
3572 
3573         auto date = Date(cast(int) days);
3574         date.roll!"months"(value, allowOverflow);
3575         days = date.dayOfGregorianCal - 1;
3576 
3577         if (days < 0)
3578         {
3579             hnsecs -= convert!("hours", "hnsecs")(24);
3580             ++days;
3581         }
3582 
3583         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
3584         adjTime = newDaysHNSecs + hnsecs;
3585         return this;
3586     }
3587 
3588     // Test roll!"months"() with AllowDayOverflow.yes
3589     @safe unittest
3590     {
3591         // Test A.D.
3592         {
3593             auto sysTime = SysTime(Date(1999, 7, 6));
3594             sysTime.roll!"months"(3);
3595             assert(sysTime == SysTime(Date(1999, 10, 6)));
3596             sysTime.roll!"months"(-4);
3597             assert(sysTime == SysTime(Date(1999, 6, 6)));
3598         }
3599 
3600         {
3601             auto sysTime = SysTime(Date(1999, 7, 6));
3602             sysTime.roll!"months"(6);
3603             assert(sysTime == SysTime(Date(1999, 1, 6)));
3604             sysTime.roll!"months"(-6);
3605             assert(sysTime == SysTime(Date(1999, 7, 6)));
3606         }
3607 
3608         {
3609             auto sysTime = SysTime(Date(1999, 7, 6));
3610             sysTime.roll!"months"(27);
3611             assert(sysTime == SysTime(Date(1999, 10, 6)));
3612             sysTime.roll!"months"(-28);
3613             assert(sysTime == SysTime(Date(1999, 6, 6)));
3614         }
3615 
3616         {
3617             auto sysTime = SysTime(Date(1999, 5, 31));
3618             sysTime.roll!"months"(1);
3619             assert(sysTime == SysTime(Date(1999, 7, 1)));
3620         }
3621 
3622         {
3623             auto sysTime = SysTime(Date(1999, 5, 31));
3624             sysTime.roll!"months"(-1);
3625             assert(sysTime == SysTime(Date(1999, 5, 1)));
3626         }
3627 
3628         {
3629             auto sysTime = SysTime(Date(1999, 2, 28));
3630             sysTime.roll!"months"(12);
3631             assert(sysTime == SysTime(Date(1999, 2, 28)));
3632         }
3633 
3634         {
3635             auto sysTime = SysTime(Date(2000, 2, 29));
3636             sysTime.roll!"months"(12);
3637             assert(sysTime == SysTime(Date(2000, 2, 29)));
3638         }
3639 
3640         {
3641             auto sysTime = SysTime(Date(1999, 7, 31));
3642             sysTime.roll!"months"(1);
3643             assert(sysTime == SysTime(Date(1999, 8, 31)));
3644             sysTime.roll!"months"(1);
3645             assert(sysTime == SysTime(Date(1999, 10, 1)));
3646         }
3647 
3648         {
3649             auto sysTime = SysTime(Date(1998, 8, 31));
3650             sysTime.roll!"months"(13);
3651             assert(sysTime == SysTime(Date(1998, 10, 1)));
3652             sysTime.roll!"months"(-13);
3653             assert(sysTime == SysTime(Date(1998, 9, 1)));
3654         }
3655 
3656         {
3657             auto sysTime = SysTime(Date(1997, 12, 31));
3658             sysTime.roll!"months"(13);
3659             assert(sysTime == SysTime(Date(1997, 1, 31)));
3660             sysTime.roll!"months"(-13);
3661             assert(sysTime == SysTime(Date(1997, 12, 31)));
3662         }
3663 
3664         {
3665             auto sysTime = SysTime(Date(1997, 12, 31));
3666             sysTime.roll!"months"(14);
3667             assert(sysTime == SysTime(Date(1997, 3, 3)));
3668             sysTime.roll!"months"(-14);
3669             assert(sysTime == SysTime(Date(1997, 1, 3)));
3670         }
3671 
3672         {
3673             auto sysTime = SysTime(Date(1998, 12, 31));
3674             sysTime.roll!"months"(14);
3675             assert(sysTime == SysTime(Date(1998, 3, 3)));
3676             sysTime.roll!"months"(-14);
3677             assert(sysTime == SysTime(Date(1998, 1, 3)));
3678         }
3679 
3680         {
3681             auto sysTime = SysTime(Date(1999, 12, 31));
3682             sysTime.roll!"months"(14);
3683             assert(sysTime == SysTime(Date(1999, 3, 3)));
3684             sysTime.roll!"months"(-14);
3685             assert(sysTime == SysTime(Date(1999, 1, 3)));
3686         }
3687 
3688         {
3689             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
3690             sysTime.roll!"months"(3);
3691             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
3692             sysTime.roll!"months"(-4);
3693             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
3694         }
3695 
3696         {
3697             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
3698             sysTime.roll!"months"(14);
3699             assert(sysTime == SysTime(DateTime(1998, 3, 3, 7, 7, 7), hnsecs(422202)));
3700             sysTime.roll!"months"(-14);
3701             assert(sysTime == SysTime(DateTime(1998, 1, 3, 7, 7, 7), hnsecs(422202)));
3702         }
3703 
3704         {
3705             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
3706             sysTime.roll!"months"(14);
3707             assert(sysTime == SysTime(DateTime(1999, 3, 3, 7, 7, 7), hnsecs(422202)));
3708             sysTime.roll!"months"(-14);
3709             assert(sysTime == SysTime(DateTime(1999, 1, 3, 7, 7, 7), hnsecs(422202)));
3710         }
3711 
3712         // Test B.C.
3713         {
3714             auto sysTime = SysTime(Date(-1999, 7, 6));
3715             sysTime.roll!"months"(3);
3716             assert(sysTime == SysTime(Date(-1999, 10, 6)));
3717             sysTime.roll!"months"(-4);
3718             assert(sysTime == SysTime(Date(-1999, 6, 6)));
3719         }
3720 
3721         {
3722             auto sysTime = SysTime(Date(-1999, 7, 6));
3723             sysTime.roll!"months"(6);
3724             assert(sysTime == SysTime(Date(-1999, 1, 6)));
3725             sysTime.roll!"months"(-6);
3726             assert(sysTime == SysTime(Date(-1999, 7, 6)));
3727         }
3728 
3729         {
3730             auto sysTime = SysTime(Date(-1999, 7, 6));
3731             sysTime.roll!"months"(-27);
3732             assert(sysTime == SysTime(Date(-1999, 4, 6)));
3733             sysTime.roll!"months"(28);
3734             assert(sysTime == SysTime(Date(-1999, 8, 6)));
3735         }
3736 
3737         {
3738             auto sysTime = SysTime(Date(-1999, 5, 31));
3739             sysTime.roll!"months"(1);
3740             assert(sysTime == SysTime(Date(-1999, 7, 1)));
3741         }
3742 
3743         {
3744             auto sysTime = SysTime(Date(-1999, 5, 31));
3745             sysTime.roll!"months"(-1);
3746             assert(sysTime == SysTime(Date(-1999, 5, 1)));
3747         }
3748 
3749         {
3750             auto sysTime = SysTime(Date(-1999, 2, 28));
3751             sysTime.roll!"months"(-12);
3752             assert(sysTime == SysTime(Date(-1999, 2, 28)));
3753         }
3754 
3755         {
3756             auto sysTime = SysTime(Date(-2000, 2, 29));
3757             sysTime.roll!"months"(-12);
3758             assert(sysTime == SysTime(Date(-2000, 2, 29)));
3759         }
3760 
3761         {
3762             auto sysTime = SysTime(Date(-1999, 7, 31));
3763             sysTime.roll!"months"(1);
3764             assert(sysTime == SysTime(Date(-1999, 8, 31)));
3765             sysTime.roll!"months"(1);
3766             assert(sysTime == SysTime(Date(-1999, 10, 1)));
3767         }
3768 
3769         {
3770             auto sysTime = SysTime(Date(-1998, 8, 31));
3771             sysTime.roll!"months"(13);
3772             assert(sysTime == SysTime(Date(-1998, 10, 1)));
3773             sysTime.roll!"months"(-13);
3774             assert(sysTime == SysTime(Date(-1998, 9, 1)));
3775         }
3776 
3777         {
3778             auto sysTime = SysTime(Date(-1997, 12, 31));
3779             sysTime.roll!"months"(13);
3780             assert(sysTime == SysTime(Date(-1997, 1, 31)));
3781             sysTime.roll!"months"(-13);
3782             assert(sysTime == SysTime(Date(-1997, 12, 31)));
3783         }
3784 
3785         {
3786             auto sysTime = SysTime(Date(-1997, 12, 31));
3787             sysTime.roll!"months"(14);
3788             assert(sysTime == SysTime(Date(-1997, 3, 3)));
3789             sysTime.roll!"months"(-14);
3790             assert(sysTime == SysTime(Date(-1997, 1, 3)));
3791         }
3792 
3793         {
3794             auto sysTime = SysTime(Date(-2002, 12, 31));
3795             sysTime.roll!"months"(14);
3796             assert(sysTime == SysTime(Date(-2002, 3, 3)));
3797             sysTime.roll!"months"(-14);
3798             assert(sysTime == SysTime(Date(-2002, 1, 3)));
3799         }
3800 
3801         {
3802             auto sysTime = SysTime(Date(-2001, 12, 31));
3803             sysTime.roll!"months"(14);
3804             assert(sysTime == SysTime(Date(-2001, 3, 3)));
3805             sysTime.roll!"months"(-14);
3806             assert(sysTime == SysTime(Date(-2001, 1, 3)));
3807         }
3808 
3809         {
3810             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3811             sysTime.roll!"months"(-1);
3812             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0)));
3813             sysTime.roll!"months"(1);
3814             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3815         }
3816 
3817         {
3818             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3819             sysTime.roll!"months"(-1);
3820             assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3821             sysTime.roll!"months"(1);
3822             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3823         }
3824 
3825         {
3826             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
3827             sysTime.roll!"months"(1);
3828             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
3829             sysTime.roll!"months"(-1);
3830             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3831         }
3832 
3833         {
3834             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
3835             sysTime.roll!"months"(1);
3836             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3837             sysTime.roll!"months"(-1);
3838             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3839         }
3840 
3841         {
3842             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), hnsecs(5007));
3843             sysTime.roll!"months"(3);
3844             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), hnsecs(5007)));
3845             sysTime.roll!"months"(-4);
3846             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), hnsecs(5007)));
3847         }
3848 
3849         {
3850             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
3851             sysTime.roll!"months"(14);
3852             assert(sysTime == SysTime(DateTime(-2002, 3, 3, 7, 7, 7), hnsecs(422202)));
3853             sysTime.roll!"months"(-14);
3854             assert(sysTime == SysTime(DateTime(-2002, 1, 3, 7, 7, 7), hnsecs(422202)));
3855         }
3856 
3857         {
3858             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
3859             sysTime.roll!"months"(14);
3860             assert(sysTime == SysTime(DateTime(-2001, 3, 3, 7, 7, 7), hnsecs(422202)));
3861             sysTime.roll!"months"(-14);
3862             assert(sysTime == SysTime(DateTime(-2001, 1, 3, 7, 7, 7), hnsecs(422202)));
3863         }
3864 
3865         // Test Both
3866         {
3867             auto sysTime = SysTime(Date(1, 1, 1));
3868             sysTime.roll!"months"(-1);
3869             assert(sysTime == SysTime(Date(1, 12, 1)));
3870             sysTime.roll!"months"(1);
3871             assert(sysTime == SysTime(Date(1, 1, 1)));
3872         }
3873 
3874         {
3875             auto sysTime = SysTime(Date(4, 1, 1));
3876             sysTime.roll!"months"(-48);
3877             assert(sysTime == SysTime(Date(4, 1, 1)));
3878             sysTime.roll!"months"(48);
3879             assert(sysTime == SysTime(Date(4, 1, 1)));
3880         }
3881 
3882         {
3883             auto sysTime = SysTime(Date(4, 3, 31));
3884             sysTime.roll!"months"(-49);
3885             assert(sysTime == SysTime(Date(4, 3, 2)));
3886             sysTime.roll!"months"(49);
3887             assert(sysTime == SysTime(Date(4, 4, 2)));
3888         }
3889 
3890         {
3891             auto sysTime = SysTime(Date(4, 3, 31));
3892             sysTime.roll!"months"(-85);
3893             assert(sysTime == SysTime(Date(4, 3, 2)));
3894             sysTime.roll!"months"(85);
3895             assert(sysTime == SysTime(Date(4, 4, 2)));
3896         }
3897 
3898         {
3899             auto sysTime = SysTime(Date(-1, 1, 1));
3900             sysTime.roll!"months"(-1);
3901             assert(sysTime == SysTime(Date(-1, 12, 1)));
3902             sysTime.roll!"months"(1);
3903             assert(sysTime == SysTime(Date(-1, 1, 1)));
3904         }
3905 
3906         {
3907             auto sysTime = SysTime(Date(-4, 1, 1));
3908             sysTime.roll!"months"(-48);
3909             assert(sysTime == SysTime(Date(-4, 1, 1)));
3910             sysTime.roll!"months"(48);
3911             assert(sysTime == SysTime(Date(-4, 1, 1)));
3912         }
3913 
3914         {
3915             auto sysTime = SysTime(Date(-4, 3, 31));
3916             sysTime.roll!"months"(-49);
3917             assert(sysTime == SysTime(Date(-4, 3, 2)));
3918             sysTime.roll!"months"(49);
3919             assert(sysTime == SysTime(Date(-4, 4, 2)));
3920         }
3921 
3922         {
3923             auto sysTime = SysTime(Date(-4, 3, 31));
3924             sysTime.roll!"months"(-85);
3925             assert(sysTime == SysTime(Date(-4, 3, 2)));
3926             sysTime.roll!"months"(85);
3927             assert(sysTime == SysTime(Date(-4, 4, 2)));
3928         }
3929 
3930         {
3931             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
3932             sysTime.roll!"months"(-1);
3933             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17)));
3934             sysTime.roll!"months"(1);
3935             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
3936         }
3937 
3938         {
3939             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
3940             sysTime.roll!"months"(-85);
3941             assert(sysTime == SysTime(DateTime(4, 3, 2, 12, 11, 10), msecs(9)));
3942             sysTime.roll!"months"(85);
3943             assert(sysTime == SysTime(DateTime(4, 4, 2, 12, 11, 10), msecs(9)));
3944         }
3945 
3946         {
3947             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3948             sysTime.roll!"months"(85);
3949             assert(sysTime == SysTime(DateTime(-3, 5, 1, 12, 11, 10), msecs(9)));
3950             sysTime.roll!"months"(-85);
3951             assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9)));
3952         }
3953 
3954         {
3955             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3956             sysTime.roll!"months"(85).roll!"months"(-83);
3957             assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), msecs(9)));
3958         }
3959 
3960         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3961         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3962         static assert(!__traits(compiles, cst.roll!"months"(4)));
3963         //static assert(!__traits(compiles, ist.roll!"months"(4)));
3964     }
3965 
3966     // Test roll!"months"() with AllowDayOverflow.no
3967     @safe unittest
3968     {
3969         // Test A.D.
3970         {
3971             auto sysTime = SysTime(Date(1999, 7, 6));
3972             sysTime.roll!"months"(3, AllowDayOverflow.no);
3973             assert(sysTime == SysTime(Date(1999, 10, 6)));
3974             sysTime.roll!"months"(-4, AllowDayOverflow.no);
3975             assert(sysTime == SysTime(Date(1999, 6, 6)));
3976         }
3977 
3978         {
3979             auto sysTime = SysTime(Date(1999, 7, 6));
3980             sysTime.roll!"months"(6, AllowDayOverflow.no);
3981             assert(sysTime == SysTime(Date(1999, 1, 6)));
3982             sysTime.roll!"months"(-6, AllowDayOverflow.no);
3983             assert(sysTime == SysTime(Date(1999, 7, 6)));
3984         }
3985 
3986         {
3987             auto sysTime = SysTime(Date(1999, 7, 6));
3988             sysTime.roll!"months"(27, AllowDayOverflow.no);
3989             assert(sysTime == SysTime(Date(1999, 10, 6)));
3990             sysTime.roll!"months"(-28, AllowDayOverflow.no);
3991             assert(sysTime == SysTime(Date(1999, 6, 6)));
3992         }
3993 
3994         {
3995             auto sysTime = SysTime(Date(1999, 5, 31));
3996             sysTime.roll!"months"(1, AllowDayOverflow.no);
3997             assert(sysTime == SysTime(Date(1999, 6, 30)));
3998         }
3999 
4000         {
4001             auto sysTime = SysTime(Date(1999, 5, 31));
4002             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4003             assert(sysTime == SysTime(Date(1999, 4, 30)));
4004         }
4005 
4006         {
4007             auto sysTime = SysTime(Date(1999, 2, 28));
4008             sysTime.roll!"months"(12, AllowDayOverflow.no);
4009             assert(sysTime == SysTime(Date(1999, 2, 28)));
4010         }
4011 
4012         {
4013             auto sysTime = SysTime(Date(2000, 2, 29));
4014             sysTime.roll!"months"(12, AllowDayOverflow.no);
4015             assert(sysTime == SysTime(Date(2000, 2, 29)));
4016         }
4017 
4018         {
4019             auto sysTime = SysTime(Date(1999, 7, 31));
4020             sysTime.roll!"months"(1, AllowDayOverflow.no);
4021             assert(sysTime == SysTime(Date(1999, 8, 31)));
4022             sysTime.roll!"months"(1, AllowDayOverflow.no);
4023             assert(sysTime == SysTime(Date(1999, 9, 30)));
4024         }
4025 
4026         {
4027             auto sysTime = SysTime(Date(1998, 8, 31));
4028             sysTime.roll!"months"(13, AllowDayOverflow.no);
4029             assert(sysTime == SysTime(Date(1998, 9, 30)));
4030             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4031             assert(sysTime == SysTime(Date(1998, 8, 30)));
4032         }
4033 
4034         {
4035             auto sysTime = SysTime(Date(1997, 12, 31));
4036             sysTime.roll!"months"(13, AllowDayOverflow.no);
4037             assert(sysTime == SysTime(Date(1997, 1, 31)));
4038             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4039             assert(sysTime == SysTime(Date(1997, 12, 31)));
4040         }
4041 
4042         {
4043             auto sysTime = SysTime(Date(1997, 12, 31));
4044             sysTime.roll!"months"(14, AllowDayOverflow.no);
4045             assert(sysTime == SysTime(Date(1997, 2, 28)));
4046             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4047             assert(sysTime == SysTime(Date(1997, 12, 28)));
4048         }
4049 
4050         {
4051             auto sysTime = SysTime(Date(1998, 12, 31));
4052             sysTime.roll!"months"(14, AllowDayOverflow.no);
4053             assert(sysTime == SysTime(Date(1998, 2, 28)));
4054             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4055             assert(sysTime == SysTime(Date(1998, 12, 28)));
4056         }
4057 
4058         {
4059             auto sysTime = SysTime(Date(1999, 12, 31));
4060             sysTime.roll!"months"(14, AllowDayOverflow.no);
4061             assert(sysTime == SysTime(Date(1999, 2, 28)));
4062             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4063             assert(sysTime == SysTime(Date(1999, 12, 28)));
4064         }
4065 
4066         {
4067             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
4068             sysTime.roll!"months"(3, AllowDayOverflow.no);
4069             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
4070             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4071             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
4072         }
4073 
4074         {
4075             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
4076             sysTime.roll!"months"(14, AllowDayOverflow.no);
4077             assert(sysTime == SysTime(DateTime(1998, 2, 28, 7, 7, 7), hnsecs(422202)));
4078             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4079             assert(sysTime == SysTime(DateTime(1998, 12, 28, 7, 7, 7), hnsecs(422202)));
4080         }
4081 
4082         {
4083             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
4084             sysTime.roll!"months"(14, AllowDayOverflow.no);
4085             assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 7, 7), hnsecs(422202)));
4086             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4087             assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202)));
4088         }
4089 
4090         // Test B.C.
4091         {
4092             auto sysTime = SysTime(Date(-1999, 7, 6));
4093             sysTime.roll!"months"(3, AllowDayOverflow.no);
4094             assert(sysTime == SysTime(Date(-1999, 10, 6)));
4095             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4096             assert(sysTime == SysTime(Date(-1999, 6, 6)));
4097         }
4098 
4099         {
4100             auto sysTime = SysTime(Date(-1999, 7, 6));
4101             sysTime.roll!"months"(6, AllowDayOverflow.no);
4102             assert(sysTime == SysTime(Date(-1999, 1, 6)));
4103             sysTime.roll!"months"(-6, AllowDayOverflow.no);
4104             assert(sysTime == SysTime(Date(-1999, 7, 6)));
4105         }
4106 
4107         {
4108             auto sysTime = SysTime(Date(-1999, 7, 6));
4109             sysTime.roll!"months"(-27, AllowDayOverflow.no);
4110             assert(sysTime == SysTime(Date(-1999, 4, 6)));
4111             sysTime.roll!"months"(28, AllowDayOverflow.no);
4112             assert(sysTime == SysTime(Date(-1999, 8, 6)));
4113         }
4114 
4115         {
4116             auto sysTime = SysTime(Date(-1999, 5, 31));
4117             sysTime.roll!"months"(1, AllowDayOverflow.no);
4118             assert(sysTime == SysTime(Date(-1999, 6, 30)));
4119         }
4120 
4121         {
4122             auto sysTime = SysTime(Date(-1999, 5, 31));
4123             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4124             assert(sysTime == SysTime(Date(-1999, 4, 30)));
4125         }
4126 
4127         {
4128             auto sysTime = SysTime(Date(-1999, 2, 28));
4129             sysTime.roll!"months"(-12, AllowDayOverflow.no);
4130             assert(sysTime == SysTime(Date(-1999, 2, 28)));
4131         }
4132 
4133         {
4134             auto sysTime = SysTime(Date(-2000, 2, 29));
4135             sysTime.roll!"months"(-12, AllowDayOverflow.no);
4136             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4137         }
4138 
4139         {
4140             auto sysTime = SysTime(Date(-1999, 7, 31));
4141             sysTime.roll!"months"(1, AllowDayOverflow.no);
4142             assert(sysTime == SysTime(Date(-1999, 8, 31)));
4143             sysTime.roll!"months"(1, AllowDayOverflow.no);
4144             assert(sysTime == SysTime(Date(-1999, 9, 30)));
4145         }
4146 
4147         {
4148             auto sysTime = SysTime(Date(-1998, 8, 31));
4149             sysTime.roll!"months"(13, AllowDayOverflow.no);
4150             assert(sysTime == SysTime(Date(-1998, 9, 30)));
4151             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4152             assert(sysTime == SysTime(Date(-1998, 8, 30)));
4153         }
4154 
4155         {
4156             auto sysTime = SysTime(Date(-1997, 12, 31));
4157             sysTime.roll!"months"(13, AllowDayOverflow.no);
4158             assert(sysTime == SysTime(Date(-1997, 1, 31)));
4159             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4160             assert(sysTime == SysTime(Date(-1997, 12, 31)));
4161         }
4162 
4163         {
4164             auto sysTime = SysTime(Date(-1997, 12, 31));
4165             sysTime.roll!"months"(14, AllowDayOverflow.no);
4166             assert(sysTime == SysTime(Date(-1997, 2, 28)));
4167             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4168             assert(sysTime == SysTime(Date(-1997, 12, 28)));
4169         }
4170 
4171         {
4172             auto sysTime = SysTime(Date(-2002, 12, 31));
4173             sysTime.roll!"months"(14, AllowDayOverflow.no);
4174             assert(sysTime == SysTime(Date(-2002, 2, 28)));
4175             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4176             assert(sysTime == SysTime(Date(-2002, 12, 28)));
4177         }
4178 
4179         {
4180             auto sysTime = SysTime(Date(-2001, 12, 31));
4181             sysTime.roll!"months"(14, AllowDayOverflow.no);
4182             assert(sysTime == SysTime(Date(-2001, 2, 28)));
4183             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4184             assert(sysTime == SysTime(Date(-2001, 12, 28)));
4185         }
4186 
4187         {
4188             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
4189             sysTime.roll!"months"(3, AllowDayOverflow.no);
4190             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
4191             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4192             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
4193         }
4194 
4195         {
4196             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
4197             sysTime.roll!"months"(14, AllowDayOverflow.no);
4198             assert(sysTime == SysTime(DateTime(-2002, 2, 28, 7, 7, 7), hnsecs(422202)));
4199             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4200             assert(sysTime == SysTime(DateTime(-2002, 12, 28, 7, 7, 7), hnsecs(422202)));
4201         }
4202 
4203         {
4204             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
4205             sysTime.roll!"months"(14, AllowDayOverflow.no);
4206             assert(sysTime == SysTime(DateTime(-2001, 2, 28, 7, 7, 7), hnsecs(422202)));
4207             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4208             assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202)));
4209         }
4210 
4211         // Test Both
4212         {
4213             auto sysTime = SysTime(Date(1, 1, 1));
4214             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4215             assert(sysTime == SysTime(Date(1, 12, 1)));
4216             sysTime.roll!"months"(1, AllowDayOverflow.no);
4217             assert(sysTime == SysTime(Date(1, 1, 1)));
4218         }
4219 
4220         {
4221             auto sysTime = SysTime(Date(4, 1, 1));
4222             sysTime.roll!"months"(-48, AllowDayOverflow.no);
4223             assert(sysTime == SysTime(Date(4, 1, 1)));
4224             sysTime.roll!"months"(48, AllowDayOverflow.no);
4225             assert(sysTime == SysTime(Date(4, 1, 1)));
4226         }
4227 
4228         {
4229             auto sysTime = SysTime(Date(4, 3, 31));
4230             sysTime.roll!"months"(-49, AllowDayOverflow.no);
4231             assert(sysTime == SysTime(Date(4, 2, 29)));
4232             sysTime.roll!"months"(49, AllowDayOverflow.no);
4233             assert(sysTime == SysTime(Date(4, 3, 29)));
4234         }
4235 
4236         {
4237             auto sysTime = SysTime(Date(4, 3, 31));
4238             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4239             assert(sysTime == SysTime(Date(4, 2, 29)));
4240             sysTime.roll!"months"(85, AllowDayOverflow.no);
4241             assert(sysTime == SysTime(Date(4, 3, 29)));
4242         }
4243 
4244         {
4245             auto sysTime = SysTime(Date(-1, 1, 1));
4246             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4247             assert(sysTime == SysTime(Date(-1, 12, 1)));
4248             sysTime.roll!"months"(1, AllowDayOverflow.no);
4249             assert(sysTime == SysTime(Date(-1, 1, 1)));
4250         }
4251 
4252         {
4253             auto sysTime = SysTime(Date(-4, 1, 1));
4254             sysTime.roll!"months"(-48, AllowDayOverflow.no);
4255             assert(sysTime == SysTime(Date(-4, 1, 1)));
4256             sysTime.roll!"months"(48, AllowDayOverflow.no);
4257             assert(sysTime == SysTime(Date(-4, 1, 1)));
4258         }
4259 
4260         {
4261             auto sysTime = SysTime(Date(-4, 3, 31));
4262             sysTime.roll!"months"(-49, AllowDayOverflow.no);
4263             assert(sysTime == SysTime(Date(-4, 2, 29)));
4264             sysTime.roll!"months"(49, AllowDayOverflow.no);
4265             assert(sysTime == SysTime(Date(-4, 3, 29)));
4266         }
4267 
4268         {
4269             auto sysTime = SysTime(Date(-4, 3, 31));
4270             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4271             assert(sysTime == SysTime(Date(-4, 2, 29)));
4272             sysTime.roll!"months"(85, AllowDayOverflow.no);
4273             assert(sysTime == SysTime(Date(-4, 3, 29)));
4274         }
4275 
4276         {
4277             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
4278             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4279             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0)));
4280             sysTime.roll!"months"(1, AllowDayOverflow.no);
4281             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
4282         }
4283 
4284         {
4285             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
4286             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4287             assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4288             sysTime.roll!"months"(1, AllowDayOverflow.no);
4289             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4290         }
4291 
4292         {
4293             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
4294             sysTime.roll!"months"(1, AllowDayOverflow.no);
4295             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
4296             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4297             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
4298         }
4299 
4300         {
4301             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
4302             sysTime.roll!"months"(1, AllowDayOverflow.no);
4303             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4304             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4305             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4306         }
4307 
4308         {
4309             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
4310             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4311             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17)));
4312             sysTime.roll!"months"(1, AllowDayOverflow.no);
4313             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
4314         }
4315 
4316         {
4317             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
4318             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4319             assert(sysTime == SysTime(DateTime(4, 2, 29, 12, 11, 10), msecs(9)));
4320             sysTime.roll!"months"(85, AllowDayOverflow.no);
4321             assert(sysTime == SysTime(DateTime(4, 3, 29, 12, 11, 10), msecs(9)));
4322         }
4323 
4324         {
4325             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4326             sysTime.roll!"months"(85, AllowDayOverflow.no);
4327             assert(sysTime == SysTime(DateTime(-3, 4, 30, 12, 11, 10), msecs(9)));
4328             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4329             assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9)));
4330         }
4331 
4332         {
4333             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4334             sysTime.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no);
4335             assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9)));
4336         }
4337     }
4338 
4339 
4340     /++
4341         Adds the given number of units to this $(LREF SysTime). A negative number
4342         will subtract.
4343 
4344         The difference between rolling and adding is that rolling does not
4345         affect larger units. For instance, rolling a $(LREF SysTime) one
4346         year's worth of days gets the exact same $(LREF SysTime).
4347 
4348         Accepted units are $(D "days"), $(D "minutes"), $(D "hours"),
4349         $(D "minutes"), $(D "seconds"), $(D "msecs"), $(D "usecs"), and
4350         $(D "hnsecs").
4351 
4352         Note that when rolling msecs, usecs or hnsecs, they all add up to a
4353         second. So, for example, rolling 1000 msecs is exactly the same as
4354         rolling 100,000 usecs.
4355 
4356         Params:
4357             units = The units to add.
4358             value = The number of $(D_PARAM units) to add to this
4359                     $(LREF SysTime).
4360       +/
4361     ref SysTime roll(string units)(long value) @safe nothrow
4362         if (units == "days")
4363     {
4364         auto hnsecs = adjTime;
4365         auto gdays = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
4366 
4367         if (hnsecs < 0)
4368         {
4369             hnsecs += convert!("hours", "hnsecs")(24);
4370             --gdays;
4371         }
4372 
4373         auto date = Date(cast(int) gdays);
4374         date.roll!"days"(value);
4375         gdays = date.dayOfGregorianCal - 1;
4376 
4377         if (gdays < 0)
4378         {
4379             hnsecs -= convert!("hours", "hnsecs")(24);
4380             ++gdays;
4381         }
4382 
4383         immutable newDaysHNSecs = convert!("days", "hnsecs")(gdays);
4384         adjTime = newDaysHNSecs + hnsecs;
4385         return  this;
4386     }
4387 
4388     ///
4389     @safe unittest
4390     {
4391         import core.time : msecs, hnsecs;
4392         import std.datetime.date : DateTime;
4393 
4394         auto st1 = SysTime(DateTime(2010, 1, 1, 11, 23, 12));
4395         st1.roll!"days"(1);
4396         assert(st1 == SysTime(DateTime(2010, 1, 2, 11, 23, 12)));
4397         st1.roll!"days"(365);
4398         assert(st1 == SysTime(DateTime(2010, 1, 26, 11, 23, 12)));
4399         st1.roll!"days"(-32);
4400         assert(st1 == SysTime(DateTime(2010, 1, 25, 11, 23, 12)));
4401 
4402         auto st2 = SysTime(DateTime(2010, 7, 4, 12, 0, 0));
4403         st2.roll!"hours"(1);
4404         assert(st2 == SysTime(DateTime(2010, 7, 4, 13, 0, 0)));
4405 
4406         auto st3 = SysTime(DateTime(2010, 2, 12, 12, 0, 0));
4407         st3.roll!"hours"(-1);
4408         assert(st3 == SysTime(DateTime(2010, 2, 12, 11, 0, 0)));
4409 
4410         auto st4 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
4411         st4.roll!"minutes"(1);
4412         assert(st4 == SysTime(DateTime(2009, 12, 31, 0, 1, 0)));
4413 
4414         auto st5 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
4415         st5.roll!"minutes"(-1);
4416         assert(st5 == SysTime(DateTime(2010, 1, 1, 0, 59, 0)));
4417 
4418         auto st6 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
4419         st6.roll!"seconds"(1);
4420         assert(st6 == SysTime(DateTime(2009, 12, 31, 0, 0, 1)));
4421 
4422         auto st7 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
4423         st7.roll!"seconds"(-1);
4424         assert(st7 == SysTime(DateTime(2010, 1, 1, 0, 0, 59)));
4425 
4426         auto dt = DateTime(2010, 1, 1, 0, 0, 0);
4427         auto st8 = SysTime(dt);
4428         st8.roll!"msecs"(1);
4429         assert(st8 == SysTime(dt, msecs(1)));
4430 
4431         auto st9 = SysTime(dt);
4432         st9.roll!"msecs"(-1);
4433         assert(st9 == SysTime(dt, msecs(999)));
4434 
4435         auto st10 = SysTime(dt);
4436         st10.roll!"hnsecs"(1);
4437         assert(st10 == SysTime(dt, hnsecs(1)));
4438 
4439         auto st11 = SysTime(dt);
4440         st11.roll!"hnsecs"(-1);
4441         assert(st11 == SysTime(dt, hnsecs(9_999_999)));
4442     }
4443 
4444     @safe unittest
4445     {
4446         // Test A.D.
4447         {
4448             auto sysTime = SysTime(Date(1999, 2, 28));
4449             sysTime.roll!"days"(1);
4450             assert(sysTime == SysTime(Date(1999, 2, 1)));
4451             sysTime.roll!"days"(-1);
4452             assert(sysTime == SysTime(Date(1999, 2, 28)));
4453         }
4454 
4455         {
4456             auto sysTime = SysTime(Date(2000, 2, 28));
4457             sysTime.roll!"days"(1);
4458             assert(sysTime == SysTime(Date(2000, 2, 29)));
4459             sysTime.roll!"days"(1);
4460             assert(sysTime == SysTime(Date(2000, 2, 1)));
4461             sysTime.roll!"days"(-1);
4462             assert(sysTime == SysTime(Date(2000, 2, 29)));
4463         }
4464 
4465         {
4466             auto sysTime = SysTime(Date(1999, 6, 30));
4467             sysTime.roll!"days"(1);
4468             assert(sysTime == SysTime(Date(1999, 6, 1)));
4469             sysTime.roll!"days"(-1);
4470             assert(sysTime == SysTime(Date(1999, 6, 30)));
4471         }
4472 
4473         {
4474             auto sysTime = SysTime(Date(1999, 7, 31));
4475             sysTime.roll!"days"(1);
4476             assert(sysTime == SysTime(Date(1999, 7, 1)));
4477             sysTime.roll!"days"(-1);
4478             assert(sysTime == SysTime(Date(1999, 7, 31)));
4479         }
4480 
4481         {
4482             auto sysTime = SysTime(Date(1999, 1, 1));
4483             sysTime.roll!"days"(-1);
4484             assert(sysTime == SysTime(Date(1999, 1, 31)));
4485             sysTime.roll!"days"(1);
4486             assert(sysTime == SysTime(Date(1999, 1, 1)));
4487         }
4488 
4489         {
4490             auto sysTime = SysTime(Date(1999, 7, 6));
4491             sysTime.roll!"days"(9);
4492             assert(sysTime == SysTime(Date(1999, 7, 15)));
4493             sysTime.roll!"days"(-11);
4494             assert(sysTime == SysTime(Date(1999, 7, 4)));
4495             sysTime.roll!"days"(30);
4496             assert(sysTime == SysTime(Date(1999, 7, 3)));
4497             sysTime.roll!"days"(-3);
4498             assert(sysTime == SysTime(Date(1999, 7, 31)));
4499         }
4500 
4501         {
4502             auto sysTime = SysTime(Date(1999, 7, 6));
4503             sysTime.roll!"days"(365);
4504             assert(sysTime == SysTime(Date(1999, 7, 30)));
4505             sysTime.roll!"days"(-365);
4506             assert(sysTime == SysTime(Date(1999, 7, 6)));
4507             sysTime.roll!"days"(366);
4508             assert(sysTime == SysTime(Date(1999, 7, 31)));
4509             sysTime.roll!"days"(730);
4510             assert(sysTime == SysTime(Date(1999, 7, 17)));
4511             sysTime.roll!"days"(-1096);
4512             assert(sysTime == SysTime(Date(1999, 7, 6)));
4513         }
4514 
4515         {
4516             auto sysTime = SysTime(Date(1999, 2, 6));
4517             sysTime.roll!"days"(365);
4518             assert(sysTime == SysTime(Date(1999, 2, 7)));
4519             sysTime.roll!"days"(-365);
4520             assert(sysTime == SysTime(Date(1999, 2, 6)));
4521             sysTime.roll!"days"(366);
4522             assert(sysTime == SysTime(Date(1999, 2, 8)));
4523             sysTime.roll!"days"(730);
4524             assert(sysTime == SysTime(Date(1999, 2, 10)));
4525             sysTime.roll!"days"(-1096);
4526             assert(sysTime == SysTime(Date(1999, 2, 6)));
4527         }
4528 
4529         {
4530             auto sysTime = SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578));
4531             sysTime.roll!"days"(1);
4532             assert(sysTime == SysTime(DateTime(1999, 2, 1, 7, 9, 2), usecs(234578)));
4533             sysTime.roll!"days"(-1);
4534             assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578)));
4535         }
4536 
4537         {
4538             auto sysTime = SysTime(DateTime(1999, 7, 6, 7, 9, 2), usecs(234578));
4539             sysTime.roll!"days"(9);
4540             assert(sysTime == SysTime(DateTime(1999, 7, 15, 7, 9, 2), usecs(234578)));
4541             sysTime.roll!"days"(-11);
4542             assert(sysTime == SysTime(DateTime(1999, 7, 4, 7, 9, 2), usecs(234578)));
4543             sysTime.roll!"days"(30);
4544             assert(sysTime == SysTime(DateTime(1999, 7, 3, 7, 9, 2), usecs(234578)));
4545             sysTime.roll!"days"(-3);
4546             assert(sysTime == SysTime(DateTime(1999, 7, 31, 7, 9, 2), usecs(234578)));
4547         }
4548 
4549         // Test B.C.
4550         {
4551             auto sysTime = SysTime(Date(-1999, 2, 28));
4552             sysTime.roll!"days"(1);
4553             assert(sysTime == SysTime(Date(-1999, 2, 1)));
4554             sysTime.roll!"days"(-1);
4555             assert(sysTime == SysTime(Date(-1999, 2, 28)));
4556         }
4557 
4558         {
4559             auto sysTime = SysTime(Date(-2000, 2, 28));
4560             sysTime.roll!"days"(1);
4561             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4562             sysTime.roll!"days"(1);
4563             assert(sysTime == SysTime(Date(-2000, 2, 1)));
4564             sysTime.roll!"days"(-1);
4565             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4566         }
4567 
4568         {
4569             auto sysTime = SysTime(Date(-1999, 6, 30));
4570             sysTime.roll!"days"(1);
4571             assert(sysTime == SysTime(Date(-1999, 6, 1)));
4572             sysTime.roll!"days"(-1);
4573             assert(sysTime == SysTime(Date(-1999, 6, 30)));
4574         }
4575 
4576         {
4577             auto sysTime = SysTime(Date(-1999, 7, 31));
4578             sysTime.roll!"days"(1);
4579             assert(sysTime == SysTime(Date(-1999, 7, 1)));
4580             sysTime.roll!"days"(-1);
4581             assert(sysTime == SysTime(Date(-1999, 7, 31)));
4582         }
4583 
4584         {
4585             auto sysTime = SysTime(Date(-1999, 1, 1));
4586             sysTime.roll!"days"(-1);
4587             assert(sysTime == SysTime(Date(-1999, 1, 31)));
4588             sysTime.roll!"days"(1);
4589             assert(sysTime == SysTime(Date(-1999, 1, 1)));
4590         }
4591 
4592         {
4593             auto sysTime = SysTime(Date(-1999, 7, 6));
4594             sysTime.roll!"days"(9);
4595             assert(sysTime == SysTime(Date(-1999, 7, 15)));
4596             sysTime.roll!"days"(-11);
4597             assert(sysTime == SysTime(Date(-1999, 7, 4)));
4598             sysTime.roll!"days"(30);
4599             assert(sysTime == SysTime(Date(-1999, 7, 3)));
4600             sysTime.roll!"days"(-3);
4601             assert(sysTime == SysTime(Date(-1999, 7, 31)));
4602         }
4603 
4604         {
4605             auto sysTime = SysTime(Date(-1999, 7, 6));
4606             sysTime.roll!"days"(365);
4607             assert(sysTime == SysTime(Date(-1999, 7, 30)));
4608             sysTime.roll!"days"(-365);
4609             assert(sysTime == SysTime(Date(-1999, 7, 6)));
4610             sysTime.roll!"days"(366);
4611             assert(sysTime == SysTime(Date(-1999, 7, 31)));
4612             sysTime.roll!"days"(730);
4613             assert(sysTime == SysTime(Date(-1999, 7, 17)));
4614             sysTime.roll!"days"(-1096);
4615             assert(sysTime == SysTime(Date(-1999, 7, 6)));
4616         }
4617 
4618         {
4619             auto sysTime = SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578));
4620             sysTime.roll!"days"(1);
4621             assert(sysTime == SysTime(DateTime(-1999, 2, 1, 7, 9, 2), usecs(234578)));
4622             sysTime.roll!"days"(-1);
4623             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578)));
4624         }
4625 
4626         {
4627             auto sysTime = SysTime(DateTime(-1999, 7, 6, 7, 9, 2), usecs(234578));
4628             sysTime.roll!"days"(9);
4629             assert(sysTime == SysTime(DateTime(-1999, 7, 15, 7, 9, 2), usecs(234578)));
4630             sysTime.roll!"days"(-11);
4631             assert(sysTime == SysTime(DateTime(-1999, 7, 4, 7, 9, 2), usecs(234578)));
4632             sysTime.roll!"days"(30);
4633             assert(sysTime == SysTime(DateTime(-1999, 7, 3, 7, 9, 2), usecs(234578)));
4634             sysTime.roll!"days"(-3);
4635         }
4636 
4637         // Test Both
4638         {
4639             auto sysTime = SysTime(Date(1, 7, 6));
4640             sysTime.roll!"days"(-365);
4641             assert(sysTime == SysTime(Date(1, 7, 13)));
4642             sysTime.roll!"days"(365);
4643             assert(sysTime == SysTime(Date(1, 7, 6)));
4644             sysTime.roll!"days"(-731);
4645             assert(sysTime == SysTime(Date(1, 7, 19)));
4646             sysTime.roll!"days"(730);
4647             assert(sysTime == SysTime(Date(1, 7, 5)));
4648         }
4649 
4650         {
4651             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
4652             sysTime.roll!"days"(-1);
4653             assert(sysTime == SysTime(DateTime(1, 1, 31, 0, 0, 0)));
4654             sysTime.roll!"days"(1);
4655             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
4656         }
4657 
4658         {
4659             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
4660             sysTime.roll!"days"(-1);
4661             assert(sysTime == SysTime(DateTime(1, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
4662             sysTime.roll!"days"(1);
4663             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4664         }
4665 
4666         {
4667             auto sysTime = SysTime(DateTime(0, 12, 31, 0, 0, 0));
4668             sysTime.roll!"days"(1);
4669             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
4670             sysTime.roll!"days"(-1);
4671             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0)));
4672         }
4673 
4674         {
4675             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
4676             sysTime.roll!"days"(1);
4677             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4678             sysTime.roll!"days"(-1);
4679             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
4680         }
4681 
4682         {
4683             auto sysTime = SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22));
4684             sysTime.roll!"days"(-365);
4685             assert(sysTime == SysTime(DateTime(1, 7, 13, 13, 13, 9), msecs(22)));
4686             sysTime.roll!"days"(365);
4687             assert(sysTime == SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22)));
4688             sysTime.roll!"days"(-731);
4689             assert(sysTime == SysTime(DateTime(1, 7, 19, 13, 13, 9), msecs(22)));
4690             sysTime.roll!"days"(730);
4691             assert(sysTime == SysTime(DateTime(1, 7, 5, 13, 13, 9), msecs(22)));
4692         }
4693 
4694         {
4695             auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22));
4696             sysTime.roll!"days"(-365);
4697             assert(sysTime == SysTime(DateTime(0, 7, 13, 13, 13, 9), msecs(22)));
4698             sysTime.roll!"days"(365);
4699             assert(sysTime == SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22)));
4700             sysTime.roll!"days"(-731);
4701             assert(sysTime == SysTime(DateTime(0, 7, 19, 13, 13, 9), msecs(22)));
4702             sysTime.roll!"days"(730);
4703             assert(sysTime == SysTime(DateTime(0, 7, 5, 13, 13, 9), msecs(22)));
4704         }
4705 
4706         {
4707             auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22));
4708             sysTime.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730);
4709             assert(sysTime == SysTime(DateTime(0, 7, 8, 13, 13, 9), msecs(22)));
4710         }
4711 
4712         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4713         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4714         static assert(!__traits(compiles, cst.roll!"days"(4)));
4715         //static assert(!__traits(compiles, ist.roll!"days"(4)));
4716     }
4717 
4718 
4719     // Shares documentation with "days" version.
4720     ref SysTime roll(string units)(long value) @safe nothrow
4721         if (units == "hours" || units == "minutes" || units == "seconds")
4722     {
4723         try
4724         {
4725             auto hnsecs = adjTime;
4726             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
4727 
4728             if (hnsecs < 0)
4729             {
4730                 hnsecs += convert!("hours", "hnsecs")(24);
4731                 --days;
4732             }
4733 
4734             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
4735             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
4736             immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
4737 
4738             auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
4739                                           cast(int) minute, cast(int) second));
4740             dateTime.roll!units(value);
4741             --days;
4742 
4743             hnsecs += convert!("hours", "hnsecs")(dateTime.hour);
4744             hnsecs += convert!("minutes", "hnsecs")(dateTime.minute);
4745             hnsecs += convert!("seconds", "hnsecs")(dateTime.second);
4746 
4747             if (days < 0)
4748             {
4749                 hnsecs -= convert!("hours", "hnsecs")(24);
4750                 ++days;
4751             }
4752 
4753             immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
4754             adjTime = newDaysHNSecs + hnsecs;
4755             return this;
4756         }
4757         catch (Exception e)
4758             assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw.");
4759     }
4760 
4761     // Test roll!"hours"().
4762     @safe unittest
4763     {
4764         static void testST(SysTime orig, int hours, in SysTime expected, size_t line = __LINE__)
4765         {
4766             orig.roll!"hours"(hours);
4767             if (orig != expected)
4768                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
4769         }
4770 
4771         // Test A.D.
4772         immutable d = msecs(45);
4773         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
4774         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
4775         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
4776         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
4777         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d));
4778         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d));
4779         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d));
4780         testST(beforeAD, 6, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d));
4781         testST(beforeAD, 7, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d));
4782         testST(beforeAD, 8, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
4783         testST(beforeAD, 9, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d));
4784         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
4785         testST(beforeAD, 11, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
4786         testST(beforeAD, 12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
4787         testST(beforeAD, 13, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
4788         testST(beforeAD, 14, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d));
4789         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d));
4790         testST(beforeAD, 16, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
4791         testST(beforeAD, 17, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d));
4792         testST(beforeAD, 18, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d));
4793         testST(beforeAD, 19, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d));
4794         testST(beforeAD, 20, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d));
4795         testST(beforeAD, 21, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d));
4796         testST(beforeAD, 22, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
4797         testST(beforeAD, 23, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
4798         testST(beforeAD, 24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
4799         testST(beforeAD, 25, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
4800         testST(beforeAD, 50, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
4801         testST(beforeAD, 10_000, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
4802 
4803         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
4804         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
4805         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d));
4806         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d));
4807         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d));
4808         testST(beforeAD, -6, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d));
4809         testST(beforeAD, -7, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d));
4810         testST(beforeAD, -8, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
4811         testST(beforeAD, -9, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d));
4812         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d));
4813         testST(beforeAD, -11, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
4814         testST(beforeAD, -12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
4815         testST(beforeAD, -13, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
4816         testST(beforeAD, -14, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
4817         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d));
4818         testST(beforeAD, -16, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
4819         testST(beforeAD, -17, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d));
4820         testST(beforeAD, -18, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d));
4821         testST(beforeAD, -19, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d));
4822         testST(beforeAD, -20, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d));
4823         testST(beforeAD, -21, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d));
4824         testST(beforeAD, -22, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
4825         testST(beforeAD, -23, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
4826         testST(beforeAD, -24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
4827         testST(beforeAD, -25, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
4828         testST(beforeAD, -50, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
4829         testST(beforeAD, -10_000, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
4830 
4831         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
4832         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
4833         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
4834 
4835         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
4836         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
4837         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
4838 
4839         testST(SysTime(DateTime(1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 31, 0, 30, 33), d));
4840         testST(SysTime(DateTime(1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(1999, 8, 1, 23, 30, 33), d));
4841 
4842         testST(SysTime(DateTime(1999, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 12, 31, 0, 30, 33), d));
4843         testST(SysTime(DateTime(2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(2000, 1, 1, 23, 30, 33), d));
4844 
4845         testST(SysTime(DateTime(1999, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(1999, 2, 28, 0, 30, 33), d));
4846         testST(SysTime(DateTime(1999, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(1999, 3, 2, 23, 30, 33), d));
4847 
4848         testST(SysTime(DateTime(2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(2000, 2, 28, 0, 30, 33), d));
4849         testST(SysTime(DateTime(2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(2000, 3, 1, 23, 30, 33), d));
4850 
4851         // Test B.C.
4852         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
4853         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
4854         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
4855         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
4856         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d));
4857         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d));
4858         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d));
4859         testST(beforeBC, 6, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d));
4860         testST(beforeBC, 7, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d));
4861         testST(beforeBC, 8, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
4862         testST(beforeBC, 9, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d));
4863         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
4864         testST(beforeBC, 11, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
4865         testST(beforeBC, 12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
4866         testST(beforeBC, 13, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
4867         testST(beforeBC, 14, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d));
4868         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d));
4869         testST(beforeBC, 16, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
4870         testST(beforeBC, 17, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d));
4871         testST(beforeBC, 18, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d));
4872         testST(beforeBC, 19, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d));
4873         testST(beforeBC, 20, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d));
4874         testST(beforeBC, 21, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d));
4875         testST(beforeBC, 22, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
4876         testST(beforeBC, 23, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
4877         testST(beforeBC, 24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
4878         testST(beforeBC, 25, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
4879         testST(beforeBC, 50, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
4880         testST(beforeBC, 10_000, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
4881 
4882         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
4883         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
4884         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d));
4885         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d));
4886         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d));
4887         testST(beforeBC, -6, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d));
4888         testST(beforeBC, -7, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d));
4889         testST(beforeBC, -8, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
4890         testST(beforeBC, -9, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d));
4891         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d));
4892         testST(beforeBC, -11, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
4893         testST(beforeBC, -12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
4894         testST(beforeBC, -13, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
4895         testST(beforeBC, -14, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
4896         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d));
4897         testST(beforeBC, -16, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
4898         testST(beforeBC, -17, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d));
4899         testST(beforeBC, -18, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d));
4900         testST(beforeBC, -19, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d));
4901         testST(beforeBC, -20, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d));
4902         testST(beforeBC, -21, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d));
4903         testST(beforeBC, -22, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
4904         testST(beforeBC, -23, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
4905         testST(beforeBC, -24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
4906         testST(beforeBC, -25, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
4907         testST(beforeBC, -50, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
4908         testST(beforeBC, -10_000, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
4909 
4910         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
4911         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
4912         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
4913 
4914         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
4915         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
4916         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
4917 
4918         testST(SysTime(DateTime(-1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 31, 0, 30, 33), d));
4919         testST(SysTime(DateTime(-1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 8, 1, 23, 30, 33), d));
4920 
4921         testST(SysTime(DateTime(-2001, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(-2001, 12, 31, 0, 30, 33), d));
4922         testST(SysTime(DateTime(-2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(-2000, 1, 1, 23, 30, 33), d));
4923 
4924         testST(SysTime(DateTime(-2001, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2001, 2, 28, 0, 30, 33), d));
4925         testST(SysTime(DateTime(-2001, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(-2001, 3, 2, 23, 30, 33), d));
4926 
4927         testST(SysTime(DateTime(-2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2000, 2, 28, 0, 30, 33), d));
4928         testST(SysTime(DateTime(-2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(-2000, 3, 1, 23, 30, 33), d));
4929 
4930         // Test Both
4931         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 17_546, SysTime(DateTime(-1, 1, 1, 13, 30, 33), d));
4932         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -17_546, SysTime(DateTime(1, 1, 1, 11, 30, 33), d));
4933 
4934         {
4935             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
4936             sysTime.roll!"hours"(-1);
4937             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 0, 0)));
4938             sysTime.roll!"hours"(1);
4939             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
4940         }
4941 
4942         {
4943             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999));
4944             sysTime.roll!"hours"(-1);
4945             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4946             sysTime.roll!"hours"(1);
4947             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999)));
4948         }
4949 
4950         {
4951             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 0, 0));
4952             sysTime.roll!"hours"(1);
4953             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0)));
4954             sysTime.roll!"hours"(-1);
4955             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0)));
4956         }
4957 
4958         {
4959             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
4960             sysTime.roll!"hours"(1);
4961             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 59, 59), hnsecs(9_999_999)));
4962             sysTime.roll!"hours"(-1);
4963             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
4964         }
4965 
4966         {
4967             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
4968             sysTime.roll!"hours"(1).roll!"hours"(-67);
4969             assert(sysTime == SysTime(DateTime(0, 12, 31, 5, 59, 59), hnsecs(9_999_999)));
4970         }
4971 
4972         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4973         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4974         static assert(!__traits(compiles, cst.roll!"hours"(4)));
4975         //static assert(!__traits(compiles, ist.roll!"hours"(4)));
4976     }
4977 
4978     // Test roll!"minutes"().
4979     @safe unittest
4980     {
4981         static void testST(SysTime orig, int minutes, in SysTime expected, size_t line = __LINE__)
4982         {
4983             orig.roll!"minutes"(minutes);
4984             if (orig != expected)
4985                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
4986         }
4987 
4988         // Test A.D.
4989         immutable d = usecs(7203);
4990         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
4991         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
4992         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
4993         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 32, 33), d));
4994         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 33, 33), d));
4995         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 34, 33), d));
4996         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 35, 33), d));
4997         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 40, 33), d));
4998         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
4999         testST(beforeAD, 29, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5000         testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5001         testST(beforeAD, 45, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5002         testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5003         testST(beforeAD, 75, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5004         testST(beforeAD, 90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5005         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 10, 33), d));
5006 
5007         testST(beforeAD, 689, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5008         testST(beforeAD, 690, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5009         testST(beforeAD, 691, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5010         testST(beforeAD, 960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5011         testST(beforeAD, 1439, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5012         testST(beforeAD, 1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5013         testST(beforeAD, 1441, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5014         testST(beforeAD, 2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5015 
5016         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5017         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 28, 33), d));
5018         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 27, 33), d));
5019         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 26, 33), d));
5020         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 25, 33), d));
5021         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 20, 33), d));
5022         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5023         testST(beforeAD, -29, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5024         testST(beforeAD, -30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5025         testST(beforeAD, -45, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5026         testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5027         testST(beforeAD, -75, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5028         testST(beforeAD, -90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5029         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 50, 33), d));
5030 
5031         testST(beforeAD, -749, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5032         testST(beforeAD, -750, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5033         testST(beforeAD, -751, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5034         testST(beforeAD, -960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5035         testST(beforeAD, -1439, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5036         testST(beforeAD, -1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5037         testST(beforeAD, -1441, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5038         testST(beforeAD, -2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5039 
5040         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5041         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5042         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5043 
5044         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(1999, 7, 6, 11, 0, 33), d));
5045         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(1999, 7, 6, 11, 59, 33), d));
5046         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(1999, 7, 6, 11, 58, 33), d));
5047 
5048         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 1, 33), d));
5049         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 33), d));
5050         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 0, 59, 33), d));
5051 
5052         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(1999, 7, 5, 23, 0, 33), d));
5053         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 33), d));
5054         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(1999, 7, 5, 23, 58, 33), d));
5055 
5056         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(1998, 12, 31, 23, 0, 33), d));
5057         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 33), d));
5058         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(1998, 12, 31, 23, 58, 33), d));
5059 
5060         // Test B.C.
5061         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5062         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5063         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5064         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 32, 33), d));
5065         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 33, 33), d));
5066         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 34, 33), d));
5067         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 35, 33), d));
5068         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 40, 33), d));
5069         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5070         testST(beforeBC, 29, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5071         testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5072         testST(beforeBC, 45, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5073         testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5074         testST(beforeBC, 75, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5075         testST(beforeBC, 90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5076         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 10, 33), d));
5077 
5078         testST(beforeBC, 689, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5079         testST(beforeBC, 690, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5080         testST(beforeBC, 691, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5081         testST(beforeBC, 960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5082         testST(beforeBC, 1439, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5083         testST(beforeBC, 1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5084         testST(beforeBC, 1441, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5085         testST(beforeBC, 2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5086 
5087         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5088         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 28, 33), d));
5089         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 27, 33), d));
5090         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 26, 33), d));
5091         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 25, 33), d));
5092         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 20, 33), d));
5093         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5094         testST(beforeBC, -29, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5095         testST(beforeBC, -30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5096         testST(beforeBC, -45, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5097         testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5098         testST(beforeBC, -75, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5099         testST(beforeBC, -90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5100         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 50, 33), d));
5101 
5102         testST(beforeBC, -749, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5103         testST(beforeBC, -750, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5104         testST(beforeBC, -751, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5105         testST(beforeBC, -960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5106         testST(beforeBC, -1439, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5107         testST(beforeBC, -1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5108         testST(beforeBC, -1441, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5109         testST(beforeBC, -2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5110 
5111         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5112         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5113         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5114 
5115         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 11, 0, 33), d));
5116         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d));
5117         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 11, 58, 33), d));
5118 
5119         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 1, 33), d));
5120         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d));
5121         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 59, 33), d));
5122 
5123         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 0, 33), d));
5124         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d));
5125         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 58, 33), d));
5126 
5127         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 0, 33), d));
5128         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d));
5129         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 58, 33), d));
5130 
5131         // Test Both
5132         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(1, 1, 1, 0, 59, 0)));
5133         testST(SysTime(DateTime(0, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5134 
5135         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(0, 1, 1, 0, 59, 0)));
5136         testST(SysTime(DateTime(-1, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(-1, 12, 31, 23, 0, 0)));
5137 
5138         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 1_052_760, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d));
5139         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -1_052_760, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5140 
5141         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 1_052_782, SysTime(DateTime(-1, 1, 1, 11, 52, 33), d));
5142         testST(SysTime(DateTime(1, 1, 1, 13, 52, 33), d), -1_052_782, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5143 
5144         {
5145             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5146             sysTime.roll!"minutes"(-1);
5147             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 0)));
5148             sysTime.roll!"minutes"(1);
5149             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5150         }
5151 
5152         {
5153             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999));
5154             sysTime.roll!"minutes"(-1);
5155             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999)));
5156             sysTime.roll!"minutes"(1);
5157             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999)));
5158         }
5159 
5160         {
5161             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 0));
5162             sysTime.roll!"minutes"(1);
5163             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5164             sysTime.roll!"minutes"(-1);
5165             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0)));
5166         }
5167 
5168         {
5169             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5170             sysTime.roll!"minutes"(1);
5171             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 59), hnsecs(9_999_999)));
5172             sysTime.roll!"minutes"(-1);
5173             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5174         }
5175 
5176         {
5177             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5178             sysTime.roll!"minutes"(1).roll!"minutes"(-79);
5179             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 41, 59), hnsecs(9_999_999)));
5180         }
5181 
5182         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5183         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5184         static assert(!__traits(compiles, cst.roll!"minutes"(4)));
5185         //static assert(!__traits(compiles, ist.roll!"minutes"(4)));
5186     }
5187 
5188     // Test roll!"seconds"().
5189     @safe unittest
5190     {
5191         static void testST(SysTime orig, int seconds, in SysTime expected, size_t line = __LINE__)
5192         {
5193             orig.roll!"seconds"(seconds);
5194             if (orig != expected)
5195                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5196         }
5197 
5198         // Test A.D.
5199         immutable d = msecs(274);
5200         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
5201         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5202         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5203         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 35), d));
5204         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 30, 36), d));
5205         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 30, 37), d));
5206         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 30, 38), d));
5207         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 43), d));
5208         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 30, 48), d));
5209         testST(beforeAD, 26, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5210         testST(beforeAD, 27, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5211         testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 30, 3), d));
5212         testST(beforeAD, 59, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5213         testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5214         testST(beforeAD, 61, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5215 
5216         testST(beforeAD, 1766, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5217         testST(beforeAD, 1767, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5218         testST(beforeAD, 1768, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d));
5219         testST(beforeAD, 2007, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5220         testST(beforeAD, 3599, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5221         testST(beforeAD, 3600, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5222         testST(beforeAD, 3601, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5223         testST(beforeAD, 7200, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5224 
5225         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5226         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 31), d));
5227         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 30, 30), d));
5228         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 30, 29), d));
5229         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 30, 28), d));
5230         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 23), d));
5231         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 30, 18), d));
5232         testST(beforeAD, -33, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5233         testST(beforeAD, -34, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5234         testST(beforeAD, -35, SysTime(DateTime(1999, 7, 6, 12, 30, 58), d));
5235         testST(beforeAD, -59, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5236         testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5237         testST(beforeAD, -61, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5238 
5239         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d));
5240         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5241         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5242 
5243         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 0, 1), d));
5244         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 0), d));
5245         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 0, 59), d));
5246 
5247         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 0, 0, 1), d));
5248         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 0), d));
5249         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 0, 0, 59), d));
5250 
5251         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(1999, 7, 5, 23, 59, 0), d));
5252         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 59), d));
5253         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(1999, 7, 5, 23, 59, 58), d));
5254 
5255         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(1998, 12, 31, 23, 59, 0), d));
5256         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 59), d));
5257         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(1998, 12, 31, 23, 59, 58), d));
5258 
5259         // Test B.C.
5260         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5261         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5262         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5263         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 35), d));
5264         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 30, 36), d));
5265         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 30, 37), d));
5266         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 30, 38), d));
5267         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 43), d));
5268         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 30, 48), d));
5269         testST(beforeBC, 26, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5270         testST(beforeBC, 27, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5271         testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 30, 3), d));
5272         testST(beforeBC, 59, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5273         testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5274         testST(beforeBC, 61, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5275 
5276         testST(beforeBC, 1766, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5277         testST(beforeBC, 1767, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5278         testST(beforeBC, 1768, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d));
5279         testST(beforeBC, 2007, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5280         testST(beforeBC, 3599, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5281         testST(beforeBC, 3600, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5282         testST(beforeBC, 3601, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5283         testST(beforeBC, 7200, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5284 
5285         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5286         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 31), d));
5287         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 30, 30), d));
5288         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 30, 29), d));
5289         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 30, 28), d));
5290         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 23), d));
5291         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 30, 18), d));
5292         testST(beforeBC, -33, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5293         testST(beforeBC, -34, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5294         testST(beforeBC, -35, SysTime(DateTime(-1999, 7, 6, 12, 30, 58), d));
5295         testST(beforeBC, -59, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5296         testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5297         testST(beforeBC, -61, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5298 
5299         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d));
5300         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5301         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5302 
5303         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 0, 1), d));
5304         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d));
5305         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 0, 59), d));
5306 
5307         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 0, 1), d));
5308         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d));
5309         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 0, 59), d));
5310 
5311         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 59, 0), d));
5312         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d));
5313         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 59, 58), d));
5314 
5315         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 59, 0), d));
5316         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d));
5317         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 59, 58), d));
5318 
5319         // Test Both
5320         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(1, 1, 1, 0, 0, 59), d));
5321         testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(0, 12, 31, 23, 59, 0), d));
5322 
5323         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(0, 1, 1, 0, 0, 59), d));
5324         testST(SysTime(DateTime(-1, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-1, 12, 31, 23, 59, 0), d));
5325 
5326         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_600L, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d));
5327         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -63_165_600L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5328 
5329         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_617L, SysTime(DateTime(-1, 1, 1, 11, 30, 50), d));
5330         testST(SysTime(DateTime(1, 1, 1, 13, 30, 50), d), -63_165_617L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5331 
5332         {
5333             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5334             sysTime.roll!"seconds"(-1);
5335             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59)));
5336             sysTime.roll!"seconds"(1);
5337             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5338         }
5339 
5340         {
5341             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999));
5342             sysTime.roll!"seconds"(-1);
5343             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999)));
5344             sysTime.roll!"seconds"(1);
5345             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
5346         }
5347 
5348         {
5349             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59));
5350             sysTime.roll!"seconds"(1);
5351             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0)));
5352             sysTime.roll!"seconds"(-1);
5353             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59)));
5354         }
5355 
5356         {
5357             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5358             sysTime.roll!"seconds"(1);
5359             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0), hnsecs(9_999_999)));
5360             sysTime.roll!"seconds"(-1);
5361             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5362         }
5363 
5364         {
5365             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5366             sysTime.roll!"seconds"(1).roll!"seconds"(-102);
5367             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 18), hnsecs(9_999_999)));
5368         }
5369 
5370         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5371         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5372         static assert(!__traits(compiles, cst.roll!"seconds"(4)));
5373         //static assert(!__traits(compiles, ist.roll!"seconds"(4)));
5374     }
5375 
5376 
5377     // Shares documentation with "days" version.
5378     ref SysTime roll(string units)(long value) @safe nothrow
5379         if (units == "msecs" || units == "usecs" || units == "hnsecs")
5380     {
5381         auto hnsecs = adjTime;
5382         immutable days = splitUnitsFromHNSecs!"days"(hnsecs);
5383         immutable negative = hnsecs < 0;
5384 
5385         if (negative)
5386             hnsecs += convert!("hours", "hnsecs")(24);
5387 
5388         immutable seconds = splitUnitsFromHNSecs!"seconds"(hnsecs);
5389         hnsecs += convert!(units, "hnsecs")(value);
5390         hnsecs %= convert!("seconds", "hnsecs")(1);
5391 
5392         if (hnsecs < 0)
5393             hnsecs += convert!("seconds", "hnsecs")(1);
5394         hnsecs += convert!("seconds", "hnsecs")(seconds);
5395 
5396         if (negative)
5397             hnsecs -= convert!("hours", "hnsecs")(24);
5398 
5399         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
5400         adjTime = newDaysHNSecs + hnsecs;
5401         return this;
5402     }
5403 
5404 
5405     // Test roll!"msecs"().
5406     @safe unittest
5407     {
5408         static void testST(SysTime orig, int milliseconds, in SysTime expected, size_t line = __LINE__)
5409         {
5410             orig.roll!"msecs"(milliseconds);
5411             if (orig != expected)
5412                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5413         }
5414 
5415         // Test A.D.
5416         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274));
5417         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5418         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275)));
5419         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(276)));
5420         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(284)));
5421         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(374)));
5422         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5423         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5424         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5425         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275)));
5426         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5427         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5428         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5429         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(1)));
5430         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5431         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5432 
5433         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273)));
5434         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(272)));
5435         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(264)));
5436         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(174)));
5437         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5438         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5439         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5440         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273)));
5441         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5442         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5443         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5444         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5445         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5446 
5447         // Test B.C.
5448         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274));
5449         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5450         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275)));
5451         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(276)));
5452         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(284)));
5453         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(374)));
5454         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5455         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5456         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5457         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275)));
5458         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5459         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5460         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5461         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(1)));
5462         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5463         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5464 
5465         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273)));
5466         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(272)));
5467         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(264)));
5468         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(174)));
5469         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5470         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5471         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5472         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273)));
5473         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5474         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5475         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5476         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5477         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5478 
5479         // Test Both
5480         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5481         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(1)));
5482         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5483         testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(999)));
5484         testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(998)));
5485         testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5486         testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5487         testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(445)));
5488 
5489         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5490         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_989_999)));
5491         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5492         testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999)));
5493         testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999)));
5494         testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5495         testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5496         testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(5_549_999)));
5497 
5498         {
5499             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5500             st.roll!"msecs"(1202).roll!"msecs"(-703);
5501             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(4_989_999)));
5502         }
5503 
5504         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5505         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5506         static assert(!__traits(compiles, cst.addMSecs(4)));
5507         //static assert(!__traits(compiles, ist.addMSecs(4)));
5508     }
5509 
5510     // Test roll!"usecs"().
5511     @safe unittest
5512     {
5513         static void testST(SysTime orig, long microseconds, in SysTime expected, size_t line = __LINE__)
5514         {
5515             orig.roll!"usecs"(microseconds);
5516             if (orig != expected)
5517                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5518         }
5519 
5520         // Test A.D.
5521         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274));
5522         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5523         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(275)));
5524         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(276)));
5525         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(284)));
5526         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(374)));
5527         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999)));
5528         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1000)));
5529         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1274)));
5530         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1275)));
5531         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(2274)));
5532         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(26_999)));
5533         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_000)));
5534         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_001)));
5535         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(766_999)));
5536         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(767_000)));
5537         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5538         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5539         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5540 
5541         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(273)));
5542         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(272)));
5543         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(264)));
5544         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(174)));
5545         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5546         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_999)));
5547         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_274)));
5548         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_273)));
5549         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(998_274)));
5550         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(967_000)));
5551         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(966_999)));
5552         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(167_000)));
5553         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(166_999)));
5554         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5555         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5556         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5557 
5558         // Test B.C.
5559         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274));
5560         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
5561         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(275)));
5562         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(276)));
5563         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(284)));
5564         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(374)));
5565         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999)));
5566         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1000)));
5567         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1274)));
5568         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1275)));
5569         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(2274)));
5570         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(26_999)));
5571         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_000)));
5572         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_001)));
5573         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(766_999)));
5574         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(767_000)));
5575         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
5576         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
5577         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
5578 
5579         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(273)));
5580         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(272)));
5581         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(264)));
5582         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(174)));
5583         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5584         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_999)));
5585         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_274)));
5586         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_273)));
5587         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(998_274)));
5588         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(967_000)));
5589         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(966_999)));
5590         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(167_000)));
5591         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(166_999)));
5592         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
5593         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
5594         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
5595 
5596         // Test Both
5597         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5598         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(1)));
5599         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5600         testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_999)));
5601         testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_998)));
5602         testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_000)));
5603         testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(998_000)));
5604         testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(997_445)));
5605         testST(beforeBoth1, -1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5606         testST(beforeBoth1, -2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5607         testST(beforeBoth1, -2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(666_667)));
5608 
5609         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5610         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_989)));
5611         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5612         testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9)));
5613         testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19)));
5614         testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999)));
5615         testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999)));
5616         testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(25_549)));
5617         testST(beforeBoth2, 1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5618         testST(beforeBoth2, 2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5619         testST(beforeBoth2, 2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(3_333_329)));
5620 
5621         {
5622             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5623             st.roll!"usecs"(9_020_027);
5624             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(200_269)));
5625         }
5626 
5627         {
5628             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5629             st.roll!"usecs"(9_020_027).roll!"usecs"(-70_034);
5630             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_499_929)));
5631         }
5632 
5633         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5634         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5635         static assert(!__traits(compiles, cst.roll!"usecs"(4)));
5636         //static assert(!__traits(compiles, ist.roll!"usecs"(4)));
5637     }
5638 
5639     // Test roll!"hnsecs"().
5640     @safe unittest
5641     {
5642         static void testST(SysTime orig, long hnsecs, in SysTime expected, size_t line = __LINE__)
5643         {
5644             orig.roll!"hnsecs"(hnsecs);
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         auto dtAD = DateTime(1999, 7, 6, 12, 30, 33);
5651         auto beforeAD = SysTime(dtAD, hnsecs(274));
5652         testST(beforeAD, 0, SysTime(dtAD, hnsecs(274)));
5653         testST(beforeAD, 1, SysTime(dtAD, hnsecs(275)));
5654         testST(beforeAD, 2, SysTime(dtAD, hnsecs(276)));
5655         testST(beforeAD, 10, SysTime(dtAD, hnsecs(284)));
5656         testST(beforeAD, 100, SysTime(dtAD, hnsecs(374)));
5657         testST(beforeAD, 725, SysTime(dtAD, hnsecs(999)));
5658         testST(beforeAD, 726, SysTime(dtAD, hnsecs(1000)));
5659         testST(beforeAD, 1000, SysTime(dtAD, hnsecs(1274)));
5660         testST(beforeAD, 1001, SysTime(dtAD, hnsecs(1275)));
5661         testST(beforeAD, 2000, SysTime(dtAD, hnsecs(2274)));
5662         testST(beforeAD, 26_725, SysTime(dtAD, hnsecs(26_999)));
5663         testST(beforeAD, 26_726, SysTime(dtAD, hnsecs(27_000)));
5664         testST(beforeAD, 26_727, SysTime(dtAD, hnsecs(27_001)));
5665         testST(beforeAD, 1_766_725, SysTime(dtAD, hnsecs(1_766_999)));
5666         testST(beforeAD, 1_766_726, SysTime(dtAD, hnsecs(1_767_000)));
5667         testST(beforeAD, 1_000_000, SysTime(dtAD, hnsecs(1_000_274)));
5668         testST(beforeAD, 60_000_000L, SysTime(dtAD, hnsecs(274)));
5669         testST(beforeAD, 3_600_000_000L, SysTime(dtAD, hnsecs(274)));
5670         testST(beforeAD, 600_000_000L, SysTime(dtAD, hnsecs(274)));
5671         testST(beforeAD, 36_000_000_000L, SysTime(dtAD, hnsecs(274)));
5672 
5673         testST(beforeAD, -1, SysTime(dtAD, hnsecs(273)));
5674         testST(beforeAD, -2, SysTime(dtAD, hnsecs(272)));
5675         testST(beforeAD, -10, SysTime(dtAD, hnsecs(264)));
5676         testST(beforeAD, -100, SysTime(dtAD, hnsecs(174)));
5677         testST(beforeAD, -274, SysTime(dtAD));
5678         testST(beforeAD, -275, SysTime(dtAD, hnsecs(9_999_999)));
5679         testST(beforeAD, -1000, SysTime(dtAD, hnsecs(9_999_274)));
5680         testST(beforeAD, -1001, SysTime(dtAD, hnsecs(9_999_273)));
5681         testST(beforeAD, -2000, SysTime(dtAD, hnsecs(9_998_274)));
5682         testST(beforeAD, -33_274, SysTime(dtAD, hnsecs(9_967_000)));
5683         testST(beforeAD, -33_275, SysTime(dtAD, hnsecs(9_966_999)));
5684         testST(beforeAD, -1_833_274, SysTime(dtAD, hnsecs(8_167_000)));
5685         testST(beforeAD, -1_833_275, SysTime(dtAD, hnsecs(8_166_999)));
5686         testST(beforeAD, -1_000_000, SysTime(dtAD, hnsecs(9_000_274)));
5687         testST(beforeAD, -60_000_000L, SysTime(dtAD, hnsecs(274)));
5688         testST(beforeAD, -3_600_000_000L, SysTime(dtAD, hnsecs(274)));
5689         testST(beforeAD, -600_000_000L, SysTime(dtAD, hnsecs(274)));
5690         testST(beforeAD, -36_000_000_000L, SysTime(dtAD, hnsecs(274)));
5691 
5692         // Test B.C.
5693         auto dtBC = DateTime(-1999, 7, 6, 12, 30, 33);
5694         auto beforeBC = SysTime(dtBC, hnsecs(274));
5695         testST(beforeBC, 0, SysTime(dtBC, hnsecs(274)));
5696         testST(beforeBC, 1, SysTime(dtBC, hnsecs(275)));
5697         testST(beforeBC, 2, SysTime(dtBC, hnsecs(276)));
5698         testST(beforeBC, 10, SysTime(dtBC, hnsecs(284)));
5699         testST(beforeBC, 100, SysTime(dtBC, hnsecs(374)));
5700         testST(beforeBC, 725, SysTime(dtBC, hnsecs(999)));
5701         testST(beforeBC, 726, SysTime(dtBC, hnsecs(1000)));
5702         testST(beforeBC, 1000, SysTime(dtBC, hnsecs(1274)));
5703         testST(beforeBC, 1001, SysTime(dtBC, hnsecs(1275)));
5704         testST(beforeBC, 2000, SysTime(dtBC, hnsecs(2274)));
5705         testST(beforeBC, 26_725, SysTime(dtBC, hnsecs(26_999)));
5706         testST(beforeBC, 26_726, SysTime(dtBC, hnsecs(27_000)));
5707         testST(beforeBC, 26_727, SysTime(dtBC, hnsecs(27_001)));
5708         testST(beforeBC, 1_766_725, SysTime(dtBC, hnsecs(1_766_999)));
5709         testST(beforeBC, 1_766_726, SysTime(dtBC, hnsecs(1_767_000)));
5710         testST(beforeBC, 1_000_000, SysTime(dtBC, hnsecs(1_000_274)));
5711         testST(beforeBC, 60_000_000L, SysTime(dtBC, hnsecs(274)));
5712         testST(beforeBC, 3_600_000_000L, SysTime(dtBC, hnsecs(274)));
5713         testST(beforeBC, 600_000_000L, SysTime(dtBC, hnsecs(274)));
5714         testST(beforeBC, 36_000_000_000L, SysTime(dtBC, hnsecs(274)));
5715 
5716         testST(beforeBC, -1, SysTime(dtBC, hnsecs(273)));
5717         testST(beforeBC, -2, SysTime(dtBC, hnsecs(272)));
5718         testST(beforeBC, -10, SysTime(dtBC, hnsecs(264)));
5719         testST(beforeBC, -100, SysTime(dtBC, hnsecs(174)));
5720         testST(beforeBC, -274, SysTime(dtBC));
5721         testST(beforeBC, -275, SysTime(dtBC, hnsecs(9_999_999)));
5722         testST(beforeBC, -1000, SysTime(dtBC, hnsecs(9_999_274)));
5723         testST(beforeBC, -1001, SysTime(dtBC, hnsecs(9_999_273)));
5724         testST(beforeBC, -2000, SysTime(dtBC, hnsecs(9_998_274)));
5725         testST(beforeBC, -33_274, SysTime(dtBC, hnsecs(9_967_000)));
5726         testST(beforeBC, -33_275, SysTime(dtBC, hnsecs(9_966_999)));
5727         testST(beforeBC, -1_833_274, SysTime(dtBC, hnsecs(8_167_000)));
5728         testST(beforeBC, -1_833_275, SysTime(dtBC, hnsecs(8_166_999)));
5729         testST(beforeBC, -1_000_000, SysTime(dtBC, hnsecs(9_000_274)));
5730         testST(beforeBC, -60_000_000L, SysTime(dtBC, hnsecs(274)));
5731         testST(beforeBC, -3_600_000_000L, SysTime(dtBC, hnsecs(274)));
5732         testST(beforeBC, -600_000_000L, SysTime(dtBC, hnsecs(274)));
5733         testST(beforeBC, -36_000_000_000L, SysTime(dtBC, hnsecs(274)));
5734 
5735         // Test Both
5736         auto dtBoth1 = DateTime(1, 1, 1, 0, 0, 0);
5737         auto beforeBoth1 = SysTime(dtBoth1);
5738         testST(beforeBoth1, 1, SysTime(dtBoth1, hnsecs(1)));
5739         testST(beforeBoth1, 0, SysTime(dtBoth1));
5740         testST(beforeBoth1, -1, SysTime(dtBoth1, hnsecs(9_999_999)));
5741         testST(beforeBoth1, -2, SysTime(dtBoth1, hnsecs(9_999_998)));
5742         testST(beforeBoth1, -1000, SysTime(dtBoth1, hnsecs(9_999_000)));
5743         testST(beforeBoth1, -2000, SysTime(dtBoth1, hnsecs(9_998_000)));
5744         testST(beforeBoth1, -2555, SysTime(dtBoth1, hnsecs(9_997_445)));
5745         testST(beforeBoth1, -1_000_000, SysTime(dtBoth1, hnsecs(9_000_000)));
5746         testST(beforeBoth1, -2_000_000, SysTime(dtBoth1, hnsecs(8_000_000)));
5747         testST(beforeBoth1, -2_333_333, SysTime(dtBoth1, hnsecs(7_666_667)));
5748         testST(beforeBoth1, -10_000_000, SysTime(dtBoth1));
5749         testST(beforeBoth1, -20_000_000, SysTime(dtBoth1));
5750         testST(beforeBoth1, -20_888_888, SysTime(dtBoth1, hnsecs(9_111_112)));
5751 
5752         auto dtBoth2 = DateTime(0, 12, 31, 23, 59, 59);
5753         auto beforeBoth2 = SysTime(dtBoth2, hnsecs(9_999_999));
5754         testST(beforeBoth2, -1, SysTime(dtBoth2, hnsecs(9_999_998)));
5755         testST(beforeBoth2, 0, SysTime(dtBoth2, hnsecs(9_999_999)));
5756         testST(beforeBoth2, 1, SysTime(dtBoth2));
5757         testST(beforeBoth2, 2, SysTime(dtBoth2, hnsecs(1)));
5758         testST(beforeBoth2, 1000, SysTime(dtBoth2, hnsecs(999)));
5759         testST(beforeBoth2, 2000, SysTime(dtBoth2, hnsecs(1999)));
5760         testST(beforeBoth2, 2555, SysTime(dtBoth2, hnsecs(2554)));
5761         testST(beforeBoth2, 1_000_000, SysTime(dtBoth2, hnsecs(999_999)));
5762         testST(beforeBoth2, 2_000_000, SysTime(dtBoth2, hnsecs(1_999_999)));
5763         testST(beforeBoth2, 2_333_333, SysTime(dtBoth2, hnsecs(2_333_332)));
5764         testST(beforeBoth2, 10_000_000, SysTime(dtBoth2, hnsecs(9_999_999)));
5765         testST(beforeBoth2, 20_000_000, SysTime(dtBoth2, hnsecs(9_999_999)));
5766         testST(beforeBoth2, 20_888_888, SysTime(dtBoth2, hnsecs(888_887)));
5767 
5768         {
5769             auto st = SysTime(dtBoth2, hnsecs(9_999_999));
5770             st.roll!"hnsecs"(70_777_222).roll!"hnsecs"(-222_555_292);
5771             assert(st == SysTime(dtBoth2, hnsecs(8_221_929)));
5772         }
5773 
5774         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5775         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5776         static assert(!__traits(compiles, cst.roll!"hnsecs"(4)));
5777         //static assert(!__traits(compiles, ist.roll!"hnsecs"(4)));
5778     }
5779 
5780 
5781     /++
5782         Gives the result of adding or subtracting a $(REF Duration, core,time)
5783         from this $(LREF SysTime).
5784 
5785         The legal types of arithmetic for $(LREF SysTime) using this operator
5786         are
5787 
5788         $(BOOKTABLE,
5789         $(TR $(TD SysTime) $(TD +) $(TD Duration) $(TD -->) $(TD SysTime))
5790         $(TR $(TD SysTime) $(TD -) $(TD Duration) $(TD -->) $(TD SysTime))
5791         )
5792 
5793         Params:
5794             duration = The $(REF Duration, core,time) to add to or subtract from
5795                        this $(LREF SysTime).
5796       +/
5797     SysTime opBinary(string op)(Duration duration) @safe const pure nothrow
5798         if (op == "+" || op == "-")
5799     {
5800         SysTime retval = SysTime(this._stdTime, this._timezone);
5801         immutable hnsecs = duration.total!"hnsecs";
5802         mixin("retval._stdTime " ~ op ~ "= hnsecs;");
5803         return retval;
5804     }
5805 
5806     ///
5807     @safe unittest
5808     {
5809         import core.time : hours, seconds;
5810         import std.datetime.date : DateTime;
5811 
5812         assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + seconds(1) ==
5813                SysTime(DateTime(2016, 1, 1, 0, 0, 0)));
5814 
5815         assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + hours(1) ==
5816                SysTime(DateTime(2016, 1, 1, 0, 59, 59)));
5817 
5818         assert(SysTime(DateTime(2016, 1, 1, 0, 0, 0)) - seconds(1) ==
5819                SysTime(DateTime(2015, 12, 31, 23, 59, 59)));
5820 
5821         assert(SysTime(DateTime(2016, 1, 1, 0, 59, 59)) - hours(1) ==
5822                SysTime(DateTime(2015, 12, 31, 23, 59, 59)));
5823     }
5824 
5825     @safe unittest
5826     {
5827         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_678));
5828 
5829         assert(st + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
5830         assert(st + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
5831         assert(st + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
5832         assert(st + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
5833         assert(st + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
5834         assert(st + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
5835         assert(st + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
5836         assert(st + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
5837         assert(st + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
5838         assert(st + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
5839         assert(st + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
5840         assert(st + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
5841         assert(st + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
5842         assert(st + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
5843         assert(st + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
5844         assert(st + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671)));
5845 
5846         assert(st - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
5847         assert(st - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
5848         assert(st - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
5849         assert(st - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
5850         assert(st - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
5851         assert(st - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
5852         assert(st - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
5853         assert(st - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
5854         assert(st - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
5855         assert(st - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
5856         assert(st - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
5857         assert(st - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
5858         assert(st - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
5859         assert(st - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
5860         assert(st - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
5861         assert(st - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671)));
5862 
5863         static void testST(in SysTime orig, long hnsecs, in SysTime expected, size_t line = __LINE__)
5864         {
5865             auto result = orig + dur!"hnsecs"(hnsecs);
5866             if (result != expected)
5867                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", result, expected), __FILE__, line);
5868         }
5869 
5870         // Test A.D.
5871         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
5872         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
5873         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
5874         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
5875         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
5876         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
5877         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
5878         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
5879         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
5880         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
5881         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
5882         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
5883         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
5884         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
5885         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
5886         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
5887         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
5888         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
5889         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
5890         testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
5891         testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
5892 
5893         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
5894         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
5895         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
5896         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
5897         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5898         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
5899         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
5900         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
5901         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
5902         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
5903         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
5904         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
5905         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
5906         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
5907         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
5908         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
5909         testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
5910         testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
5911 
5912         // Test B.C.
5913         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
5914         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
5915         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
5916         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
5917         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
5918         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
5919         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
5920         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
5921         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
5922         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
5923         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
5924         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
5925         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
5926         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
5927         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
5928         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
5929         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
5930         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
5931         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
5932         testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
5933         testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
5934 
5935         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
5936         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
5937         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
5938         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
5939         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5940         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
5941         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
5942         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
5943         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
5944         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
5945         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
5946         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
5947         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
5948         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
5949         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
5950         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
5951         testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
5952         testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
5953 
5954         // Test Both
5955         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5956         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
5957         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5958         testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5959         testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
5960         testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
5961         testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
5962         testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
5963         testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
5964         testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
5965         testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
5966         testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
5967         testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
5968         testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
5969 
5970         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5971         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
5972         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5973         testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5974         testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
5975         testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
5976         testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
5977         testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
5978         testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
5979         testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
5980         testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
5981         testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
5982         testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
5983         testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887)));
5984 
5985         auto duration = dur!"seconds"(12);
5986         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5987         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5988         assert(cst + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45)));
5989         //assert(ist + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45)));
5990         assert(cst - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21)));
5991         //assert(ist - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21)));
5992     }
5993 
5994 
5995     /++
5996         Gives the result of adding or subtracting a $(REF Duration, core,time) from
5997         this $(LREF SysTime), as well as assigning the result to this
5998         $(LREF SysTime).
5999 
6000         The legal types of arithmetic for $(LREF SysTime) using this operator are
6001 
6002         $(BOOKTABLE,
6003         $(TR $(TD SysTime) $(TD +) $(TD Duration) $(TD -->) $(TD SysTime))
6004         $(TR $(TD SysTime) $(TD -) $(TD Duration) $(TD -->) $(TD SysTime))
6005         )
6006 
6007         Params:
6008             duration = The $(REF Duration, core,time) to add to or subtract from
6009                        this $(LREF SysTime).
6010       +/
6011     ref SysTime opOpAssign(string op)(Duration duration) @safe pure nothrow
6012         if (op == "+" || op == "-")
6013     {
6014         immutable hnsecs = duration.total!"hnsecs";
6015         mixin("_stdTime " ~ op ~ "= hnsecs;");
6016         return this;
6017     }
6018 
6019     @safe unittest
6020     {
6021         auto before = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6022         assert(before + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
6023         assert(before + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
6024         assert(before + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
6025         assert(before + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
6026 
6027         assert(before + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
6028         assert(before + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
6029         assert(before + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
6030         assert(before + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
6031         assert(before + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
6032         assert(before + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
6033         assert(before + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
6034         assert(before + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
6035         assert(before + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
6036         assert(before + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
6037         assert(before + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
6038         assert(before + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
6039 
6040         assert(before - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
6041         assert(before - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
6042         assert(before - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
6043         assert(before - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
6044 
6045         assert(before - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
6046         assert(before - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
6047         assert(before - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
6048         assert(before - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
6049         assert(before - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
6050         assert(before - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
6051         assert(before - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
6052         assert(before - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
6053         assert(before - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
6054         assert(before - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
6055         assert(before - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
6056         assert(before - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
6057 
6058         static void testST(SysTime orig, long hnsecs, in SysTime expected, size_t line = __LINE__)
6059         {
6060             auto r = orig += dur!"hnsecs"(hnsecs);
6061             if (orig != expected)
6062                 throw new AssertError(format("Failed 1. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
6063             if (r != expected)
6064                 throw new AssertError(format("Failed 2. actual [%s] != expected [%s]", r, expected), __FILE__, line);
6065         }
6066 
6067         // Test A.D.
6068         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
6069         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
6070         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
6071         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
6072         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
6073         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
6074         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
6075         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6076         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6077         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6078         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6079         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6080         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6081         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6082         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6083         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6084         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6085         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
6086         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
6087         testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
6088         testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
6089 
6090         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
6091         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
6092         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
6093         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
6094         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
6095         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6096         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6097         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6098         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6099         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6100         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6101         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6102         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6103         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6104         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
6105         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
6106         testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
6107         testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
6108 
6109         // Test B.C.
6110         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
6111         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
6112         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
6113         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
6114         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
6115         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
6116         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
6117         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6118         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6119         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6120         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6121         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6122         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6123         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6124         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6125         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6126         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6127         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
6128         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
6129         testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
6130         testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
6131 
6132         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
6133         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
6134         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
6135         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
6136         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6137         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6138         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6139         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6140         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6141         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6142         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6143         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6144         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6145         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6146         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
6147         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
6148         testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
6149         testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
6150 
6151         // Test Both
6152         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6153         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6154         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6155         testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6156         testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6157         testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
6158         testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
6159         testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
6160         testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
6161         testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
6162         testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
6163         testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6164         testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
6165         testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
6166 
6167         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6168         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6169         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6170         testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6171         testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6172         testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
6173         testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
6174         testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
6175         testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
6176         testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
6177         testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
6178         testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6179         testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
6180         testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887)));
6181 
6182         {
6183             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6184             (st += dur!"hnsecs"(52)) += dur!"seconds"(-907);
6185             assert(st == SysTime(DateTime(0, 12, 31, 23, 44, 53), hnsecs(51)));
6186         }
6187 
6188         auto duration = dur!"seconds"(12);
6189         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6190         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6191         static assert(!__traits(compiles, cst += duration));
6192         //static assert(!__traits(compiles, ist += duration));
6193         static assert(!__traits(compiles, cst -= duration));
6194         //static assert(!__traits(compiles, ist -= duration));
6195     }
6196 
6197 
6198     /++
6199         Gives the difference between two $(LREF SysTime)s.
6200 
6201         The legal types of arithmetic for $(LREF SysTime) using this operator
6202         are
6203 
6204         $(BOOKTABLE,
6205         $(TR $(TD SysTime) $(TD -) $(TD SysTime) $(TD -->) $(TD duration))
6206         )
6207       +/
6208     Duration opBinary(string op)(in SysTime rhs) @safe const pure nothrow
6209         if (op == "-")
6210     {
6211         return dur!"hnsecs"(_stdTime - rhs._stdTime);
6212     }
6213 
6214     @safe unittest
6215     {
6216         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1998, 7, 6, 12, 30, 33)) ==
6217                dur!"seconds"(31_536_000));
6218         assert(SysTime(DateTime(1998, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6219                dur!"seconds"(-31_536_000));
6220 
6221         assert(SysTime(DateTime(1999, 8, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6222                dur!"seconds"(26_78_400));
6223         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 8, 6, 12, 30, 33)) ==
6224                dur!"seconds"(-26_78_400));
6225 
6226         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 5, 12, 30, 33)) ==
6227                dur!"seconds"(86_400));
6228         assert(SysTime(DateTime(1999, 7, 5, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6229                dur!"seconds"(-86_400));
6230 
6231         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 11, 30, 33)) ==
6232                dur!"seconds"(3600));
6233         assert(SysTime(DateTime(1999, 7, 6, 11, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6234                dur!"seconds"(-3600));
6235 
6236         assert(SysTime(DateTime(1999, 7, 6, 12, 31, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6237                dur!"seconds"(60));
6238         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 31, 33)) ==
6239                dur!"seconds"(-60));
6240 
6241         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 34)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6242                dur!"seconds"(1));
6243         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 34)) ==
6244                dur!"seconds"(-1));
6245 
6246         {
6247             auto dt = DateTime(1999, 7, 6, 12, 30, 33);
6248             assert(SysTime(dt, msecs(532)) - SysTime(dt) == msecs(532));
6249             assert(SysTime(dt) - SysTime(dt, msecs(532)) == msecs(-532));
6250 
6251             assert(SysTime(dt, usecs(333_347)) - SysTime(dt) == usecs(333_347));
6252             assert(SysTime(dt) - SysTime(dt, usecs(333_347)) == usecs(-333_347));
6253 
6254             assert(SysTime(dt, hnsecs(1_234_567)) - SysTime(dt) == hnsecs(1_234_567));
6255             assert(SysTime(dt) - SysTime(dt, hnsecs(1_234_567)) == hnsecs(-1_234_567));
6256         }
6257 
6258         assert(SysTime(DateTime(1, 1, 1, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(45033));
6259         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(1, 1, 1, 12, 30, 33)) == dur!"seconds"(-45033));
6260         assert(SysTime(DateTime(0, 12, 31, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(-41367));
6261         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 12, 30, 33)) == dur!"seconds"(41367));
6262 
6263         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) ==
6264                dur!"hnsecs"(1));
6265         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) ==
6266                dur!"hnsecs"(-1));
6267 
6268         version (Posix)
6269             immutable tz = PosixTimeZone.getTimeZone("America/Los_Angeles");
6270         else version (Windows)
6271             immutable tz = WindowsTimeZone.getTimeZone("Pacific Standard Time");
6272 
6273         {
6274             auto dt = DateTime(2011, 1, 13, 8, 17, 2);
6275             auto d = msecs(296);
6276             assert(SysTime(dt, d, tz) - SysTime(dt, d, tz) == Duration.zero);
6277             assert(SysTime(dt, d, tz) - SysTime(dt, d, UTC()) == hours(8));
6278             assert(SysTime(dt, d, UTC()) - SysTime(dt, d, tz) == hours(-8));
6279         }
6280 
6281         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6282         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6283         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6284         assert(st - st == Duration.zero);
6285         assert(cst - st == Duration.zero);
6286         //assert(ist - st == Duration.zero);
6287 
6288         assert(st - cst == Duration.zero);
6289         assert(cst - cst == Duration.zero);
6290         //assert(ist - cst == Duration.zero);
6291 
6292         //assert(st - ist == Duration.zero);
6293         //assert(cst - ist == Duration.zero);
6294         //assert(ist - ist == Duration.zero);
6295     }
6296 
6297 
6298     /++
6299         Returns the difference between the two $(LREF SysTime)s in months.
6300 
6301         To get the difference in years, subtract the year property
6302         of two $(LREF SysTime)s. To get the difference in days or weeks,
6303         subtract the $(LREF SysTime)s themselves and use the
6304         $(REF Duration, core,time) that results. Because converting between
6305         months and smaller units requires a specific date (which
6306         $(REF Duration, core,time)s don't have), getting the difference in
6307         months requires some math using both the year and month properties, so
6308         this is a convenience function for getting the difference in months.
6309 
6310         Note that the number of days in the months or how far into the month
6311         either date is is irrelevant. It is the difference in the month property
6312         combined with the difference in years * 12. So, for instance,
6313         December 31st and January 1st are one month apart just as December 1st
6314         and January 31st are one month apart.
6315 
6316         Params:
6317             rhs = The $(LREF SysTime) to subtract from this one.
6318       +/
6319     int diffMonths(in SysTime rhs) @safe const nothrow
6320     {
6321         return (cast(Date) this).diffMonths(cast(Date) rhs);
6322     }
6323 
6324     ///
6325     @safe unittest
6326     {
6327         import std.datetime.date : Date;
6328 
6329         assert(SysTime(Date(1999, 2, 1)).diffMonths(
6330                    SysTime(Date(1999, 1, 31))) == 1);
6331 
6332         assert(SysTime(Date(1999, 1, 31)).diffMonths(
6333                    SysTime(Date(1999, 2, 1))) == -1);
6334 
6335         assert(SysTime(Date(1999, 3, 1)).diffMonths(
6336                    SysTime(Date(1999, 1, 1))) == 2);
6337 
6338         assert(SysTime(Date(1999, 1, 1)).diffMonths(
6339                    SysTime(Date(1999, 3, 31))) == -2);
6340     }
6341 
6342     @safe unittest
6343     {
6344         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6345         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6346         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6347         assert(st.diffMonths(st) == 0);
6348         assert(cst.diffMonths(st) == 0);
6349         //assert(ist.diffMonths(st) == 0);
6350 
6351         assert(st.diffMonths(cst) == 0);
6352         assert(cst.diffMonths(cst) == 0);
6353         //assert(ist.diffMonths(cst) == 0);
6354 
6355         //assert(st.diffMonths(ist) == 0);
6356         //assert(cst.diffMonths(ist) == 0);
6357         //assert(ist.diffMonths(ist) == 0);
6358     }
6359 
6360 
6361     /++
6362         Whether this $(LREF SysTime) is in a leap year.
6363      +/
6364     @property bool isLeapYear() @safe const nothrow
6365     {
6366         return (cast(Date) this).isLeapYear;
6367     }
6368 
6369     @safe unittest
6370     {
6371         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6372         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6373         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6374         assert(!st.isLeapYear);
6375         assert(!cst.isLeapYear);
6376         //assert(!ist.isLeapYear);
6377     }
6378 
6379 
6380     /++
6381         Day of the week this $(LREF SysTime) is on.
6382       +/
6383     @property DayOfWeek dayOfWeek() @safe const nothrow
6384     {
6385         return getDayOfWeek(dayOfGregorianCal);
6386     }
6387 
6388     @safe unittest
6389     {
6390         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6391         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6392         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6393         assert(st.dayOfWeek == DayOfWeek.tue);
6394         assert(cst.dayOfWeek == DayOfWeek.tue);
6395         //assert(ist.dayOfWeek == DayOfWeek.tue);
6396     }
6397 
6398 
6399     /++
6400         Day of the year this $(LREF SysTime) is on.
6401       +/
6402     @property ushort dayOfYear() @safe const nothrow
6403     {
6404         return (cast(Date) this).dayOfYear;
6405     }
6406 
6407     ///
6408     @safe unittest
6409     {
6410         import std.datetime.date : DateTime;
6411 
6412         assert(SysTime(DateTime(1999, 1, 1, 12, 22, 7)).dayOfYear == 1);
6413         assert(SysTime(DateTime(1999, 12, 31, 7, 2, 59)).dayOfYear == 365);
6414         assert(SysTime(DateTime(2000, 12, 31, 21, 20, 0)).dayOfYear == 366);
6415     }
6416 
6417     @safe unittest
6418     {
6419         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6420         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6421         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6422         assert(st.dayOfYear == 187);
6423         assert(cst.dayOfYear == 187);
6424         //assert(ist.dayOfYear == 187);
6425     }
6426 
6427 
6428     /++
6429         Day of the year.
6430 
6431         Params:
6432             day = The day of the year to set which day of the year this
6433                   $(LREF SysTime) is on.
6434       +/
6435     @property void dayOfYear(int day) @safe
6436     {
6437         immutable hnsecs = adjTime;
6438         immutable days = convert!("hnsecs", "days")(hnsecs);
6439         immutable theRest = hnsecs - convert!("days", "hnsecs")(days);
6440 
6441         auto date = Date(cast(int) days);
6442         date.dayOfYear = day;
6443 
6444         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
6445 
6446         adjTime = newDaysHNSecs + theRest;
6447     }
6448 
6449     @safe unittest
6450     {
6451         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6452         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6453         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6454         st.dayOfYear = 12;
6455         assert(st.dayOfYear == 12);
6456         static assert(!__traits(compiles, cst.dayOfYear = 12));
6457         //static assert(!__traits(compiles, ist.dayOfYear = 12));
6458     }
6459 
6460 
6461     /++
6462         The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on.
6463      +/
6464     @property int dayOfGregorianCal() @safe const nothrow
6465     {
6466         immutable adjustedTime = adjTime;
6467 
6468         // We have to add one because 0 would be midnight, January 1st, 1 A.D.,
6469         // which would be the 1st day of the Gregorian Calendar, not the 0th. So,
6470         // simply casting to days is one day off.
6471         if (adjustedTime > 0)
6472             return cast(int) getUnitsFromHNSecs!"days"(adjustedTime) + 1;
6473 
6474         long hnsecs = adjustedTime;
6475         immutable days = cast(int) splitUnitsFromHNSecs!"days"(hnsecs);
6476 
6477         return hnsecs == 0 ? days + 1 : days;
6478     }
6479 
6480     ///
6481     @safe unittest
6482     {
6483         import std.datetime.date : DateTime;
6484 
6485         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
6486         assert(SysTime(DateTime(1, 12, 31, 23, 59, 59)).dayOfGregorianCal == 365);
6487         assert(SysTime(DateTime(2, 1, 1, 2, 2, 2)).dayOfGregorianCal == 366);
6488 
6489         assert(SysTime(DateTime(0, 12, 31, 7, 7, 7)).dayOfGregorianCal == 0);
6490         assert(SysTime(DateTime(0, 1, 1, 19, 30, 0)).dayOfGregorianCal == -365);
6491         assert(SysTime(DateTime(-1, 12, 31, 4, 7, 0)).dayOfGregorianCal == -366);
6492 
6493         assert(SysTime(DateTime(2000, 1, 1, 9, 30, 20)).dayOfGregorianCal == 730_120);
6494         assert(SysTime(DateTime(2010, 12, 31, 15, 45, 50)).dayOfGregorianCal == 734_137);
6495     }
6496 
6497     @safe unittest
6498     {
6499         // Test A.D.
6500         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
6501         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 1);
6502         assert(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 1);
6503 
6504         assert(SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1);
6505         assert(SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)).dayOfGregorianCal == 2);
6506         assert(SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 32);
6507         assert(SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 366);
6508         assert(SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 731);
6509         assert(SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1096);
6510         assert(SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1462);
6511         assert(SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 17_898);
6512         assert(SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 35_065);
6513         assert(SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_160);
6514         assert(SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_525);
6515         assert(SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 37_986);
6516         assert(SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 72_684);
6517         assert(SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 73_049);
6518         assert(SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_208);
6519         assert(SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_573);
6520         assert(SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 145_732);
6521         assert(SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 146_098);
6522         assert(SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_257);
6523         assert(SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_622);
6524         assert(SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 364_878);
6525         assert(SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 365_243);
6526         assert(SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_023);
6527         assert(SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_389);
6528         assert(SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_596);
6529         assert(SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_961);
6530         assert(SysTime(DateTime(1945, 11, 12, 12, 2, 9), msecs(212)).dayOfGregorianCal == 710_347);
6531         assert(SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 729_755);
6532         assert(SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_120);
6533         assert(SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_486);
6534 
6535         assert(SysTime(DateTime(2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_773);
6536         assert(SysTime(DateTime(2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_803);
6537         assert(SysTime(DateTime(2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_804);
6538         assert(SysTime(DateTime(2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_831);
6539         assert(SysTime(DateTime(2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_832);
6540         assert(SysTime(DateTime(2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_862);
6541         assert(SysTime(DateTime(2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_863);
6542         assert(SysTime(DateTime(2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_892);
6543         assert(SysTime(DateTime(2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_893);
6544         assert(SysTime(DateTime(2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_923);
6545         assert(SysTime(DateTime(2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_924);
6546         assert(SysTime(DateTime(2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_953);
6547         assert(SysTime(DateTime(2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_954);
6548         assert(SysTime(DateTime(2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_984);
6549         assert(SysTime(DateTime(2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_985);
6550         assert(SysTime(DateTime(2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_015);
6551         assert(SysTime(DateTime(2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_016);
6552         assert(SysTime(DateTime(2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_045);
6553         assert(SysTime(DateTime(2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_046);
6554         assert(SysTime(DateTime(2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_076);
6555         assert(SysTime(DateTime(2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_077);
6556         assert(SysTime(DateTime(2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_106);
6557         assert(SysTime(DateTime(2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_107);
6558         assert(SysTime(DateTime(2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_137);
6559 
6560         assert(SysTime(DateTime(2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == 734_534);
6561         assert(SysTime(DateTime(2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == 734_561);
6562         assert(SysTime(DateTime(2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == 734_562);
6563         assert(SysTime(DateTime(2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == 734_563);
6564 
6565         // Test B.C.
6566         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 0);
6567         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == 0);
6568         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59)).dayOfGregorianCal == 0);
6569         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 0);
6570         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).dayOfGregorianCal == 0);
6571 
6572         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == -366);
6573         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == -366);
6574         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59)).dayOfGregorianCal == -366);
6575         assert(SysTime(DateTime(-1, 12, 31, 0, 0, 0)).dayOfGregorianCal == -366);
6576 
6577         assert(SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == 0);
6578         assert(SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1);
6579         assert(SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -30);
6580         assert(SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -31);
6581 
6582         assert(SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -366);
6583         assert(SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -367);
6584         assert(SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730);
6585         assert(SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731);
6586         assert(SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1095);
6587         assert(SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1096);
6588         assert(SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1460);
6589         assert(SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1461);
6590         assert(SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1826);
6591         assert(SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1827);
6592         assert(SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -2191);
6593         assert(SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -3652);
6594 
6595         assert(SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_262);
6596         assert(SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_627);
6597         assert(SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -35_794);
6598         assert(SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_160);
6599         assert(SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_524);
6600         assert(SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_889);
6601         assert(SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -37_254);
6602         assert(SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -38_715);
6603         assert(SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_413);
6604         assert(SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_778);
6605         assert(SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -109_937);
6606         assert(SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -110_302);
6607         assert(SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_097);
6608         assert(SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_462);
6609         assert(SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_827);
6610         assert(SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_621);
6611         assert(SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_986);
6612         assert(SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -183_351);
6613         assert(SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_607);
6614         assert(SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_972);
6615         assert(SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_387);
6616         assert(SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_388);
6617         assert(SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_753);
6618         assert(SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -585_118);
6619         assert(SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_325);
6620         assert(SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_690);
6621         assert(SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_484);
6622         assert(SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_485);
6623         assert(SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_850);
6624         assert(SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731_215);
6625 
6626         assert(SysTime(DateTime(-2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_502);
6627         assert(SysTime(DateTime(-2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_472);
6628         assert(SysTime(DateTime(-2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_471);
6629         assert(SysTime(DateTime(-2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_444);
6630         assert(SysTime(DateTime(-2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_443);
6631         assert(SysTime(DateTime(-2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_413);
6632         assert(SysTime(DateTime(-2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_412);
6633         assert(SysTime(DateTime(-2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_383);
6634         assert(SysTime(DateTime(-2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_382);
6635         assert(SysTime(DateTime(-2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_352);
6636         assert(SysTime(DateTime(-2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_351);
6637         assert(SysTime(DateTime(-2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_322);
6638         assert(SysTime(DateTime(-2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_321);
6639         assert(SysTime(DateTime(-2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_291);
6640         assert(SysTime(DateTime(-2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_290);
6641         assert(SysTime(DateTime(-2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_260);
6642         assert(SysTime(DateTime(-2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_259);
6643         assert(SysTime(DateTime(-2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_230);
6644         assert(SysTime(DateTime(-2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_229);
6645         assert(SysTime(DateTime(-2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_199);
6646         assert(SysTime(DateTime(-2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_198);
6647         assert(SysTime(DateTime(-2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_169);
6648         assert(SysTime(DateTime(-2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_168);
6649         assert(SysTime(DateTime(-2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_138);
6650 
6651         assert(SysTime(DateTime(-2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == -735_202);
6652         assert(SysTime(DateTime(-2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == -735_175);
6653         assert(SysTime(DateTime(-2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == -735_174);
6654         assert(SysTime(DateTime(-2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == -735_173);
6655 
6656         // Start of Hebrew Calendar
6657         assert(SysTime(DateTime(-3760, 9, 7, 0, 0, 0)).dayOfGregorianCal == -1_373_427);
6658 
6659         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6660         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6661         assert(cst.dayOfGregorianCal == 729_941);
6662         //assert(ist.dayOfGregorianCal == 729_941);
6663     }
6664 
6665 
6666     // Test that the logic for the day of the Gregorian Calendar is consistent
6667     // between Date and SysTime.
6668     @safe unittest
6669     {
6670         void test(Date date, SysTime st, size_t line = __LINE__)
6671         {
6672             if (date.dayOfGregorianCal != st.dayOfGregorianCal)
6673             {
6674                 throw new AssertError(format("Date [%s] SysTime [%s]", date.dayOfGregorianCal, st.dayOfGregorianCal),
6675                                       __FILE__, line);
6676             }
6677         }
6678 
6679         // Test A.D.
6680         test(Date(1, 1, 1), SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6681         test(Date(1, 1, 2), SysTime(DateTime(1, 1, 2, 0, 0, 0), hnsecs(500)));
6682         test(Date(1, 2, 1), SysTime(DateTime(1, 2, 1, 0, 0, 0), hnsecs(50_000)));
6683         test(Date(2, 1, 1), SysTime(DateTime(2, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6684         test(Date(3, 1, 1), SysTime(DateTime(3, 1, 1, 12, 13, 14)));
6685         test(Date(4, 1, 1), SysTime(DateTime(4, 1, 1, 12, 13, 14), hnsecs(500)));
6686         test(Date(5, 1, 1), SysTime(DateTime(5, 1, 1, 12, 13, 14), hnsecs(50_000)));
6687         test(Date(50, 1, 1), SysTime(DateTime(50, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
6688         test(Date(97, 1, 1), SysTime(DateTime(97, 1, 1, 23, 59, 59)));
6689         test(Date(100, 1, 1), SysTime(DateTime(100, 1, 1, 23, 59, 59), hnsecs(500)));
6690         test(Date(101, 1, 1), SysTime(DateTime(101, 1, 1, 23, 59, 59), hnsecs(50_000)));
6691         test(Date(105, 1, 1), SysTime(DateTime(105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
6692         test(Date(200, 1, 1), SysTime(DateTime(200, 1, 1, 0, 0, 0)));
6693         test(Date(201, 1, 1), SysTime(DateTime(201, 1, 1, 0, 0, 0), hnsecs(500)));
6694         test(Date(300, 1, 1), SysTime(DateTime(300, 1, 1, 0, 0, 0), hnsecs(50_000)));
6695         test(Date(301, 1, 1), SysTime(DateTime(301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6696         test(Date(400, 1, 1), SysTime(DateTime(400, 1, 1, 12, 13, 14)));
6697         test(Date(401, 1, 1), SysTime(DateTime(401, 1, 1, 12, 13, 14), hnsecs(500)));
6698         test(Date(500, 1, 1), SysTime(DateTime(500, 1, 1, 12, 13, 14), hnsecs(50_000)));
6699         test(Date(501, 1, 1), SysTime(DateTime(501, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
6700         test(Date(1000, 1, 1), SysTime(DateTime(1000, 1, 1, 23, 59, 59)));
6701         test(Date(1001, 1, 1), SysTime(DateTime(1001, 1, 1, 23, 59, 59), hnsecs(500)));
6702         test(Date(1600, 1, 1), SysTime(DateTime(1600, 1, 1, 23, 59, 59), hnsecs(50_000)));
6703         test(Date(1601, 1, 1), SysTime(DateTime(1601, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
6704         test(Date(1900, 1, 1), SysTime(DateTime(1900, 1, 1, 0, 0, 0)));
6705         test(Date(1901, 1, 1), SysTime(DateTime(1901, 1, 1, 0, 0, 0), hnsecs(500)));
6706         test(Date(1945, 11, 12), SysTime(DateTime(1945, 11, 12, 0, 0, 0), hnsecs(50_000)));
6707         test(Date(1999, 1, 1), SysTime(DateTime(1999, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6708         test(Date(1999, 7, 6), SysTime(DateTime(1999, 7, 6, 12, 13, 14)));
6709         test(Date(2000, 1, 1), SysTime(DateTime(2000, 1, 1, 12, 13, 14), hnsecs(500)));
6710         test(Date(2001, 1, 1), SysTime(DateTime(2001, 1, 1, 12, 13, 14), hnsecs(50_000)));
6711 
6712         test(Date(2010, 1, 1), SysTime(DateTime(2010, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
6713         test(Date(2010, 1, 31), SysTime(DateTime(2010, 1, 31, 23, 0, 0)));
6714         test(Date(2010, 2, 1), SysTime(DateTime(2010, 2, 1, 23, 59, 59), hnsecs(500)));
6715         test(Date(2010, 2, 28), SysTime(DateTime(2010, 2, 28, 23, 59, 59), hnsecs(50_000)));
6716         test(Date(2010, 3, 1), SysTime(DateTime(2010, 3, 1, 23, 59, 59), hnsecs(9_999_999)));
6717         test(Date(2010, 3, 31), SysTime(DateTime(2010, 3, 31, 0, 0, 0)));
6718         test(Date(2010, 4, 1), SysTime(DateTime(2010, 4, 1, 0, 0, 0), hnsecs(500)));
6719         test(Date(2010, 4, 30), SysTime(DateTime(2010, 4, 30, 0, 0, 0), hnsecs(50_000)));
6720         test(Date(2010, 5, 1), SysTime(DateTime(2010, 5, 1, 0, 0, 0), hnsecs(9_999_999)));
6721         test(Date(2010, 5, 31), SysTime(DateTime(2010, 5, 31, 12, 13, 14)));
6722         test(Date(2010, 6, 1), SysTime(DateTime(2010, 6, 1, 12, 13, 14), hnsecs(500)));
6723         test(Date(2010, 6, 30), SysTime(DateTime(2010, 6, 30, 12, 13, 14), hnsecs(50_000)));
6724         test(Date(2010, 7, 1), SysTime(DateTime(2010, 7, 1, 12, 13, 14), hnsecs(9_999_999)));
6725         test(Date(2010, 7, 31), SysTime(DateTime(2010, 7, 31, 23, 59, 59)));
6726         test(Date(2010, 8, 1), SysTime(DateTime(2010, 8, 1, 23, 59, 59), hnsecs(500)));
6727         test(Date(2010, 8, 31), SysTime(DateTime(2010, 8, 31, 23, 59, 59), hnsecs(50_000)));
6728         test(Date(2010, 9, 1), SysTime(DateTime(2010, 9, 1, 23, 59, 59), hnsecs(9_999_999)));
6729         test(Date(2010, 9, 30), SysTime(DateTime(2010, 9, 30, 12, 0, 0)));
6730         test(Date(2010, 10, 1), SysTime(DateTime(2010, 10, 1, 0, 12, 0), hnsecs(500)));
6731         test(Date(2010, 10, 31), SysTime(DateTime(2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
6732         test(Date(2010, 11, 1), SysTime(DateTime(2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
6733         test(Date(2010, 11, 30), SysTime(DateTime(2010, 11, 30, 0, 59, 0)));
6734         test(Date(2010, 12, 1), SysTime(DateTime(2010, 12, 1, 0, 0, 59), hnsecs(500)));
6735         test(Date(2010, 12, 31), SysTime(DateTime(2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
6736 
6737         test(Date(2012, 2, 1), SysTime(DateTime(2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
6738         test(Date(2012, 2, 28), SysTime(DateTime(2012, 2, 28, 23, 59, 0)));
6739         test(Date(2012, 2, 29), SysTime(DateTime(2012, 2, 29, 7, 7, 7), hnsecs(7)));
6740         test(Date(2012, 3, 1), SysTime(DateTime(2012, 3, 1, 7, 7, 7), hnsecs(7)));
6741 
6742         // Test B.C.
6743         test(Date(0, 12, 31), SysTime(DateTime(0, 12, 31, 0, 0, 0)));
6744         test(Date(0, 12, 30), SysTime(DateTime(0, 12, 30, 0, 0, 0), hnsecs(500)));
6745         test(Date(0, 12, 1), SysTime(DateTime(0, 12, 1, 0, 0, 0), hnsecs(50_000)));
6746         test(Date(0, 11, 30), SysTime(DateTime(0, 11, 30, 0, 0, 0), hnsecs(9_999_999)));
6747 
6748         test(Date(-1, 12, 31), SysTime(DateTime(-1, 12, 31, 12, 13, 14)));
6749         test(Date(-1, 12, 30), SysTime(DateTime(-1, 12, 30, 12, 13, 14), hnsecs(500)));
6750         test(Date(-1, 1, 1), SysTime(DateTime(-1, 1, 1, 12, 13, 14), hnsecs(50_000)));
6751         test(Date(-2, 12, 31), SysTime(DateTime(-2, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
6752         test(Date(-2, 1, 1), SysTime(DateTime(-2, 1, 1, 23, 59, 59)));
6753         test(Date(-3, 12, 31), SysTime(DateTime(-3, 12, 31, 23, 59, 59), hnsecs(500)));
6754         test(Date(-3, 1, 1), SysTime(DateTime(-3, 1, 1, 23, 59, 59), hnsecs(50_000)));
6755         test(Date(-4, 12, 31), SysTime(DateTime(-4, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6756         test(Date(-4, 1, 1), SysTime(DateTime(-4, 1, 1, 0, 0, 0)));
6757         test(Date(-5, 12, 31), SysTime(DateTime(-5, 12, 31, 0, 0, 0), hnsecs(500)));
6758         test(Date(-5, 1, 1), SysTime(DateTime(-5, 1, 1, 0, 0, 0), hnsecs(50_000)));
6759         test(Date(-9, 1, 1), SysTime(DateTime(-9, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6760 
6761         test(Date(-49, 1, 1), SysTime(DateTime(-49, 1, 1, 12, 13, 14)));
6762         test(Date(-50, 1, 1), SysTime(DateTime(-50, 1, 1, 12, 13, 14), hnsecs(500)));
6763         test(Date(-97, 1, 1), SysTime(DateTime(-97, 1, 1, 12, 13, 14), hnsecs(50_000)));
6764         test(Date(-99, 12, 31), SysTime(DateTime(-99, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
6765         test(Date(-99, 1, 1), SysTime(DateTime(-99, 1, 1, 23, 59, 59)));
6766         test(Date(-100, 1, 1), SysTime(DateTime(-100, 1, 1, 23, 59, 59), hnsecs(500)));
6767         test(Date(-101, 1, 1), SysTime(DateTime(-101, 1, 1, 23, 59, 59), hnsecs(50_000)));
6768         test(Date(-105, 1, 1), SysTime(DateTime(-105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
6769         test(Date(-200, 1, 1), SysTime(DateTime(-200, 1, 1, 0, 0, 0)));
6770         test(Date(-201, 1, 1), SysTime(DateTime(-201, 1, 1, 0, 0, 0), hnsecs(500)));
6771         test(Date(-300, 1, 1), SysTime(DateTime(-300, 1, 1, 0, 0, 0), hnsecs(50_000)));
6772         test(Date(-301, 1, 1), SysTime(DateTime(-301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6773         test(Date(-400, 12, 31), SysTime(DateTime(-400, 12, 31, 12, 13, 14)));
6774         test(Date(-400, 1, 1), SysTime(DateTime(-400, 1, 1, 12, 13, 14), hnsecs(500)));
6775         test(Date(-401, 1, 1), SysTime(DateTime(-401, 1, 1, 12, 13, 14), hnsecs(50_000)));
6776         test(Date(-499, 1, 1), SysTime(DateTime(-499, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
6777         test(Date(-500, 1, 1), SysTime(DateTime(-500, 1, 1, 23, 59, 59)));
6778         test(Date(-501, 1, 1), SysTime(DateTime(-501, 1, 1, 23, 59, 59), hnsecs(500)));
6779         test(Date(-1000, 1, 1), SysTime(DateTime(-1000, 1, 1, 23, 59, 59), hnsecs(50_000)));
6780         test(Date(-1001, 1, 1), SysTime(DateTime(-1001, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
6781         test(Date(-1599, 1, 1), SysTime(DateTime(-1599, 1, 1, 0, 0, 0)));
6782         test(Date(-1600, 12, 31), SysTime(DateTime(-1600, 12, 31, 0, 0, 0), hnsecs(500)));
6783         test(Date(-1600, 1, 1), SysTime(DateTime(-1600, 1, 1, 0, 0, 0), hnsecs(50_000)));
6784         test(Date(-1601, 1, 1), SysTime(DateTime(-1601, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6785         test(Date(-1900, 1, 1), SysTime(DateTime(-1900, 1, 1, 12, 13, 14)));
6786         test(Date(-1901, 1, 1), SysTime(DateTime(-1901, 1, 1, 12, 13, 14), hnsecs(500)));
6787         test(Date(-1999, 1, 1), SysTime(DateTime(-1999, 1, 1, 12, 13, 14), hnsecs(50_000)));
6788         test(Date(-1999, 7, 6), SysTime(DateTime(-1999, 7, 6, 12, 13, 14), hnsecs(9_999_999)));
6789         test(Date(-2000, 12, 31), SysTime(DateTime(-2000, 12, 31, 23, 59, 59)));
6790         test(Date(-2000, 1, 1), SysTime(DateTime(-2000, 1, 1, 23, 59, 59), hnsecs(500)));
6791         test(Date(-2001, 1, 1), SysTime(DateTime(-2001, 1, 1, 23, 59, 59), hnsecs(50_000)));
6792 
6793         test(Date(-2010, 1, 1), SysTime(DateTime(-2010, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
6794         test(Date(-2010, 1, 31), SysTime(DateTime(-2010, 1, 31, 0, 0, 0)));
6795         test(Date(-2010, 2, 1), SysTime(DateTime(-2010, 2, 1, 0, 0, 0), hnsecs(500)));
6796         test(Date(-2010, 2, 28), SysTime(DateTime(-2010, 2, 28, 0, 0, 0), hnsecs(50_000)));
6797         test(Date(-2010, 3, 1), SysTime(DateTime(-2010, 3, 1, 0, 0, 0), hnsecs(9_999_999)));
6798         test(Date(-2010, 3, 31), SysTime(DateTime(-2010, 3, 31, 12, 13, 14)));
6799         test(Date(-2010, 4, 1), SysTime(DateTime(-2010, 4, 1, 12, 13, 14), hnsecs(500)));
6800         test(Date(-2010, 4, 30), SysTime(DateTime(-2010, 4, 30, 12, 13, 14), hnsecs(50_000)));
6801         test(Date(-2010, 5, 1), SysTime(DateTime(-2010, 5, 1, 12, 13, 14), hnsecs(9_999_999)));
6802         test(Date(-2010, 5, 31), SysTime(DateTime(-2010, 5, 31, 23, 59, 59)));
6803         test(Date(-2010, 6, 1), SysTime(DateTime(-2010, 6, 1, 23, 59, 59), hnsecs(500)));
6804         test(Date(-2010, 6, 30), SysTime(DateTime(-2010, 6, 30, 23, 59, 59), hnsecs(50_000)));
6805         test(Date(-2010, 7, 1), SysTime(DateTime(-2010, 7, 1, 23, 59, 59), hnsecs(9_999_999)));
6806         test(Date(-2010, 7, 31), SysTime(DateTime(-2010, 7, 31, 0, 0, 0)));
6807         test(Date(-2010, 8, 1), SysTime(DateTime(-2010, 8, 1, 0, 0, 0), hnsecs(500)));
6808         test(Date(-2010, 8, 31), SysTime(DateTime(-2010, 8, 31, 0, 0, 0), hnsecs(50_000)));
6809         test(Date(-2010, 9, 1), SysTime(DateTime(-2010, 9, 1, 0, 0, 0), hnsecs(9_999_999)));
6810         test(Date(-2010, 9, 30), SysTime(DateTime(-2010, 9, 30, 12, 0, 0)));
6811         test(Date(-2010, 10, 1), SysTime(DateTime(-2010, 10, 1, 0, 12, 0), hnsecs(500)));
6812         test(Date(-2010, 10, 31), SysTime(DateTime(-2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
6813         test(Date(-2010, 11, 1), SysTime(DateTime(-2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
6814         test(Date(-2010, 11, 30), SysTime(DateTime(-2010, 11, 30, 0, 59, 0)));
6815         test(Date(-2010, 12, 1), SysTime(DateTime(-2010, 12, 1, 0, 0, 59), hnsecs(500)));
6816         test(Date(-2010, 12, 31), SysTime(DateTime(-2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
6817 
6818         test(Date(-2012, 2, 1), SysTime(DateTime(-2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
6819         test(Date(-2012, 2, 28), SysTime(DateTime(-2012, 2, 28, 23, 59, 0)));
6820         test(Date(-2012, 2, 29), SysTime(DateTime(-2012, 2, 29, 7, 7, 7), hnsecs(7)));
6821         test(Date(-2012, 3, 1), SysTime(DateTime(-2012, 3, 1, 7, 7, 7), hnsecs(7)));
6822 
6823         test(Date(-3760, 9, 7), SysTime(DateTime(-3760, 9, 7, 0, 0, 0)));
6824     }
6825 
6826 
6827     /++
6828         The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on.
6829         Setting this property does not affect the time portion of $(LREF SysTime).
6830 
6831         Params:
6832             days = The day of the Gregorian Calendar to set this $(LREF SysTime)
6833                    to.
6834      +/
6835     @property void dayOfGregorianCal(int days) @safe nothrow
6836     {
6837         auto hnsecs = adjTime;
6838         hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
6839 
6840         if (hnsecs < 0)
6841             hnsecs += convert!("hours", "hnsecs")(24);
6842 
6843         if (--days < 0)
6844         {
6845             hnsecs -= convert!("hours", "hnsecs")(24);
6846             ++days;
6847         }
6848 
6849         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
6850 
6851         adjTime = newDaysHNSecs + hnsecs;
6852     }
6853 
6854     ///
6855     @safe unittest
6856     {
6857         import std.datetime.date : DateTime;
6858 
6859         auto st = SysTime(DateTime(0, 1, 1, 12, 0, 0));
6860         st.dayOfGregorianCal = 1;
6861         assert(st == SysTime(DateTime(1, 1, 1, 12, 0, 0)));
6862 
6863         st.dayOfGregorianCal = 365;
6864         assert(st == SysTime(DateTime(1, 12, 31, 12, 0, 0)));
6865 
6866         st.dayOfGregorianCal = 366;
6867         assert(st == SysTime(DateTime(2, 1, 1, 12, 0, 0)));
6868 
6869         st.dayOfGregorianCal = 0;
6870         assert(st == SysTime(DateTime(0, 12, 31, 12, 0, 0)));
6871 
6872         st.dayOfGregorianCal = -365;
6873         assert(st == SysTime(DateTime(-0, 1, 1, 12, 0, 0)));
6874 
6875         st.dayOfGregorianCal = -366;
6876         assert(st == SysTime(DateTime(-1, 12, 31, 12, 0, 0)));
6877 
6878         st.dayOfGregorianCal = 730_120;
6879         assert(st == SysTime(DateTime(2000, 1, 1, 12, 0, 0)));
6880 
6881         st.dayOfGregorianCal = 734_137;
6882         assert(st == SysTime(DateTime(2010, 12, 31, 12, 0, 0)));
6883     }
6884 
6885     @safe unittest
6886     {
6887         void testST(SysTime orig, int day, in SysTime expected, size_t line = __LINE__)
6888         {
6889             orig.dayOfGregorianCal = day;
6890             if (orig != expected)
6891                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
6892         }
6893 
6894         // Test A.D.
6895         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6896         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6897         testST(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 1,
6898                SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
6899 
6900         // Test B.C.
6901         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
6902         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 0,
6903                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6904         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(1)), 0,
6905                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
6906         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6907 
6908         // Test Both.
6909         testST(SysTime(DateTime(-512, 7, 20, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6910         testST(SysTime(DateTime(-513, 6, 6, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6911         testST(SysTime(DateTime(-511, 5, 7, 23, 59, 59), hnsecs(9_999_999)), 1,
6912                SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
6913 
6914         testST(SysTime(DateTime(1607, 4, 8, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
6915         testST(SysTime(DateTime(1500, 3, 9, 23, 59, 59), hnsecs(9_999_999)), 0,
6916                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6917         testST(SysTime(DateTime(999, 2, 10, 23, 59, 59), hnsecs(1)), 0,
6918                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
6919         testST(SysTime(DateTime(2007, 12, 11, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6920 
6921 
6922         auto st = SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212));
6923 
6924         void testST2(int day, in SysTime expected, size_t line = __LINE__)
6925         {
6926             st.dayOfGregorianCal = day;
6927             if (st != expected)
6928                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", st, expected), __FILE__, line);
6929         }
6930 
6931         // Test A.D.
6932         testST2(1, SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)));
6933         testST2(2, SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)));
6934         testST2(32, SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)));
6935         testST2(366, SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)));
6936         testST2(731, SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)));
6937         testST2(1096, SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)));
6938         testST2(1462, SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)));
6939         testST2(17_898, SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)));
6940         testST2(35_065, SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)));
6941         testST2(36_160, SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)));
6942         testST2(36_525, SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)));
6943         testST2(37_986, SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)));
6944         testST2(72_684, SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)));
6945         testST2(73_049, SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)));
6946         testST2(109_208, SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)));
6947         testST2(109_573, SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)));
6948         testST2(145_732, SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)));
6949         testST2(146_098, SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)));
6950         testST2(182_257, SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)));
6951         testST2(182_622, SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)));
6952         testST2(364_878, SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)));
6953         testST2(365_243, SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)));
6954         testST2(584_023, SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)));
6955         testST2(584_389, SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)));
6956         testST2(693_596, SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)));
6957         testST2(693_961, SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)));
6958         testST2(729_755, SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)));
6959         testST2(730_120, SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)));
6960         testST2(730_486, SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)));
6961 
6962         testST2(733_773, SysTime(DateTime(2010, 1, 1, 12, 2, 9), msecs(212)));
6963         testST2(733_803, SysTime(DateTime(2010, 1, 31, 12, 2, 9), msecs(212)));
6964         testST2(733_804, SysTime(DateTime(2010, 2, 1, 12, 2, 9), msecs(212)));
6965         testST2(733_831, SysTime(DateTime(2010, 2, 28, 12, 2, 9), msecs(212)));
6966         testST2(733_832, SysTime(DateTime(2010, 3, 1, 12, 2, 9), msecs(212)));
6967         testST2(733_862, SysTime(DateTime(2010, 3, 31, 12, 2, 9), msecs(212)));
6968         testST2(733_863, SysTime(DateTime(2010, 4, 1, 12, 2, 9), msecs(212)));
6969         testST2(733_892, SysTime(DateTime(2010, 4, 30, 12, 2, 9), msecs(212)));
6970         testST2(733_893, SysTime(DateTime(2010, 5, 1, 12, 2, 9), msecs(212)));
6971         testST2(733_923, SysTime(DateTime(2010, 5, 31, 12, 2, 9), msecs(212)));
6972         testST2(733_924, SysTime(DateTime(2010, 6, 1, 12, 2, 9), msecs(212)));
6973         testST2(733_953, SysTime(DateTime(2010, 6, 30, 12, 2, 9), msecs(212)));
6974         testST2(733_954, SysTime(DateTime(2010, 7, 1, 12, 2, 9), msecs(212)));
6975         testST2(733_984, SysTime(DateTime(2010, 7, 31, 12, 2, 9), msecs(212)));
6976         testST2(733_985, SysTime(DateTime(2010, 8, 1, 12, 2, 9), msecs(212)));
6977         testST2(734_015, SysTime(DateTime(2010, 8, 31, 12, 2, 9), msecs(212)));
6978         testST2(734_016, SysTime(DateTime(2010, 9, 1, 12, 2, 9), msecs(212)));
6979         testST2(734_045, SysTime(DateTime(2010, 9, 30, 12, 2, 9), msecs(212)));
6980         testST2(734_046, SysTime(DateTime(2010, 10, 1, 12, 2, 9), msecs(212)));
6981         testST2(734_076, SysTime(DateTime(2010, 10, 31, 12, 2, 9), msecs(212)));
6982         testST2(734_077, SysTime(DateTime(2010, 11, 1, 12, 2, 9), msecs(212)));
6983         testST2(734_106, SysTime(DateTime(2010, 11, 30, 12, 2, 9), msecs(212)));
6984         testST2(734_107, SysTime(DateTime(2010, 12, 1, 12, 2, 9), msecs(212)));
6985         testST2(734_137, SysTime(DateTime(2010, 12, 31, 12, 2, 9), msecs(212)));
6986 
6987         testST2(734_534, SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
6988         testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
6989         testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
6990         testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
6991 
6992         testST2(734_534,  SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
6993 
6994         testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
6995         testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
6996         testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
6997 
6998         // Test B.C.
6999         testST2(0, SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)));
7000         testST2(-1, SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)));
7001         testST2(-30, SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)));
7002         testST2(-31, SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)));
7003 
7004         testST2(-366, SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)));
7005         testST2(-367, SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)));
7006         testST2(-730, SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)));
7007         testST2(-731, SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)));
7008         testST2(-1095, SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)));
7009         testST2(-1096, SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)));
7010         testST2(-1460, SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)));
7011         testST2(-1461, SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)));
7012         testST2(-1826, SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)));
7013         testST2(-1827, SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)));
7014         testST2(-2191, SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)));
7015         testST2(-3652, SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)));
7016 
7017         testST2(-18_262, SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)));
7018         testST2(-18_627, SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)));
7019         testST2(-35_794, SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)));
7020         testST2(-36_160, SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)));
7021         testST2(-36_524, SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)));
7022         testST2(-36_889, SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)));
7023         testST2(-37_254, SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)));
7024         testST2(-38_715, SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)));
7025         testST2(-73_413, SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)));
7026         testST2(-73_778, SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)));
7027         testST2(-109_937, SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)));
7028         testST2(-110_302, SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)));
7029         testST2(-146_097, SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)));
7030         testST2(-146_462, SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)));
7031         testST2(-146_827, SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)));
7032         testST2(-182_621, SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)));
7033         testST2(-182_986, SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)));
7034         testST2(-183_351, SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)));
7035         testST2(-365_607, SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)));
7036         testST2(-365_972, SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)));
7037         testST2(-584_387, SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)));
7038         testST2(-584_388, SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)));
7039         testST2(-584_753, SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)));
7040         testST2(-585_118, SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)));
7041         testST2(-694_325, SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)));
7042         testST2(-694_690, SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)));
7043         testST2(-730_484, SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)));
7044         testST2(-730_485, SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)));
7045         testST2(-730_850, SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)));
7046         testST2(-731_215, SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)));
7047 
7048         testST2(-734_502, SysTime(DateTime(-2010, 1, 1, 12, 2, 9), msecs(212)));
7049         testST2(-734_472, SysTime(DateTime(-2010, 1, 31, 12, 2, 9), msecs(212)));
7050         testST2(-734_471, SysTime(DateTime(-2010, 2, 1, 12, 2, 9), msecs(212)));
7051         testST2(-734_444, SysTime(DateTime(-2010, 2, 28, 12, 2, 9), msecs(212)));
7052         testST2(-734_443, SysTime(DateTime(-2010, 3, 1, 12, 2, 9), msecs(212)));
7053         testST2(-734_413, SysTime(DateTime(-2010, 3, 31, 12, 2, 9), msecs(212)));
7054         testST2(-734_412, SysTime(DateTime(-2010, 4, 1, 12, 2, 9), msecs(212)));
7055         testST2(-734_383, SysTime(DateTime(-2010, 4, 30, 12, 2, 9), msecs(212)));
7056         testST2(-734_382, SysTime(DateTime(-2010, 5, 1, 12, 2, 9), msecs(212)));
7057         testST2(-734_352, SysTime(DateTime(-2010, 5, 31, 12, 2, 9), msecs(212)));
7058         testST2(-734_351, SysTime(DateTime(-2010, 6, 1, 12, 2, 9), msecs(212)));
7059         testST2(-734_322, SysTime(DateTime(-2010, 6, 30, 12, 2, 9), msecs(212)));
7060         testST2(-734_321, SysTime(DateTime(-2010, 7, 1, 12, 2, 9), msecs(212)));
7061         testST2(-734_291, SysTime(DateTime(-2010, 7, 31, 12, 2, 9), msecs(212)));
7062         testST2(-734_290, SysTime(DateTime(-2010, 8, 1, 12, 2, 9), msecs(212)));
7063         testST2(-734_260, SysTime(DateTime(-2010, 8, 31, 12, 2, 9), msecs(212)));
7064         testST2(-734_259, SysTime(DateTime(-2010, 9, 1, 12, 2, 9), msecs(212)));
7065         testST2(-734_230, SysTime(DateTime(-2010, 9, 30, 12, 2, 9), msecs(212)));
7066         testST2(-734_229, SysTime(DateTime(-2010, 10, 1, 12, 2, 9), msecs(212)));
7067         testST2(-734_199, SysTime(DateTime(-2010, 10, 31, 12, 2, 9), msecs(212)));
7068         testST2(-734_198, SysTime(DateTime(-2010, 11, 1, 12, 2, 9), msecs(212)));
7069         testST2(-734_169, SysTime(DateTime(-2010, 11, 30, 12, 2, 9), msecs(212)));
7070         testST2(-734_168, SysTime(DateTime(-2010, 12, 1, 12, 2, 9), msecs(212)));
7071         testST2(-734_138, SysTime(DateTime(-2010, 12, 31, 12, 2, 9), msecs(212)));
7072 
7073         testST2(-735_202, SysTime(DateTime(-2012, 2, 1, 12, 2, 9), msecs(212)));
7074         testST2(-735_175, SysTime(DateTime(-2012, 2, 28, 12, 2, 9), msecs(212)));
7075         testST2(-735_174, SysTime(DateTime(-2012, 2, 29, 12, 2, 9), msecs(212)));
7076         testST2(-735_173, SysTime(DateTime(-2012, 3, 1, 12, 2, 9), msecs(212)));
7077 
7078         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7079         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7080         static assert(!__traits(compiles, cst.dayOfGregorianCal = 7));
7081         //static assert(!__traits(compiles, ist.dayOfGregorianCal = 7));
7082     }
7083 
7084 
7085     /++
7086         The ISO 8601 week of the year that this $(LREF SysTime) is in.
7087 
7088         See_Also:
7089             $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date).
7090       +/
7091     @property ubyte isoWeek() @safe const nothrow
7092     {
7093         return (cast(Date) this).isoWeek;
7094     }
7095 
7096     ///
7097     @safe unittest
7098     {
7099         import std.datetime.date : Date;
7100 
7101         auto st = SysTime(Date(1999, 7, 6));
7102         const cst = SysTime(Date(2010, 5, 1));
7103         immutable ist = SysTime(Date(2015, 10, 10));
7104 
7105         assert(st.isoWeek == 27);
7106         assert(cst.isoWeek == 17);
7107         assert(ist.isoWeek == 41);
7108     }
7109 
7110 
7111     /++
7112         $(LREF SysTime) for the last day in the month that this Date is in.
7113         The time portion of endOfMonth is always 23:59:59.9999999.
7114       +/
7115     @property SysTime endOfMonth() @safe const nothrow
7116     {
7117         immutable hnsecs = adjTime;
7118         immutable days = getUnitsFromHNSecs!"days"(hnsecs);
7119 
7120         auto date = Date(cast(int) days + 1).endOfMonth;
7121         auto newDays = date.dayOfGregorianCal - 1;
7122         long theTimeHNSecs;
7123 
7124         if (newDays < 0)
7125         {
7126             theTimeHNSecs = -1;
7127             ++newDays;
7128         }
7129         else
7130             theTimeHNSecs = convert!("days", "hnsecs")(1) - 1;
7131 
7132         immutable newDaysHNSecs = convert!("days", "hnsecs")(newDays);
7133 
7134         auto retval = SysTime(this._stdTime, this._timezone);
7135         retval.adjTime = newDaysHNSecs + theTimeHNSecs;
7136 
7137         return retval;
7138     }
7139 
7140     ///
7141     @safe unittest
7142     {
7143         import core.time : msecs, usecs, hnsecs;
7144         import std.datetime.date : DateTime;
7145 
7146         assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonth ==
7147                SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7148 
7149         assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0), msecs(24)).endOfMonth ==
7150                SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7151 
7152         assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27), usecs(5203)).endOfMonth ==
7153                SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7154 
7155         assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9), hnsecs(12345)).endOfMonth ==
7156                SysTime(DateTime(2000, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7157     }
7158 
7159     @safe unittest
7160     {
7161         // Test A.D.
7162         assert(SysTime(Date(1999, 1, 1)).endOfMonth == SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7163         assert(SysTime(Date(1999, 2, 1)).endOfMonth == SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7164         assert(SysTime(Date(2000, 2, 1)).endOfMonth == SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7165         assert(SysTime(Date(1999, 3, 1)).endOfMonth == SysTime(DateTime(1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
7166         assert(SysTime(Date(1999, 4, 1)).endOfMonth == SysTime(DateTime(1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
7167         assert(SysTime(Date(1999, 5, 1)).endOfMonth == SysTime(DateTime(1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
7168         assert(SysTime(Date(1999, 6, 1)).endOfMonth == SysTime(DateTime(1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7169         assert(SysTime(Date(1999, 7, 1)).endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7170         assert(SysTime(Date(1999, 8, 1)).endOfMonth == SysTime(DateTime(1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
7171         assert(SysTime(Date(1999, 9, 1)).endOfMonth == SysTime(DateTime(1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
7172         assert(SysTime(Date(1999, 10, 1)).endOfMonth == SysTime(DateTime(1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
7173         assert(SysTime(Date(1999, 11, 1)).endOfMonth == SysTime(DateTime(1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
7174         assert(SysTime(Date(1999, 12, 1)).endOfMonth == SysTime(DateTime(1999, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7175 
7176         // Test B.C.
7177         assert(SysTime(Date(-1999, 1, 1)).endOfMonth == SysTime(DateTime(-1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7178         assert(SysTime(Date(-1999, 2, 1)).endOfMonth == SysTime(DateTime(-1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7179         assert(SysTime(Date(-2000, 2, 1)).endOfMonth == SysTime(DateTime(-2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7180         assert(SysTime(Date(-1999, 3, 1)).endOfMonth == SysTime(DateTime(-1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
7181         assert(SysTime(Date(-1999, 4, 1)).endOfMonth == SysTime(DateTime(-1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
7182         assert(SysTime(Date(-1999, 5, 1)).endOfMonth == SysTime(DateTime(-1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
7183         assert(SysTime(Date(-1999, 6, 1)).endOfMonth == SysTime(DateTime(-1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7184         assert(SysTime(Date(-1999, 7, 1)).endOfMonth == SysTime(DateTime(-1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7185         assert(SysTime(Date(-1999, 8, 1)).endOfMonth == SysTime(DateTime(-1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
7186         assert(SysTime(Date(-1999, 9, 1)).endOfMonth == SysTime(DateTime(-1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
7187         assert(SysTime(Date(-1999, 10, 1)).endOfMonth ==
7188                SysTime(DateTime(-1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
7189         assert(SysTime(Date(-1999, 11, 1)).endOfMonth ==
7190                SysTime(DateTime(-1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
7191         assert(SysTime(Date(-1999, 12, 1)).endOfMonth ==
7192                SysTime(DateTime(-1999, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7193 
7194         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7195         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7196         assert(cst.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7197         //assert(ist.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7198     }
7199 
7200 
7201     /++
7202         The last day in the month that this $(LREF SysTime) is in.
7203       +/
7204     @property ubyte daysInMonth() @safe const nothrow
7205     {
7206         return Date(dayOfGregorianCal).daysInMonth;
7207     }
7208 
7209     ///
7210     @safe unittest
7211     {
7212         import std.datetime.date : DateTime;
7213 
7214         assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).daysInMonth == 31);
7215         assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0)).daysInMonth == 28);
7216         assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27)).daysInMonth == 29);
7217         assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9)).daysInMonth == 30);
7218     }
7219 
7220     @safe unittest
7221     {
7222         // Test A.D.
7223         assert(SysTime(DateTime(1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
7224         assert(SysTime(DateTime(1999, 2, 1, 17, 13, 12)).daysInMonth == 28);
7225         assert(SysTime(DateTime(2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
7226         assert(SysTime(DateTime(1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
7227         assert(SysTime(DateTime(1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
7228         assert(SysTime(DateTime(1999, 5, 1, 15, 13, 12)).daysInMonth == 31);
7229         assert(SysTime(DateTime(1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
7230         assert(SysTime(DateTime(1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
7231         assert(SysTime(DateTime(1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
7232         assert(SysTime(DateTime(1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
7233         assert(SysTime(DateTime(1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
7234         assert(SysTime(DateTime(1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
7235         assert(SysTime(DateTime(1999, 12, 1, 12, 52, 13)).daysInMonth == 31);
7236 
7237         // Test B.C.
7238         assert(SysTime(DateTime(-1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
7239         assert(SysTime(DateTime(-1999, 2, 1, 7, 13, 12)).daysInMonth == 28);
7240         assert(SysTime(DateTime(-2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
7241         assert(SysTime(DateTime(-1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
7242         assert(SysTime(DateTime(-1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
7243         assert(SysTime(DateTime(-1999, 5, 1, 5, 13, 12)).daysInMonth == 31);
7244         assert(SysTime(DateTime(-1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
7245         assert(SysTime(DateTime(-1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
7246         assert(SysTime(DateTime(-1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
7247         assert(SysTime(DateTime(-1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
7248         assert(SysTime(DateTime(-1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
7249         assert(SysTime(DateTime(-1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
7250         assert(SysTime(DateTime(-1999, 12, 1, 12, 52, 13)).daysInMonth == 31);
7251 
7252         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7253         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7254         assert(cst.daysInMonth == 31);
7255         //assert(ist.daysInMonth == 31);
7256     }
7257 
7258 
7259     /++
7260         Whether the current year is a date in A.D.
7261       +/
7262     @property bool isAD() @safe const nothrow
7263     {
7264         return adjTime >= 0;
7265     }
7266 
7267     ///
7268     @safe unittest
7269     {
7270         import std.datetime.date : DateTime;
7271 
7272         assert(SysTime(DateTime(1, 1, 1, 12, 7, 0)).isAD);
7273         assert(SysTime(DateTime(2010, 12, 31, 0, 0, 0)).isAD);
7274         assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
7275         assert(!SysTime(DateTime(-2010, 1, 1, 2, 2, 2)).isAD);
7276     }
7277 
7278     @safe unittest
7279     {
7280         assert(SysTime(DateTime(2010, 7, 4, 12, 0, 9)).isAD);
7281         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).isAD);
7282         assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
7283         assert(!SysTime(DateTime(0, 1, 1, 23, 59, 59)).isAD);
7284         assert(!SysTime(DateTime(-1, 1, 1, 23 ,59 ,59)).isAD);
7285         assert(!SysTime(DateTime(-2010, 7, 4, 12, 2, 2)).isAD);
7286 
7287         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7288         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7289         assert(cst.isAD);
7290         //assert(ist.isAD);
7291     }
7292 
7293 
7294     /++
7295         The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day)
7296         for this $(LREF SysTime) at the given time. For example,
7297         prior to noon, 1996-03-31 would be the Julian day number 2_450_173, so
7298         this function returns 2_450_173, while from noon onward, the Julian
7299         day number would be 2_450_174, so this function returns 2_450_174.
7300       +/
7301     @property long julianDay() @safe const nothrow
7302     {
7303         immutable jd = dayOfGregorianCal + 1_721_425;
7304         return hour < 12 ? jd - 1 : jd;
7305     }
7306 
7307     @safe unittest
7308     {
7309         assert(SysTime(DateTime(-4713, 11, 24, 0, 0, 0)).julianDay == -1);
7310         assert(SysTime(DateTime(-4713, 11, 24, 12, 0, 0)).julianDay == 0);
7311 
7312         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).julianDay == 1_721_424);
7313         assert(SysTime(DateTime(0, 12, 31, 12, 0, 0)).julianDay == 1_721_425);
7314 
7315         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).julianDay == 1_721_425);
7316         assert(SysTime(DateTime(1, 1, 1, 12, 0, 0)).julianDay == 1_721_426);
7317 
7318         assert(SysTime(DateTime(1582, 10, 15, 0, 0, 0)).julianDay == 2_299_160);
7319         assert(SysTime(DateTime(1582, 10, 15, 12, 0, 0)).julianDay == 2_299_161);
7320 
7321         assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).julianDay == 2_400_000);
7322         assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).julianDay == 2_400_001);
7323 
7324         assert(SysTime(DateTime(1982, 1, 4, 0, 0, 0)).julianDay == 2_444_973);
7325         assert(SysTime(DateTime(1982, 1, 4, 12, 0, 0)).julianDay == 2_444_974);
7326 
7327         assert(SysTime(DateTime(1996, 3, 31, 0, 0, 0)).julianDay == 2_450_173);
7328         assert(SysTime(DateTime(1996, 3, 31, 12, 0, 0)).julianDay == 2_450_174);
7329 
7330         assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).julianDay == 2_455_432);
7331         assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).julianDay == 2_455_433);
7332 
7333         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7334         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7335         assert(cst.julianDay == 2_451_366);
7336         //assert(ist.julianDay == 2_451_366);
7337     }
7338 
7339 
7340     /++
7341         The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for
7342         any time on this date (since, the modified Julian day changes at
7343         midnight).
7344       +/
7345     @property long modJulianDay() @safe const nothrow
7346     {
7347         return dayOfGregorianCal + 1_721_425 - 2_400_001;
7348     }
7349 
7350     @safe unittest
7351     {
7352         assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).modJulianDay == 0);
7353         assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).modJulianDay == 0);
7354 
7355         assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).modJulianDay == 55_432);
7356         assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).modJulianDay == 55_432);
7357 
7358         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7359         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7360         assert(cst.modJulianDay == 51_365);
7361         //assert(ist.modJulianDay == 51_365);
7362     }
7363 
7364 
7365     /++
7366         Returns a $(REF Date,std,datetime,date) equivalent to this $(LREF SysTime).
7367       +/
7368     Date opCast(T)() @safe const nothrow
7369         if (is(Unqual!T == Date))
7370     {
7371         return Date(dayOfGregorianCal);
7372     }
7373 
7374     @safe unittest
7375     {
7376         assert(cast(Date) SysTime(Date(1999, 7, 6)) == Date(1999, 7, 6));
7377         assert(cast(Date) SysTime(Date(2000, 12, 31)) == Date(2000, 12, 31));
7378         assert(cast(Date) SysTime(Date(2001, 1, 1)) == Date(2001, 1, 1));
7379 
7380         assert(cast(Date) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == Date(1999, 7, 6));
7381         assert(cast(Date) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == Date(2000, 12, 31));
7382         assert(cast(Date) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == Date(2001, 1, 1));
7383 
7384         assert(cast(Date) SysTime(Date(-1999, 7, 6)) == Date(-1999, 7, 6));
7385         assert(cast(Date) SysTime(Date(-2000, 12, 31)) == Date(-2000, 12, 31));
7386         assert(cast(Date) SysTime(Date(-2001, 1, 1)) == Date(-2001, 1, 1));
7387 
7388         assert(cast(Date) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == Date(-1999, 7, 6));
7389         assert(cast(Date) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == Date(-2000, 12, 31));
7390         assert(cast(Date) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == Date(-2001, 1, 1));
7391 
7392         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7393         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7394         assert(cast(Date) cst != Date.init);
7395         //assert(cast(Date) ist != Date.init);
7396     }
7397 
7398 
7399     /++
7400         Returns a $(REF DateTime,std,datetime,date) equivalent to this
7401         $(LREF SysTime).
7402       +/
7403     DateTime opCast(T)() @safe const nothrow
7404         if (is(Unqual!T == DateTime))
7405     {
7406         try
7407         {
7408             auto hnsecs = adjTime;
7409             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
7410 
7411             if (hnsecs < 0)
7412             {
7413                 hnsecs += convert!("hours", "hnsecs")(24);
7414                 --days;
7415             }
7416 
7417             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
7418             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
7419             immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
7420 
7421             return DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour, cast(int) minute, cast(int) second));
7422         }
7423         catch (Exception e)
7424             assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw.");
7425     }
7426 
7427     @safe unittest
7428     {
7429         assert(cast(DateTime) SysTime(DateTime(1, 1, 6, 7, 12, 22)) == DateTime(1, 1, 6, 7, 12, 22));
7430         assert(cast(DateTime) SysTime(DateTime(1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(1, 1, 6, 7, 12, 22));
7431         assert(cast(DateTime) SysTime(Date(1999, 7, 6)) == DateTime(1999, 7, 6, 0, 0, 0));
7432         assert(cast(DateTime) SysTime(Date(2000, 12, 31)) == DateTime(2000, 12, 31, 0, 0, 0));
7433         assert(cast(DateTime) SysTime(Date(2001, 1, 1)) == DateTime(2001, 1, 1, 0, 0, 0));
7434 
7435         assert(cast(DateTime) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == DateTime(1999, 7, 6, 12, 10, 9));
7436         assert(cast(DateTime) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == DateTime(2000, 12, 31, 13, 11, 10));
7437         assert(cast(DateTime) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == DateTime(2001, 1, 1, 14, 12, 11));
7438 
7439         assert(cast(DateTime) SysTime(DateTime(-1, 1, 6, 7, 12, 22)) == DateTime(-1, 1, 6, 7, 12, 22));
7440         assert(cast(DateTime) SysTime(DateTime(-1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(-1, 1, 6, 7, 12, 22));
7441         assert(cast(DateTime) SysTime(Date(-1999, 7, 6)) == DateTime(-1999, 7, 6, 0, 0, 0));
7442         assert(cast(DateTime) SysTime(Date(-2000, 12, 31)) == DateTime(-2000, 12, 31, 0, 0, 0));
7443         assert(cast(DateTime) SysTime(Date(-2001, 1, 1)) == DateTime(-2001, 1, 1, 0, 0, 0));
7444 
7445         assert(cast(DateTime) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == DateTime(-1999, 7, 6, 12, 10, 9));
7446         assert(cast(DateTime) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == DateTime(-2000, 12, 31, 13, 11, 10));
7447         assert(cast(DateTime) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == DateTime(-2001, 1, 1, 14, 12, 11));
7448 
7449         assert(cast(DateTime) SysTime(DateTime(2011, 1, 13, 8, 17, 2), msecs(296), LocalTime()) ==
7450                DateTime(2011, 1, 13, 8, 17, 2));
7451 
7452         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7453         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7454         assert(cast(DateTime) cst != DateTime.init);
7455         //assert(cast(DateTime) ist != DateTime.init);
7456     }
7457 
7458 
7459     /++
7460         Returns a $(REF TimeOfDay,std,datetime,date) equivalent to this
7461         $(LREF SysTime).
7462       +/
7463     TimeOfDay opCast(T)() @safe const nothrow
7464         if (is(Unqual!T == TimeOfDay))
7465     {
7466         try
7467         {
7468             auto hnsecs = adjTime;
7469             hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
7470 
7471             if (hnsecs < 0)
7472                 hnsecs += convert!("hours", "hnsecs")(24);
7473 
7474             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
7475             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
7476             immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
7477 
7478             return TimeOfDay(cast(int) hour, cast(int) minute, cast(int) second);
7479         }
7480         catch (Exception e)
7481             assert(0, "TimeOfDay's constructor threw.");
7482     }
7483 
7484     @safe unittest
7485     {
7486         assert(cast(TimeOfDay) SysTime(Date(1999, 7, 6)) == TimeOfDay(0, 0, 0));
7487         assert(cast(TimeOfDay) SysTime(Date(2000, 12, 31)) == TimeOfDay(0, 0, 0));
7488         assert(cast(TimeOfDay) SysTime(Date(2001, 1, 1)) == TimeOfDay(0, 0, 0));
7489 
7490         assert(cast(TimeOfDay) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
7491         assert(cast(TimeOfDay) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
7492         assert(cast(TimeOfDay) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11));
7493 
7494         assert(cast(TimeOfDay) SysTime(Date(-1999, 7, 6)) == TimeOfDay(0, 0, 0));
7495         assert(cast(TimeOfDay) SysTime(Date(-2000, 12, 31)) == TimeOfDay(0, 0, 0));
7496         assert(cast(TimeOfDay) SysTime(Date(-2001, 1, 1)) == TimeOfDay(0, 0, 0));
7497 
7498         assert(cast(TimeOfDay) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
7499         assert(cast(TimeOfDay) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
7500         assert(cast(TimeOfDay) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11));
7501 
7502         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7503         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7504         assert(cast(TimeOfDay) cst != TimeOfDay.init);
7505         //assert(cast(TimeOfDay) ist != TimeOfDay.init);
7506     }
7507 
7508 
7509     // Temporary hack until bug http://d.puremagic.com/issues/show_bug.cgi?id=4867 is fixed.
7510     // This allows assignment from const(SysTime) to SysTime.
7511     // It may be a good idea to keep it though, since casting from a type to itself
7512     // should be allowed, and it doesn't work without this opCast() since opCast()
7513     // has already been defined for other types.
7514     SysTime opCast(T)() @safe const pure nothrow
7515         if (is(Unqual!T == SysTime))
7516     {
7517         return SysTime(_stdTime, _timezone);
7518     }
7519 
7520 
7521     /++
7522         Converts this $(LREF SysTime) to a string with the format
7523         YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds and TZ is time
7524         zone).
7525 
7526         Note that the number of digits in the fractional seconds varies with the
7527         number of fractional seconds. It's a maximum of 7 (which would be
7528         hnsecs), but only has as many as are necessary to hold the correct value
7529         (so no trailing zeroes), and if there are no fractional seconds, then
7530         there is no decimal point.
7531 
7532         If this $(LREF SysTime)'s time zone is
7533         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
7534         zone is $(D UTC), then it is "Z". Otherwise, it is the offset from UTC
7535         (e.g. +0100 or -0700). Note that the offset from UTC is $(I not) enough
7536         to uniquely identify the time zone.
7537 
7538         Time zone offsets will be in the form +HHMM or -HHMM.
7539 
7540         $(RED Warning:
7541             Previously, toISOString did the same as $(LREF toISOExtString) and
7542             generated +HH:MM or -HH:MM for the time zone when it was not
7543             $(REF LocalTime,std,datetime,timezone) or
7544             $(REF UTC,std,datetime,timezone), which is not in conformance with
7545             ISO 8601 for the non-extended string format. This has now been
7546             fixed. However, for now, fromISOString will continue to accept the
7547             extended format for the time zone so that any code which has been
7548             writing out the result of toISOString to read in later will continue
7549             to work. The current behavior will be kept until July 2019 at which
7550             point, fromISOString will be fixed to be standards compliant.)
7551       +/
7552     string toISOString() @safe const nothrow
7553     {
7554         try
7555         {
7556             immutable adjustedTime = adjTime;
7557             long hnsecs = adjustedTime;
7558 
7559             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
7560 
7561             if (hnsecs < 0)
7562             {
7563                 hnsecs += convert!("hours", "hnsecs")(24);
7564                 --days;
7565             }
7566 
7567             auto hour = splitUnitsFromHNSecs!"hours"(hnsecs);
7568             auto minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
7569             auto second = splitUnitsFromHNSecs!"seconds"(hnsecs);
7570 
7571             auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
7572                                           cast(int) minute, cast(int) second));
7573             auto fracSecStr = fracSecsToISOString(cast(int) hnsecs);
7574 
7575             if (_timezone is LocalTime())
7576                 return dateTime.toISOString() ~ fracSecStr;
7577 
7578             if (_timezone is UTC())
7579                 return dateTime.toISOString() ~ fracSecStr ~ "Z";
7580 
7581             immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
7582 
7583             return format("%s%s%s",
7584                           dateTime.toISOString(),
7585                           fracSecStr,
7586                           SimpleTimeZone.toISOExtString(utcOffset));
7587         }
7588         catch (Exception e)
7589             assert(0, "format() threw.");
7590     }
7591 
7592     ///
7593     @safe unittest
7594     {
7595         import core.time : msecs, hnsecs;
7596         import std.datetime.date : DateTime;
7597 
7598         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOString() ==
7599                "20100704T070612");
7600 
7601         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOString() ==
7602                "19981225T021500.024");
7603 
7604         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOString() ==
7605                "00000105T230959");
7606 
7607         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOString() ==
7608                "-00040105T000002.052092");
7609     }
7610 
7611     @safe unittest
7612     {
7613         // Test A.D.
7614         assert(SysTime(DateTime.init, UTC()).toISOString() == "00010101T000000Z");
7615         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOString() == "00010101T000000.0000001Z");
7616 
7617         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOString() == "00091204T000000");
7618         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOString() == "00991204T050612");
7619         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOString() == "09991204T134459");
7620         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOString() == "99990704T235959");
7621         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOString() == "+100001020T010101");
7622 
7623         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "00091204T000000.042");
7624         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "00991204T050612.1");
7625         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "09991204T134459.04502");
7626         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "99990704T235959.0000012");
7627         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "+100001020T010101.050789");
7628 
7629         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
7630                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOString() ==
7631                "20121221T121212-06:00");
7632 
7633         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
7634                        new immutable SimpleTimeZone(dur!"minutes"(420))).toISOString() ==
7635                "20121221T121212+07:00");
7636 
7637         // Test B.C.
7638         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOString() ==
7639                "00001231T235959.9999999Z");
7640         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOString() == "00001231T235959.0000001Z");
7641         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOString() == "00001231T235959Z");
7642 
7643         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOString() == "00001204T001204");
7644         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOString() == "-00091204T000000");
7645         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOString() == "-00991204T050612");
7646         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOString() == "-09991204T134459");
7647         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOString() == "-99990704T235959");
7648         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOString() == "-100001020T010101");
7649 
7650         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOString() == "00001204T000000.007");
7651         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "-00091204T000000.042");
7652         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "-00991204T050612.1");
7653         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "-09991204T134459.04502");
7654         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "-99990704T235959.0000012");
7655         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "-100001020T010101.050789");
7656 
7657         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7658         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7659         assert(cast(TimeOfDay) cst != TimeOfDay.init);
7660         //assert(cast(TimeOfDay) ist != TimeOfDay.init);
7661     }
7662 
7663 
7664 
7665     /++
7666         Converts this $(LREF SysTime) to a string with the format
7667         YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
7668         is the time zone).
7669 
7670         Note that the number of digits in the fractional seconds varies with the
7671         number of fractional seconds. It's a maximum of 7 (which would be
7672         hnsecs), but only has as many as are necessary to hold the correct value
7673         (so no trailing zeroes), and if there are no fractional seconds, then
7674         there is no decimal point.
7675 
7676         If this $(LREF SysTime)'s time zone is
7677         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
7678         zone is $(D UTC), then it is "Z". Otherwise, it is the offset from UTC
7679         (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not)
7680         enough to uniquely identify the time zone.
7681 
7682         Time zone offsets will be in the form +HH:MM or -HH:MM.
7683       +/
7684     string toISOExtString() @safe const nothrow
7685     {
7686         try
7687         {
7688             immutable adjustedTime = adjTime;
7689             long hnsecs = adjustedTime;
7690 
7691             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
7692 
7693             if (hnsecs < 0)
7694             {
7695                 hnsecs += convert!("hours", "hnsecs")(24);
7696                 --days;
7697             }
7698 
7699             auto hour = splitUnitsFromHNSecs!"hours"(hnsecs);
7700             auto minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
7701             auto second = splitUnitsFromHNSecs!"seconds"(hnsecs);
7702 
7703             auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
7704                                           cast(int) minute, cast(int) second));
7705             auto fracSecStr = fracSecsToISOString(cast(int) hnsecs);
7706 
7707             if (_timezone is LocalTime())
7708                 return dateTime.toISOExtString() ~ fracSecStr;
7709 
7710             if (_timezone is UTC())
7711                 return dateTime.toISOExtString() ~ fracSecStr ~ "Z";
7712 
7713             immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
7714 
7715             return format("%s%s%s",
7716                           dateTime.toISOExtString(),
7717                           fracSecStr,
7718                           SimpleTimeZone.toISOExtString(utcOffset));
7719         }
7720         catch (Exception e)
7721             assert(0, "format() threw.");
7722     }
7723 
7724     ///
7725     @safe unittest
7726     {
7727         import core.time : msecs, hnsecs;
7728         import std.datetime.date : DateTime;
7729 
7730         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOExtString() ==
7731                "2010-07-04T07:06:12");
7732 
7733         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOExtString() ==
7734                "1998-12-25T02:15:00.024");
7735 
7736         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOExtString() ==
7737                "0000-01-05T23:09:59");
7738 
7739         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString() ==
7740                "-0004-01-05T00:00:02.052092");
7741     }
7742 
7743     @safe unittest
7744     {
7745         // Test A.D.
7746         assert(SysTime(DateTime.init, UTC()).toISOExtString() == "0001-01-01T00:00:00Z");
7747         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOExtString() ==
7748                "0001-01-01T00:00:00.0000001Z");
7749 
7750         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00");
7751         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12");
7752         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59");
7753         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59");
7754         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01");
7755 
7756         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "0009-12-04T00:00:00.042");
7757         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "0099-12-04T05:06:12.1");
7758         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() == "0999-12-04T13:44:59.04502");
7759         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() == "9999-07-04T23:59:59.0000012");
7760         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
7761                "+10000-10-20T01:01:01.050789");
7762 
7763         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
7764                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOExtString() ==
7765                "2012-12-21T12:12:12-06:00");
7766 
7767         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
7768                        new immutable SimpleTimeZone(dur!"minutes"(420))).toISOExtString() ==
7769                "2012-12-21T12:12:12+07:00");
7770 
7771         // Test B.C.
7772         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOExtString() ==
7773                "0000-12-31T23:59:59.9999999Z");
7774         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOExtString() ==
7775                "0000-12-31T23:59:59.0000001Z");
7776         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOExtString() == "0000-12-31T23:59:59Z");
7777 
7778         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04");
7779         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00");
7780         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12");
7781         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59");
7782         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59");
7783         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01");
7784 
7785         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOExtString() == "0000-12-04T00:00:00.007");
7786         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "-0009-12-04T00:00:00.042");
7787         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "-0099-12-04T05:06:12.1");
7788         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() ==
7789                "-0999-12-04T13:44:59.04502");
7790         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() ==
7791                "-9999-07-04T23:59:59.0000012");
7792         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
7793                "-10000-10-20T01:01:01.050789");
7794 
7795         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7796         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7797         assert(cast(TimeOfDay) cst != TimeOfDay.init);
7798         //assert(cast(TimeOfDay) ist != TimeOfDay.init);
7799     }
7800 
7801     /++
7802         Converts this $(LREF SysTime) to a string with the format
7803         YYYY-Mon-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
7804         is the time zone).
7805 
7806         Note that the number of digits in the fractional seconds varies with the
7807         number of fractional seconds. It's a maximum of 7 (which would be
7808         hnsecs), but only has as many as are necessary to hold the correct value
7809         (so no trailing zeroes), and if there are no fractional seconds, then
7810         there is no decimal point.
7811 
7812         If this $(LREF SysTime)'s time zone is
7813         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
7814         zone is $(D UTC), then it is "Z". Otherwise, it is the offset from UTC
7815         (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not)
7816         enough to uniquely identify the time zone.
7817 
7818         Time zone offsets will be in the form +HH:MM or -HH:MM.
7819       +/
7820     string toSimpleString() @safe const nothrow
7821     {
7822         try
7823         {
7824             immutable adjustedTime = adjTime;
7825             long hnsecs = adjustedTime;
7826 
7827             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
7828 
7829             if (hnsecs < 0)
7830             {
7831                 hnsecs += convert!("hours", "hnsecs")(24);
7832                 --days;
7833             }
7834 
7835             auto hour = splitUnitsFromHNSecs!"hours"(hnsecs);
7836             auto minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
7837             auto second = splitUnitsFromHNSecs!"seconds"(hnsecs);
7838 
7839             auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
7840                                           cast(int) minute, cast(int) second));
7841             auto fracSecStr = fracSecsToISOString(cast(int) hnsecs);
7842 
7843             if (_timezone is LocalTime())
7844                 return dateTime.toSimpleString() ~ fracSecStr;
7845 
7846             if (_timezone is UTC())
7847                 return dateTime.toSimpleString() ~ fracSecStr ~ "Z";
7848 
7849             immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
7850 
7851             return format("%s%s%s",
7852                           dateTime.toSimpleString(),
7853                           fracSecStr,
7854                           SimpleTimeZone.toISOExtString(utcOffset));
7855         }
7856         catch (Exception e)
7857             assert(0, "format() threw.");
7858     }
7859 
7860     ///
7861     @safe unittest
7862     {
7863         import core.time : msecs, hnsecs;
7864         import std.datetime.date : DateTime;
7865 
7866         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toSimpleString() ==
7867                "2010-Jul-04 07:06:12");
7868 
7869         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toSimpleString() ==
7870                "1998-Dec-25 02:15:00.024");
7871 
7872         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toSimpleString() ==
7873                "0000-Jan-05 23:09:59");
7874 
7875         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toSimpleString() ==
7876                 "-0004-Jan-05 00:00:02.052092");
7877     }
7878 
7879     @safe unittest
7880     {
7881         // Test A.D.
7882         assert(SysTime(DateTime.init, UTC()).toString() == "0001-Jan-01 00:00:00Z");
7883         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toString() == "0001-Jan-01 00:00:00.0000001Z");
7884 
7885         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00");
7886         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12");
7887         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59");
7888         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59");
7889         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01");
7890 
7891         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "0009-Dec-04 00:00:00.042");
7892         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "0099-Dec-04 05:06:12.1");
7893         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
7894                "0999-Dec-04 13:44:59.04502");
7895         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
7896                "9999-Jul-04 23:59:59.0000012");
7897         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() ==
7898                "+10000-Oct-20 01:01:01.050789");
7899 
7900         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
7901                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toSimpleString() ==
7902                "2012-Dec-21 12:12:12-06:00");
7903 
7904         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
7905                        new immutable SimpleTimeZone(dur!"minutes"(420))).toSimpleString() ==
7906                "2012-Dec-21 12:12:12+07:00");
7907 
7908         // Test B.C.
7909         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toSimpleString() ==
7910                "0000-Dec-31 23:59:59.9999999Z");
7911         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toSimpleString() ==
7912                "0000-Dec-31 23:59:59.0000001Z");
7913         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toSimpleString() == "0000-Dec-31 23:59:59Z");
7914 
7915         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04");
7916         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00");
7917         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12");
7918         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59");
7919         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59");
7920         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01");
7921 
7922         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toSimpleString() == "0000-Dec-04 00:00:00.007");
7923         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "-0009-Dec-04 00:00:00.042");
7924         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "-0099-Dec-04 05:06:12.1");
7925         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
7926                "-0999-Dec-04 13:44:59.04502");
7927         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
7928                "-9999-Jul-04 23:59:59.0000012");
7929         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() ==
7930                "-10000-Oct-20 01:01:01.050789");
7931 
7932         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7933         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7934         assert(cast(TimeOfDay) cst != TimeOfDay.init);
7935         //assert(cast(TimeOfDay) ist != TimeOfDay.init);
7936     }
7937 
7938 
7939     /++
7940         Converts this $(LREF SysTime) to a string.
7941 
7942         This function exists to make it easy to convert a $(LREF SysTime) to a
7943         string for code that does not care what the exact format is - just that
7944         it presents the information in a clear manner. It also makes it easy to
7945         simply convert a $(LREF SysTime) to a string when using functions such
7946         as `to!string`, `format`, or `writeln` which use toString to convert
7947         user-defined types. So, it is unlikely that much code will call
7948         toString directly.
7949 
7950         The format of the string is purposefully unspecified, and code that
7951         cares about the format of the string should use `toISOString`,
7952         `toISOExtString`, `toSimpleString`, or some other custom formatting
7953         function that explicitly generates the format that the code needs. The
7954         reason is that the code is then clear about what format it's using,
7955         making it less error-prone to maintain the code and interact with other
7956         software that consumes the generated strings. It's for this same reason
7957         that $(LREF SysTime) has no `fromString` function, whereas it does have
7958         `fromISOString`, `fromISOExtString`, and `fromSimpleString`.
7959 
7960         The format returned by toString may or may not change in the future.
7961       +/
7962     string toString() @safe const nothrow
7963     {
7964         return toSimpleString();
7965     }
7966 
7967     @safe unittest
7968     {
7969         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7970         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7971         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7972         assert(st.toString());
7973         assert(cst.toString());
7974         //assert(ist.toString());
7975     }
7976 
7977 
7978     /++
7979         Creates a $(LREF SysTime) from a string with the format
7980         YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds is the time
7981         zone). Whitespace is stripped from the given string.
7982 
7983         The exact format is exactly as described in $(D toISOString) except that
7984         trailing zeroes are permitted - including having fractional seconds with
7985         all zeroes. However, a decimal point with nothing following it is
7986         invalid. Also, while $(LREF toISOString) will never generate a string
7987         with more than 7 digits in the fractional seconds (because that's the
7988         limit with hecto-nanosecond precision), it will allow more than 7 digits
7989         in order to read strings from other sources that have higher precision
7990         (however, any digits beyond 7 will be truncated).
7991 
7992         If there is no time zone in the string, then
7993         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
7994         then $(D UTC) is used. Otherwise, a
7995         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
7996         given offset from UTC is used. To get the returned $(LREF SysTime) to be
7997         a particular time zone, pass in that time zone and the $(LREF SysTime)
7998         to be returned will be converted to that time zone (though it will still
7999         be read in as whatever time zone is in its string).
8000 
8001         The accepted formats for time zone offsets are +HH, -HH, +HHMM, and
8002         -HHMM.
8003 
8004         $(RED Warning:
8005             Previously, $(LREF toISOString) did the same as
8006             $(LREF toISOExtString) and generated +HH:MM or -HH:MM for the time
8007             zone when it was not $(REF LocalTime,std,datetime,timezone) or
8008             $(REF UTC,std,datetime,timezone), which is not in conformance with
8009             ISO 8601 for the non-extended string format. This has now been
8010             fixed. However, for now, fromISOString will continue to accept the
8011             extended format for the time zone so that any code which has been
8012             writing out the result of toISOString to read in later will continue
8013             to work. The current behavior will be kept until July 2019 at which
8014             point, fromISOString will be fixed to be standards compliant.)
8015 
8016         Params:
8017             isoString = A string formatted in the ISO format for dates and times.
8018             tz        = The time zone to convert the given time to (no
8019                         conversion occurs if null).
8020 
8021         Throws:
8022             $(REF DateTimeException,std,datetime,date) if the given string is
8023             not in the ISO format or if the resulting $(LREF SysTime) would not
8024             be valid.
8025       +/
8026     static SysTime fromISOString(S)(in S isoString, immutable TimeZone tz = null) @safe
8027         if (isSomeString!S)
8028     {
8029         import std.algorithm.searching : startsWith, find;
8030         import std.conv : to;
8031         import std.string : strip;
8032 
8033         auto dstr = to!dstring(strip(isoString));
8034         immutable skipFirst = dstr.startsWith('+', '-') != 0;
8035 
8036         auto found = (skipFirst ? dstr[1..$] : dstr).find('.', 'Z', '+', '-');
8037         auto dateTimeStr = dstr[0 .. $ - found[0].length];
8038 
8039         dstring fracSecStr;
8040         dstring zoneStr;
8041 
8042         if (found[1] != 0)
8043         {
8044             if (found[1] == 1)
8045             {
8046                 auto foundTZ = found[0].find('Z', '+', '-');
8047 
8048                 if (foundTZ[1] != 0)
8049                 {
8050                     fracSecStr = found[0][0 .. $ - foundTZ[0].length];
8051                     zoneStr = foundTZ[0];
8052                 }
8053                 else
8054                     fracSecStr = found[0];
8055             }
8056             else
8057                 zoneStr = found[0];
8058         }
8059 
8060         try
8061         {
8062             auto dateTime = DateTime.fromISOString(dateTimeStr);
8063             auto fracSec = fracSecsFromISOString(fracSecStr);
8064             Rebindable!(immutable TimeZone) parsedZone;
8065 
8066             if (zoneStr.empty)
8067                 parsedZone = LocalTime();
8068             else if (zoneStr == "Z")
8069                 parsedZone = UTC();
8070             else
8071             {
8072                 try
8073                     parsedZone = SimpleTimeZone.fromISOString(zoneStr);
8074                 catch (DateTimeException dte)
8075                     parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
8076             }
8077 
8078             auto retval = SysTime(dateTime, fracSec, parsedZone);
8079 
8080             if (tz !is null)
8081                 retval.timezone = tz;
8082 
8083             return retval;
8084         }
8085         catch (DateTimeException dte)
8086             throw new DateTimeException(format("Invalid ISO String: %s", isoString));
8087     }
8088 
8089     ///
8090     @safe unittest
8091     {
8092         import core.time : hours, msecs, usecs, hnsecs;
8093         import std.datetime.date : DateTime;
8094         import std.datetime.timezone : SimpleTimeZone, UTC;
8095 
8096         assert(SysTime.fromISOString("20100704T070612") ==
8097                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8098 
8099         assert(SysTime.fromISOString("19981225T021500.007") ==
8100                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
8101 
8102         assert(SysTime.fromISOString("00000105T230959.00002") ==
8103                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
8104 
8105         assert(SysTime.fromISOString("20130207T043937.000050392") ==
8106                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
8107 
8108         assert(SysTime.fromISOString("-00040105T000002") ==
8109                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
8110 
8111         assert(SysTime.fromISOString(" 20100704T070612 ") ==
8112                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8113 
8114         assert(SysTime.fromISOString("20100704T070612Z") ==
8115                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
8116 
8117         assert(SysTime.fromISOString("20100704T070612-0800") ==
8118                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8119                        new immutable SimpleTimeZone(hours(-8))));
8120 
8121         assert(SysTime.fromISOString("20100704T070612+0800") ==
8122                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8123                        new immutable SimpleTimeZone(hours(8))));
8124     }
8125 
8126     @safe unittest
8127     {
8128         foreach (str; ["", "20100704000000", "20100704 000000", "20100704t000000",
8129                        "20100704T000000.", "20100704T000000.A", "20100704T000000.Z",
8130                        "20100704T000000.0000000A", "20100704T000000.00000000A",
8131                        "20100704T000000+", "20100704T000000-", "20100704T000000:",
8132                        "20100704T000000-:", "20100704T000000+:", "20100704T000000-1:",
8133                        "20100704T000000+1:", "20100704T000000+1:0",
8134                        "20100704T000000-12.00", "20100704T000000+12.00",
8135                        "20100704T000000-8", "20100704T000000+8",
8136                        "20100704T000000-800", "20100704T000000+800",
8137                        "20100704T000000-080", "20100704T000000+080",
8138                        "20100704T000000-2400", "20100704T000000+2400",
8139                        "20100704T000000-1260", "20100704T000000+1260",
8140                        "20100704T000000.0-8", "20100704T000000.0+8",
8141                        "20100704T000000.0-800", "20100704T000000.0+800",
8142                        "20100704T000000.0-080", "20100704T000000.0+080",
8143                        "20100704T000000.0-2400", "20100704T000000.0+2400",
8144                        "20100704T000000.0-1260", "20100704T000000.0+1260",
8145                        "20100704T000000-8:00", "20100704T000000+8:00",
8146                        "20100704T000000-08:0", "20100704T000000+08:0",
8147                        "20100704T000000-24:00", "20100704T000000+24:00",
8148                        "20100704T000000-12:60", "20100704T000000+12:60",
8149                        "20100704T000000.0-8:00", "20100704T000000.0+8:00",
8150                        "20100704T000000.0-08:0", "20100704T000000.0+08:0",
8151                        "20100704T000000.0-24:00", "20100704T000000.0+24:00",
8152                        "20100704T000000.0-12:60", "20100704T000000.0+12:60",
8153                        "2010-07-0400:00:00", "2010-07-04 00:00:00",
8154                        "2010-07-04t00:00:00", "2010-07-04T00:00:00.",
8155                        "2010-Jul-0400:00:00", "2010-Jul-04 00:00:00", "2010-Jul-04t00:00:00",
8156                        "2010-Jul-04T00:00:00", "2010-Jul-04 00:00:00.",
8157                        "2010-12-22T172201", "2010-Dec-22 17:22:01"])
8158         {
8159             assertThrown!DateTimeException(SysTime.fromISOString(str), format("[%s]", str));
8160         }
8161 
8162         static void test(string str, SysTime st, size_t line = __LINE__)
8163         {
8164             if (SysTime.fromISOString(str) != st)
8165                 throw new AssertError("unittest failure", __FILE__, line);
8166         }
8167 
8168         test("20101222T172201", SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
8169         test("19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8170         test("-19990706T123033", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
8171         test("+019990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8172         test("19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8173         test(" 19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8174         test(" 19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8175 
8176         test("19070707T121212.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
8177         test("19070707T121212.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
8178         test("19070707T121212.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
8179         test("20100704T000000.00000000", SysTime(Date(2010, 07, 04)));
8180         test("20100704T000000.00000009", SysTime(Date(2010, 07, 04)));
8181         test("20100704T000000.00000019", SysTime(DateTime(2010, 07, 04), hnsecs(1)));
8182         test("19070707T121212.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
8183         test("19070707T121212.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
8184         test("19070707T121212.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
8185         test("19070707T121212.0010000", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
8186 
8187         auto west60 = new immutable SimpleTimeZone(hours(-1));
8188         auto west90 = new immutable SimpleTimeZone(minutes(-90));
8189         auto west480 = new immutable SimpleTimeZone(hours(-8));
8190         auto east60 = new immutable SimpleTimeZone(hours(1));
8191         auto east90 = new immutable SimpleTimeZone(minutes(90));
8192         auto east480 = new immutable SimpleTimeZone(hours(8));
8193 
8194         test("20101222T172201Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
8195         test("20101222T172201-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8196         test("20101222T172201-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8197         test("20101222T172201-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
8198         test("20101222T172201-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
8199         test("20101222T172201+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8200         test("20101222T172201+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8201         test("20101222T172201+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8202         test("20101222T172201+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
8203 
8204         test("20101103T065106.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
8205         test("20101222T172201.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC()));
8206         test("20101222T172201.23112-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
8207         test("20101222T172201.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), west60));
8208         test("20101222T172201.1-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
8209         test("20101222T172201.55-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
8210         test("20101222T172201.1234567+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
8211         test("20101222T172201.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8212         test("20101222T172201.0000000+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8213         test("20101222T172201.45+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
8214 
8215         // @@@DEPRECATED_2019-07@@@
8216         // This isn't deprecated per se, but that text will make it so that it
8217         // pops up when deprecations are moved along around July 2019. At that
8218         // time, we will update fromISOString so that it is conformant with ISO
8219         // 8601, and it will no longer accept ISO extended time zones (it does
8220         // currently because of issue #15654 - toISOString used to incorrectly
8221         // use the ISO extended time zone format). These tests will then start
8222         // failing will need to be updated accordingly. Also, the notes about
8223         // this issue in toISOString and fromISOString's documentation will need
8224         // to be removed.
8225         test("20101222T172201-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8226         test("20101222T172201-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
8227         test("20101222T172201-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
8228         test("20101222T172201+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8229         test("20101222T172201+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8230         test("20101222T172201+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
8231 
8232         test("20101222T172201.23112-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
8233         test("20101222T172201.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
8234         test("20101222T172201.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
8235         test("20101222T172201.1234567+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
8236         test("20101222T172201.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8237         test("20101222T172201.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
8238     }
8239 
8240     // bug# 17801
8241     @safe unittest
8242     {
8243         import std.conv : to;
8244         import std.meta : AliasSeq;
8245         foreach (C; AliasSeq!(char, wchar, dchar))
8246         {
8247             foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
8248             {
8249                 assert(SysTime.fromISOString(to!S("20121221T141516Z")) ==
8250                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
8251             }
8252         }
8253     }
8254 
8255 
8256     /++
8257         Creates a $(LREF SysTime) from a string with the format
8258         YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds is the
8259         time zone). Whitespace is stripped from the given string.
8260 
8261         The exact format is exactly as described in $(D toISOExtString)
8262         except that trailing zeroes are permitted - including having fractional
8263         seconds with all zeroes. However, a decimal point with nothing following
8264         it is invalid. Also, while $(LREF toISOExtString) will never generate a
8265         string with more than 7 digits in the fractional seconds (because that's
8266         the limit with hecto-nanosecond precision), it will allow more than 7
8267         digits in order to read strings from other sources that have higher
8268         precision (however, any digits beyond 7 will be truncated).
8269 
8270         If there is no time zone in the string, then
8271         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
8272         then $(D UTC) is used. Otherwise, a
8273         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
8274         given offset from UTC is used. To get the returned $(LREF SysTime) to be
8275         a particular time zone, pass in that time zone and the $(LREF SysTime)
8276         to be returned will be converted to that time zone (though it will still
8277         be read in as whatever time zone is in its string).
8278 
8279         The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and
8280         -HH:MM.
8281 
8282         Params:
8283             isoExtString = A string formatted in the ISO Extended format for
8284                            dates and times.
8285             tz           = The time zone to convert the given time to (no
8286                            conversion occurs if null).
8287 
8288         Throws:
8289             $(REF DateTimeException,std,datetime,date) if the given string is
8290             not in the ISO format or if the resulting $(LREF SysTime) would not
8291             be valid.
8292       +/
8293     static SysTime fromISOExtString(S)(in S isoExtString, immutable TimeZone tz = null) @safe
8294         if (isSomeString!(S))
8295     {
8296         import std.algorithm.searching : countUntil, find;
8297         import std.conv : to;
8298         import std.string : strip;
8299 
8300         auto dstr = to!dstring(strip(isoExtString));
8301 
8302         auto tIndex = dstr.countUntil('T');
8303         enforce(tIndex != -1, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
8304 
8305         auto found = dstr[tIndex + 1 .. $].find('.', 'Z', '+', '-');
8306         auto dateTimeStr = dstr[0 .. $ - found[0].length];
8307 
8308         dstring fracSecStr;
8309         dstring zoneStr;
8310 
8311         if (found[1] != 0)
8312         {
8313             if (found[1] == 1)
8314             {
8315                 auto foundTZ = found[0].find('Z', '+', '-');
8316 
8317                 if (foundTZ[1] != 0)
8318                 {
8319                     fracSecStr = found[0][0 .. $ - foundTZ[0].length];
8320                     zoneStr = foundTZ[0];
8321                 }
8322                 else
8323                     fracSecStr = found[0];
8324             }
8325             else
8326                 zoneStr = found[0];
8327         }
8328 
8329         try
8330         {
8331             auto dateTime = DateTime.fromISOExtString(dateTimeStr);
8332             auto fracSec = fracSecsFromISOString(fracSecStr);
8333             Rebindable!(immutable TimeZone) parsedZone;
8334 
8335             if (zoneStr.empty)
8336                 parsedZone = LocalTime();
8337             else if (zoneStr == "Z")
8338                 parsedZone = UTC();
8339             else
8340                 parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
8341 
8342             auto retval = SysTime(dateTime, fracSec, parsedZone);
8343 
8344             if (tz !is null)
8345                 retval.timezone = tz;
8346 
8347             return retval;
8348         }
8349         catch (DateTimeException dte)
8350             throw new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString));
8351     }
8352 
8353     ///
8354     @safe unittest
8355     {
8356         import core.time : hours, msecs, usecs, hnsecs;
8357         import std.datetime.date : DateTime;
8358         import std.datetime.timezone : SimpleTimeZone, UTC;
8359 
8360         assert(SysTime.fromISOExtString("2010-07-04T07:06:12") ==
8361                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8362 
8363         assert(SysTime.fromISOExtString("1998-12-25T02:15:00.007") ==
8364                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
8365 
8366         assert(SysTime.fromISOExtString("0000-01-05T23:09:59.00002") ==
8367                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
8368 
8369         assert(SysTime.fromISOExtString("2013-02-07T04:39:37.000050392") ==
8370                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
8371 
8372         assert(SysTime.fromISOExtString("-0004-01-05T00:00:02") ==
8373                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
8374 
8375         assert(SysTime.fromISOExtString(" 2010-07-04T07:06:12 ") ==
8376                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8377 
8378         assert(SysTime.fromISOExtString("2010-07-04T07:06:12Z") ==
8379                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
8380 
8381         assert(SysTime.fromISOExtString("2010-07-04T07:06:12-08:00") ==
8382                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8383                        new immutable SimpleTimeZone(hours(-8))));
8384         assert(SysTime.fromISOExtString("2010-07-04T07:06:12+08:00") ==
8385                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8386                        new immutable SimpleTimeZone(hours(8))));
8387     }
8388 
8389     @safe unittest
8390     {
8391         foreach (str; ["", "20100704000000", "20100704 000000",
8392                        "20100704t000000", "20100704T000000.", "20100704T000000.0",
8393                        "2010-07:0400:00:00", "2010-07-04 00:00:00",
8394                        "2010-07-04 00:00:00", "2010-07-04t00:00:00",
8395                        "2010-07-04T00:00:00.", "2010-07-04T00:00:00.A", "2010-07-04T00:00:00.Z",
8396                        "2010-07-04T00:00:00.0000000A", "2010-07-04T00:00:00.00000000A",
8397                        "2010-07-04T00:00:00+", "2010-07-04T00:00:00-",
8398                        "2010-07-04T00:00:00:", "2010-07-04T00:00:00-:", "2010-07-04T00:00:00+:",
8399                        "2010-07-04T00:00:00-1:", "2010-07-04T00:00:00+1:", "2010-07-04T00:00:00+1:0",
8400                        "2010-07-04T00:00:00-12.00", "2010-07-04T00:00:00+12.00",
8401                        "2010-07-04T00:00:00-8", "2010-07-04T00:00:00+8",
8402                        "20100704T000000-800", "20100704T000000+800",
8403                        "20100704T000000-080", "20100704T000000+080",
8404                        "20100704T000000-2400", "20100704T000000+2400",
8405                        "20100704T000000-1260", "20100704T000000+1260",
8406                        "20100704T000000.0-800", "20100704T000000.0+800",
8407                        "20100704T000000.0-8", "20100704T000000.0+8",
8408                        "20100704T000000.0-080", "20100704T000000.0+080",
8409                        "20100704T000000.0-2400", "20100704T000000.0+2400",
8410                        "20100704T000000.0-1260", "20100704T000000.0+1260",
8411                        "2010-07-04T00:00:00-8:00", "2010-07-04T00:00:00+8:00",
8412                        "2010-07-04T00:00:00-24:00", "2010-07-04T00:00:00+24:00",
8413                        "2010-07-04T00:00:00-12:60", "2010-07-04T00:00:00+12:60",
8414                        "2010-07-04T00:00:00.0-8:00", "2010-07-04T00:00:00.0+8:00",
8415                        "2010-07-04T00:00:00.0-8", "2010-07-04T00:00:00.0+8",
8416                        "2010-07-04T00:00:00.0-24:00", "2010-07-04T00:00:00.0+24:00",
8417                        "2010-07-04T00:00:00.0-12:60", "2010-07-04T00:00:00.0+12:60",
8418                        "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00",
8419                        "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.0",
8420                        "20101222T172201", "2010-Dec-22 17:22:01"])
8421         {
8422             assertThrown!DateTimeException(SysTime.fromISOExtString(str), format("[%s]", str));
8423         }
8424 
8425         static void test(string str, SysTime st, size_t line = __LINE__)
8426         {
8427             if (SysTime.fromISOExtString(str) != st)
8428                 throw new AssertError("unittest failure", __FILE__, line);
8429         }
8430 
8431         test("2010-12-22T17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
8432         test("1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8433         test("-1999-07-06T12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
8434         test("+01999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8435         test("1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8436         test(" 1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8437         test(" 1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8438 
8439         test("1907-07-07T12:12:12.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
8440         test("1907-07-07T12:12:12.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
8441         test("1907-07-07T12:12:12.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
8442         test("2010-07-04T00:00:00.00000000", SysTime(Date(2010, 07, 04)));
8443         test("2010-07-04T00:00:00.00000009", SysTime(Date(2010, 07, 04)));
8444         test("2010-07-04T00:00:00.00000019", SysTime(DateTime(2010, 07, 04), hnsecs(1)));
8445         test("1907-07-07T12:12:12.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
8446         test("1907-07-07T12:12:12.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
8447         test("1907-07-07T12:12:12.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
8448         test("1907-07-07T12:12:12.0010000", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
8449 
8450         auto west60 = new immutable SimpleTimeZone(hours(-1));
8451         auto west90 = new immutable SimpleTimeZone(minutes(-90));
8452         auto west480 = new immutable SimpleTimeZone(hours(-8));
8453         auto east60 = new immutable SimpleTimeZone(hours(1));
8454         auto east90 = new immutable SimpleTimeZone(minutes(90));
8455         auto east480 = new immutable SimpleTimeZone(hours(8));
8456 
8457         test("2010-12-22T17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
8458         test("2010-12-22T17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8459         test("2010-12-22T17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8460         test("2010-12-22T17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
8461         test("2010-12-22T17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
8462         test("2010-12-22T17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8463         test("2010-12-22T17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8464         test("2010-12-22T17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8465         test("2010-12-22T17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
8466 
8467         test("2010-11-03T06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
8468         test("2010-12-22T17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC()));
8469         test("2010-12-22T17:22:01.23112-01:00",
8470              SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
8471         test("2010-12-22T17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), west60));
8472         test("2010-12-22T17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
8473         test("2010-12-22T17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
8474         test("2010-12-22T17:22:01.1234567+01:00",
8475              SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
8476         test("2010-12-22T17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8477         test("2010-12-22T17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8478         test("2010-12-22T17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
8479     }
8480 
8481     // bug# 17801
8482     @safe unittest
8483     {
8484         import std.conv : to;
8485         import std.meta : AliasSeq;
8486         foreach (C; AliasSeq!(char, wchar, dchar))
8487         {
8488             foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
8489             {
8490                 assert(SysTime.fromISOExtString(to!S("2012-12-21T14:15:16Z")) ==
8491                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
8492             }
8493         }
8494     }
8495 
8496 
8497     /++
8498         Creates a $(LREF SysTime) from a string with the format
8499         YYYY-MM-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds is the
8500         time zone). Whitespace is stripped from the given string.
8501 
8502         The exact format is exactly as described in $(D toSimpleString) except
8503         that trailing zeroes are permitted - including having fractional seconds
8504         with all zeroes. However, a decimal point with nothing following it is
8505         invalid. Also, while $(LREF toSimpleString) will never generate a
8506         string with more than 7 digits in the fractional seconds (because that's
8507         the limit with hecto-nanosecond precision), it will allow more than 7
8508         digits in order to read strings from other sources that have higher
8509         precision (however, any digits beyond 7 will be truncated).
8510 
8511         If there is no time zone in the string, then
8512         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
8513         then $(D UTC) is used. Otherwise, a
8514         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
8515         given offset from UTC is used. To get the returned $(LREF SysTime) to be
8516         a particular time zone, pass in that time zone and the $(LREF SysTime)
8517         to be returned will be converted to that time zone (though it will still
8518         be read in as whatever time zone is in its string).
8519 
8520         The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and
8521         -HH:MM.
8522 
8523         Params:
8524             simpleString = A string formatted in the way that
8525                            $(D toSimpleString) formats dates and times.
8526             tz           = The time zone to convert the given time to (no
8527                            conversion occurs if null).
8528 
8529         Throws:
8530             $(REF DateTimeException,std,datetime,date) if the given string is
8531             not in the ISO format or if the resulting $(LREF SysTime) would not
8532             be valid.
8533       +/
8534     static SysTime fromSimpleString(S)(in S simpleString, immutable TimeZone tz = null) @safe
8535         if (isSomeString!(S))
8536     {
8537         import std.algorithm.searching : countUntil, find;
8538         import std.conv : to;
8539         import std.string : strip;
8540 
8541         auto dstr = to!dstring(strip(simpleString));
8542 
8543         auto spaceIndex = dstr.countUntil(' ');
8544         enforce(spaceIndex != -1, new DateTimeException(format("Invalid Simple String: %s", simpleString)));
8545 
8546         auto found = dstr[spaceIndex + 1 .. $].find('.', 'Z', '+', '-');
8547         auto dateTimeStr = dstr[0 .. $ - found[0].length];
8548 
8549         dstring fracSecStr;
8550         dstring zoneStr;
8551 
8552         if (found[1] != 0)
8553         {
8554             if (found[1] == 1)
8555             {
8556                 auto foundTZ = found[0].find('Z', '+', '-');
8557 
8558                 if (foundTZ[1] != 0)
8559                 {
8560                     fracSecStr = found[0][0 .. $ - foundTZ[0].length];
8561                     zoneStr = foundTZ[0];
8562                 }
8563                 else
8564                     fracSecStr = found[0];
8565             }
8566             else
8567                 zoneStr = found[0];
8568         }
8569 
8570         try
8571         {
8572             auto dateTime = DateTime.fromSimpleString(dateTimeStr);
8573             auto fracSec = fracSecsFromISOString(fracSecStr);
8574             Rebindable!(immutable TimeZone) parsedZone;
8575 
8576             if (zoneStr.empty)
8577                 parsedZone = LocalTime();
8578             else if (zoneStr == "Z")
8579                 parsedZone = UTC();
8580             else
8581                 parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
8582 
8583             auto retval = SysTime(dateTime, fracSec, parsedZone);
8584 
8585             if (tz !is null)
8586                 retval.timezone = tz;
8587 
8588             return retval;
8589         }
8590         catch (DateTimeException dte)
8591             throw new DateTimeException(format("Invalid Simple String: %s", simpleString));
8592     }
8593 
8594     ///
8595     @safe unittest
8596     {
8597         import core.time : hours, msecs, usecs, hnsecs;
8598         import std.datetime.date : DateTime;
8599         import std.datetime.timezone : SimpleTimeZone, UTC;
8600 
8601         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12") ==
8602                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8603 
8604         assert(SysTime.fromSimpleString("1998-Dec-25 02:15:00.007") ==
8605                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
8606 
8607         assert(SysTime.fromSimpleString("0000-Jan-05 23:09:59.00002") ==
8608                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
8609 
8610         assert(SysTime.fromSimpleString("2013-Feb-07 04:39:37.000050392") ==
8611                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
8612 
8613         assert(SysTime.fromSimpleString("-0004-Jan-05 00:00:02") ==
8614                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
8615 
8616         assert(SysTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") ==
8617                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8618 
8619         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12Z") ==
8620                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
8621 
8622         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12-08:00") ==
8623                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8624                        new immutable SimpleTimeZone(hours(-8))));
8625 
8626         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12+08:00") ==
8627                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8628                        new immutable SimpleTimeZone(hours(8))));
8629     }
8630 
8631     @safe unittest
8632     {
8633         foreach (str; ["", "20100704000000", "20100704 000000",
8634                        "20100704t000000", "20100704T000000.", "20100704T000000.0",
8635                        "2010-07-0400:00:00", "2010-07-04 00:00:00", "2010-07-04t00:00:00",
8636                        "2010-07-04T00:00:00.", "2010-07-04T00:00:00.0",
8637                        "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00", "2010-Jul-04T00:00:00",
8638                        "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.A", "2010-Jul-04 00:00:00.Z",
8639                        "2010-Jul-04 00:00:00.0000000A", "2010-Jul-04 00:00:00.00000000A",
8640                        "2010-Jul-04 00:00:00+", "2010-Jul-04 00:00:00-",
8641                        "2010-Jul-04 00:00:00:", "2010-Jul-04 00:00:00-:",
8642                        "2010-Jul-04 00:00:00+:", "2010-Jul-04 00:00:00-1:",
8643                        "2010-Jul-04 00:00:00+1:", "2010-Jul-04 00:00:00+1:0",
8644                        "2010-Jul-04 00:00:00-12.00", "2010-Jul-04 00:00:00+12.00",
8645                        "2010-Jul-04 00:00:00-8", "2010-Jul-04 00:00:00+8",
8646                        "20100704T000000-800", "20100704T000000+800",
8647                        "20100704T000000-080", "20100704T000000+080",
8648                        "20100704T000000-2400", "20100704T000000+2400",
8649                        "20100704T000000-1260", "20100704T000000+1260",
8650                        "20100704T000000.0-800", "20100704T000000.0+800",
8651                        "20100704T000000.0-8", "20100704T000000.0+8",
8652                        "20100704T000000.0-080", "20100704T000000.0+080",
8653                        "20100704T000000.0-2400", "20100704T000000.0+2400",
8654                        "20100704T000000.0-1260", "20100704T000000.0+1260",
8655                        "2010-Jul-04 00:00:00-8:00", "2010-Jul-04 00:00:00+8:00",
8656                        "2010-Jul-04 00:00:00-08:0", "2010-Jul-04 00:00:00+08:0",
8657                        "2010-Jul-04 00:00:00-24:00", "2010-Jul-04 00:00:00+24:00",
8658                        "2010-Jul-04 00:00:00-12:60", "2010-Jul-04 00:00:00+24:60",
8659                        "2010-Jul-04 00:00:00.0-8:00", "2010-Jul-04 00:00:00+8:00",
8660                        "2010-Jul-04 00:00:00.0-8", "2010-Jul-04 00:00:00.0+8",
8661                        "2010-Jul-04 00:00:00.0-08:0", "2010-Jul-04 00:00:00.0+08:0",
8662                        "2010-Jul-04 00:00:00.0-24:00", "2010-Jul-04 00:00:00.0+24:00",
8663                        "2010-Jul-04 00:00:00.0-12:60", "2010-Jul-04 00:00:00.0+24:60",
8664                        "20101222T172201", "2010-12-22T172201"])
8665         {
8666             assertThrown!DateTimeException(SysTime.fromSimpleString(str), format("[%s]", str));
8667         }
8668 
8669         static void test(string str, SysTime st, size_t line = __LINE__)
8670         {
8671             if (SysTime.fromSimpleString(str) != st)
8672                 throw new AssertError("unittest failure", __FILE__, line);
8673         }
8674 
8675         test("2010-Dec-22 17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
8676         test("1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8677         test("-1999-Jul-06 12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
8678         test("+01999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8679         test("1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8680         test(" 1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8681         test(" 1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8682 
8683         test("1907-Jul-07 12:12:12.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
8684         test("1907-Jul-07 12:12:12.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
8685         test("2010-Jul-04 00:00:00.00000000", SysTime(Date(2010, 07, 04)));
8686         test("2010-Jul-04 00:00:00.00000009", SysTime(Date(2010, 07, 04)));
8687         test("2010-Jul-04 00:00:00.00000019", SysTime(DateTime(2010, 07, 04), hnsecs(1)));
8688         test("1907-Jul-07 12:12:12.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
8689         test("1907-Jul-07 12:12:12.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
8690         test("1907-Jul-07 12:12:12.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
8691         test("1907-Jul-07 12:12:12.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
8692         test("1907-Jul-07 12:12:12.0010000", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
8693 
8694         auto west60 = new immutable SimpleTimeZone(hours(-1));
8695         auto west90 = new immutable SimpleTimeZone(minutes(-90));
8696         auto west480 = new immutable SimpleTimeZone(hours(-8));
8697         auto east60 = new immutable SimpleTimeZone(hours(1));
8698         auto east90 = new immutable SimpleTimeZone(minutes(90));
8699         auto east480 = new immutable SimpleTimeZone(hours(8));
8700 
8701         test("2010-Dec-22 17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
8702         test("2010-Dec-22 17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8703         test("2010-Dec-22 17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8704         test("2010-Dec-22 17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
8705         test("2010-Dec-22 17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
8706         test("2010-Dec-22 17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8707         test("2010-Dec-22 17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8708         test("2010-Dec-22 17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8709         test("2010-Dec-22 17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
8710 
8711         test("2010-Nov-03 06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
8712         test("2010-Dec-22 17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC()));
8713         test("2010-Dec-22 17:22:01.23112-01:00",
8714              SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
8715         test("2010-Dec-22 17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), west60));
8716         test("2010-Dec-22 17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
8717         test("2010-Dec-22 17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
8718         test("2010-Dec-22 17:22:01.1234567+01:00",
8719              SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
8720         test("2010-Dec-22 17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8721         test("2010-Dec-22 17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8722         test("2010-Dec-22 17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
8723     }
8724 
8725     // bug# 17801
8726     @safe unittest
8727     {
8728         import std.conv : to;
8729         import std.meta : AliasSeq;
8730         foreach (C; AliasSeq!(char, wchar, dchar))
8731         {
8732             foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
8733             {
8734                 assert(SysTime.fromSimpleString(to!S("2012-Dec-21 14:15:16Z")) ==
8735                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
8736             }
8737         }
8738     }
8739 
8740 
8741     /++
8742         Returns the $(LREF SysTime) farthest in the past which is representable
8743         by $(LREF SysTime).
8744 
8745         The $(LREF SysTime) which is returned is in UTC.
8746       +/
8747     @property static SysTime min() @safe pure nothrow
8748     {
8749         return SysTime(long.min, UTC());
8750     }
8751 
8752     @safe unittest
8753     {
8754         assert(SysTime.min.year < 0);
8755         assert(SysTime.min < SysTime.max);
8756     }
8757 
8758 
8759     /++
8760         Returns the $(LREF SysTime) farthest in the future which is representable
8761         by $(LREF SysTime).
8762 
8763         The $(LREF SysTime) which is returned is in UTC.
8764       +/
8765     @property static SysTime max() @safe pure nothrow
8766     {
8767         return SysTime(long.max, UTC());
8768     }
8769 
8770     @safe unittest
8771     {
8772         assert(SysTime.max.year > 0);
8773         assert(SysTime.max > SysTime.min);
8774     }
8775 
8776 
8777 private:
8778 
8779     /+
8780         Returns $(D stdTime) converted to $(LREF SysTime)'s time zone.
8781       +/
8782     @property long adjTime() @safe const nothrow
8783     {
8784         return _timezone.utcToTZ(_stdTime);
8785     }
8786 
8787 
8788     /+
8789         Converts the given hnsecs from $(LREF SysTime)'s time zone to std time.
8790       +/
8791     @property void adjTime(long adjTime) @safe nothrow
8792     {
8793         _stdTime = _timezone.tzToUTC(adjTime);
8794     }
8795 
8796 
8797     // Commented out due to bug http://d.puremagic.com/issues/show_bug.cgi?id=5058
8798     /+
8799     invariant()
8800     {
8801         assert(_timezone !is null, "Invariant Failure: timezone is null. Were you foolish enough to use " ~
8802                                    "SysTime.init? (since timezone for SysTime.init can't be set at compile time).");
8803     }
8804     +/
8805 
8806 
8807     long  _stdTime;
8808     Rebindable!(immutable TimeZone) _timezone;
8809 }
8810 
8811 
8812 /++
8813     Converts from unix time (which uses midnight, January 1st, 1970 UTC as its
8814     epoch and seconds as its units) to "std time" (which uses midnight,
8815     January 1st, 1 A.D. UTC and hnsecs as its units).
8816 
8817     The C standard does not specify the representation of time_t, so it is
8818     implementation defined. On POSIX systems, unix time is equivalent to
8819     time_t, but that's not necessarily true on other systems (e.g. it is
8820     not true for the Digital Mars C runtime). So, be careful when using unix
8821     time with C functions on non-POSIX systems.
8822 
8823     "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO
8824     8601 and is what $(LREF SysTime) uses internally. However, holding the time
8825     as an integer in hnescs since that epoch technically isn't actually part of
8826     the standard, much as it's based on it, so the name "std time" isn't
8827     particularly good, but there isn't an official name for it. C# uses "ticks"
8828     for the same thing, but they aren't actually clock ticks, and the term
8829     "ticks" $(I is) used for actual clock ticks for $(REF MonoTime, core,time),
8830     so it didn't make sense to use the term ticks here. So, for better or worse,
8831     std.datetime uses the term "std time" for this.
8832 
8833     Params:
8834         unixTime = The unix time to convert.
8835 
8836     See_Also:
8837         SysTime.fromUnixTime
8838   +/
unixTimeToStdTime(long unixTime)8839 long unixTimeToStdTime(long unixTime) @safe pure nothrow
8840 {
8841     return 621_355_968_000_000_000L + convert!("seconds", "hnsecs")(unixTime);
8842 }
8843 
8844 ///
8845 @safe unittest
8846 {
8847     import std.datetime.date : DateTime;
8848     import std.datetime.timezone : UTC;
8849 
8850     // Midnight, January 1st, 1970
8851     assert(unixTimeToStdTime(0) == 621_355_968_000_000_000L);
8852     assert(SysTime(unixTimeToStdTime(0)) ==
8853            SysTime(DateTime(1970, 1, 1), UTC()));
8854 
8855     assert(unixTimeToStdTime(int.max) == 642_830_804_470_000_000L);
8856     assert(SysTime(unixTimeToStdTime(int.max)) ==
8857            SysTime(DateTime(2038, 1, 19, 3, 14, 07), UTC()));
8858 
8859     assert(unixTimeToStdTime(-127_127) == 621_354_696_730_000_000L);
8860     assert(SysTime(unixTimeToStdTime(-127_127)) ==
8861            SysTime(DateTime(1969, 12, 30, 12, 41, 13), UTC()));
8862 }
8863 
8864 @safe unittest
8865 {
8866     // Midnight, January 2nd, 1970
8867     assert(unixTimeToStdTime(86_400) == 621_355_968_000_000_000L + 864_000_000_000L);
8868     // Midnight, December 31st, 1969
8869     assert(unixTimeToStdTime(-86_400) == 621_355_968_000_000_000L - 864_000_000_000L);
8870 
8871     assert(unixTimeToStdTime(0) == (Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs");
8872     assert(unixTimeToStdTime(0) == (DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs");
8873 
8874     foreach (dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)])
8875         assert(unixTimeToStdTime((dt - DateTime(1970, 1, 1)).total!"seconds") == (dt - DateTime.init).total!"hnsecs");
8876 }
8877 
8878 
8879 /++
8880     Converts std time (which uses midnight, January 1st, 1 A.D. UTC as its epoch
8881     and hnsecs as its units) to unix time (which uses midnight, January 1st,
8882     1970 UTC as its epoch and seconds as its units).
8883 
8884     The C standard does not specify the representation of time_t, so it is
8885     implementation defined. On POSIX systems, unix time is equivalent to
8886     time_t, but that's not necessarily true on other systems (e.g. it is
8887     not true for the Digital Mars C runtime). So, be careful when using unix
8888     time with C functions on non-POSIX systems.
8889 
8890     "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO
8891     8601 and is what $(LREF SysTime) uses internally. However, holding the time
8892     as an integer in hnescs since that epoch technically isn't actually part of
8893     the standard, much as it's based on it, so the name "std time" isn't
8894     particularly good, but there isn't an official name for it. C# uses "ticks"
8895     for the same thing, but they aren't actually clock ticks, and the term
8896     "ticks" $(I is) used for actual clock ticks for $(REF MonoTime, core,time),
8897     so it didn't make sense to use the term ticks here. So, for better or worse,
8898     std.datetime uses the term "std time" for this.
8899 
8900     By default, the return type is time_t (which is normally an alias for
8901     int on 32-bit systems and long on 64-bit systems), but if a different
8902     size is required than either int or long can be passed as a template
8903     argument to get the desired size.
8904 
8905     If the return type is int, and the result can't fit in an int, then the
8906     closest value that can be held in 32 bits will be used (so $(D int.max)
8907     if it goes over and $(D int.min) if it goes under). However, no attempt
8908     is made to deal with integer overflow if the return type is long.
8909 
8910     Params:
8911         T = The return type (int or long). It defaults to time_t, which is
8912             normally 32 bits on a 32-bit system and 64 bits on a 64-bit
8913             system.
8914         stdTime = The std time to convert.
8915 
8916     Returns:
8917         A signed integer representing the unix time which is equivalent to
8918         the given std time.
8919 
8920     See_Also:
8921         SysTime.toUnixTime
8922   +/
8923 T stdTimeToUnixTime(T = time_t)(long stdTime) @safe pure nothrow
8924 if (is(T == int) || is(T == long))
8925 {
8926     immutable unixTime = convert!("hnsecs", "seconds")(stdTime - 621_355_968_000_000_000L);
8927 
8928     static assert(is(time_t == int) || is(time_t == long),
8929                   "Currently, std.datetime only supports systems where time_t is int or long");
8930 
8931     static if (is(T == long))
8932         return unixTime;
8933     else static if (is(T == int))
8934     {
8935         if (unixTime > int.max)
8936             return int.max;
8937         return unixTime < int.min ? int.min : cast(int) unixTime;
8938     }
8939     else
8940         static assert(0, "Bug in template constraint. Only int and long allowed.");
8941 }
8942 
8943 ///
8944 @safe unittest
8945 {
8946     // Midnight, January 1st, 1970 UTC
8947     assert(stdTimeToUnixTime(621_355_968_000_000_000L) == 0);
8948 
8949     // 2038-01-19 03:14:07 UTC
8950     assert(stdTimeToUnixTime(642_830_804_470_000_000L) == int.max);
8951 }
8952 
8953 @safe unittest
8954 {
8955     enum unixEpochAsStdTime = (Date(1970, 1, 1) - Date.init).total!"hnsecs";
8956 
8957     assert(stdTimeToUnixTime(unixEpochAsStdTime) == 0);  // Midnight, January 1st, 1970
8958     assert(stdTimeToUnixTime(unixEpochAsStdTime + 864_000_000_000L) == 86_400);  // Midnight, January 2nd, 1970
8959     assert(stdTimeToUnixTime(unixEpochAsStdTime - 864_000_000_000L) == -86_400);  // Midnight, December 31st, 1969
8960 
8961     assert(stdTimeToUnixTime((Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs") == 0);
8962     assert(stdTimeToUnixTime((DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs") == 0);
8963 
8964     foreach (dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)])
8965         assert(stdTimeToUnixTime((dt - DateTime.init).total!"hnsecs") == (dt - DateTime(1970, 1, 1)).total!"seconds");
8966 
8967     enum max = convert!("seconds", "hnsecs")(int.max);
8968     enum min = convert!("seconds", "hnsecs")(int.min);
8969     enum one = convert!("seconds", "hnsecs")(1);
8970 
8971     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max) == int.max);
8972     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max) == int.max);
8973 
8974     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + one) == int.max + 1L);
8975     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + one) == int.max);
8976     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + 9_999_999) == int.max);
8977     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + 9_999_999) == int.max);
8978 
8979     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min) == int.min);
8980     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min) == int.min);
8981 
8982     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - one) == int.min - 1L);
8983     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - one) == int.min);
8984     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - 9_999_999) == int.min);
8985     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - 9_999_999) == int.min);
8986 }
8987 
8988 
version(StdDdoc)8989 version (StdDdoc)
8990 {
8991     version (Windows)
8992     {}
8993     else
8994     {
8995         alias SYSTEMTIME = void*;
8996         alias FILETIME = void*;
8997     }
8998 
8999     /++
9000         $(BLUE This function is Windows-Only.)
9001 
9002         Converts a $(D SYSTEMTIME) struct to a $(LREF SysTime).
9003 
9004         Params:
9005             st = The $(D SYSTEMTIME) struct to convert.
9006             tz = The time zone that the time in the $(D SYSTEMTIME) struct is
9007                  assumed to be (if the $(D SYSTEMTIME) was supplied by a Windows
9008                  system call, the $(D SYSTEMTIME) will either be in local time
9009                  or UTC, depending on the call).
9010 
9011         Throws:
9012             $(REF DateTimeException,std,datetime,date) if the given
9013             $(D SYSTEMTIME) will not fit in a $(LREF SysTime), which is highly
9014             unlikely to happen given that $(D SysTime.max) is in 29,228 A.D. and
9015             the maximum $(D SYSTEMTIME) is in 30,827 A.D.
9016       +/
9017     SysTime SYSTEMTIMEToSysTime(const SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe;
9018 
9019 
9020     /++
9021         $(BLUE This function is Windows-Only.)
9022 
9023         Converts a $(LREF SysTime) to a $(D SYSTEMTIME) struct.
9024 
9025         The $(D SYSTEMTIME) which is returned will be set using the given
9026         $(LREF SysTime)'s time zone, so to get the $(D SYSTEMTIME) in
9027         UTC, set the $(LREF SysTime)'s time zone to UTC.
9028 
9029         Params:
9030             sysTime = The $(LREF SysTime) to convert.
9031 
9032         Throws:
9033             $(REF DateTimeException,std,datetime,date) if the given
9034             $(LREF SysTime) will not fit in a $(D SYSTEMTIME). This will only
9035             happen if the $(LREF SysTime)'s date is prior to 1601 A.D.
9036       +/
9037     SYSTEMTIME SysTimeToSYSTEMTIME(in SysTime sysTime) @safe;
9038 
9039 
9040     /++
9041         $(BLUE This function is Windows-Only.)
9042 
9043         Converts a $(D FILETIME) struct to the number of hnsecs since midnight,
9044         January 1st, 1 A.D.
9045 
9046         Params:
9047             ft = The $(D FILETIME) struct to convert.
9048 
9049         Throws:
9050             $(REF DateTimeException,std,datetime,date) if the given
9051             $(D FILETIME) cannot be represented as the return value.
9052       +/
9053     long FILETIMEToStdTime(scope const FILETIME* ft) @safe;
9054 
9055 
9056     /++
9057         $(BLUE This function is Windows-Only.)
9058 
9059         Converts a $(D FILETIME) struct to a $(LREF SysTime).
9060 
9061         Params:
9062             ft = The $(D FILETIME) struct to convert.
9063             tz = The time zone that the $(LREF SysTime) will be in
9064                  ($(D FILETIME)s are in UTC).
9065 
9066         Throws:
9067             $(REF DateTimeException,std,datetime,date) if the given
9068             $(D FILETIME) will not fit in a $(LREF SysTime).
9069       +/
9070     SysTime FILETIMEToSysTime(scope const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe;
9071 
9072 
9073     /++
9074         $(BLUE This function is Windows-Only.)
9075 
9076         Converts a number of hnsecs since midnight, January 1st, 1 A.D. to a
9077         $(D FILETIME) struct.
9078 
9079         Params:
9080             stdTime = The number of hnsecs since midnight, January 1st, 1 A.D.
9081                       UTC.
9082 
9083         Throws:
9084             $(REF DateTimeException,std,datetime,date) if the given value will
9085             not fit in a $(D FILETIME).
9086       +/
9087     FILETIME stdTimeToFILETIME(long stdTime) @safe;
9088 
9089 
9090     /++
9091         $(BLUE This function is Windows-Only.)
9092 
9093         Converts a $(LREF SysTime) to a $(D FILETIME) struct.
9094 
9095         $(D FILETIME)s are always in UTC.
9096 
9097         Params:
9098             sysTime = The $(LREF SysTime) to convert.
9099 
9100         Throws:
9101             $(REF DateTimeException,std,datetime,date) if the given
9102             $(LREF SysTime) will not fit in a $(D FILETIME).
9103       +/
9104     FILETIME SysTimeToFILETIME(SysTime sysTime) @safe;
9105 }
9106 else version (Windows)
9107 {
9108     SysTime SYSTEMTIMEToSysTime(const SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe
9109     {
9110         const max = SysTime.max;
9111 
9112         static void throwLaterThanMax()
9113         {
9114             throw new DateTimeException("The given SYSTEMTIME is for a date greater than SysTime.max.");
9115         }
9116 
9117         if (st.wYear > max.year)
9118             throwLaterThanMax();
9119         else if (st.wYear == max.year)
9120         {
9121             if (st.wMonth > max.month)
9122                 throwLaterThanMax();
9123             else if (st.wMonth == max.month)
9124             {
9125                 if (st.wDay > max.day)
9126                     throwLaterThanMax();
9127                 else if (st.wDay == max.day)
9128                 {
9129                     if (st.wHour > max.hour)
9130                         throwLaterThanMax();
9131                     else if (st.wHour == max.hour)
9132                     {
9133                         if (st.wMinute > max.minute)
9134                             throwLaterThanMax();
9135                         else if (st.wMinute == max.minute)
9136                         {
9137                             if (st.wSecond > max.second)
9138                                 throwLaterThanMax();
9139                             else if (st.wSecond == max.second)
9140                             {
9141                                 if (st.wMilliseconds > max.fracSecs.total!"msecs")
9142                                     throwLaterThanMax();
9143                             }
9144                         }
9145                     }
9146                 }
9147             }
9148         }
9149 
9150         auto dt = DateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
9151 
9152         return SysTime(dt, msecs(st.wMilliseconds), tz);
9153     }
9154 
9155     @system unittest
9156     {
9157         auto sysTime = Clock.currTime(UTC());
9158         SYSTEMTIME st = void;
9159         GetSystemTime(&st);
9160         auto converted = SYSTEMTIMEToSysTime(&st, UTC());
9161 
9162         assert(abs((converted - sysTime)) <= dur!"seconds"(2));
9163     }
9164 
9165 
9166     SYSTEMTIME SysTimeToSYSTEMTIME(in SysTime sysTime) @safe
9167     {
9168         immutable dt = cast(DateTime) sysTime;
9169 
9170         if (dt.year < 1601)
9171             throw new DateTimeException("SYSTEMTIME cannot hold dates prior to the year 1601.");
9172 
9173         SYSTEMTIME st;
9174 
9175         st.wYear = dt.year;
9176         st.wMonth = dt.month;
9177         st.wDayOfWeek = dt.dayOfWeek;
9178         st.wDay = dt.day;
9179         st.wHour = dt.hour;
9180         st.wMinute = dt.minute;
9181         st.wSecond = dt.second;
9182         st.wMilliseconds = cast(ushort) sysTime.fracSecs.total!"msecs";
9183 
9184         return st;
9185     }
9186 
9187     @system unittest
9188     {
9189         SYSTEMTIME st = void;
9190         GetSystemTime(&st);
9191         auto sysTime = SYSTEMTIMEToSysTime(&st, UTC());
9192 
9193         SYSTEMTIME result = SysTimeToSYSTEMTIME(sysTime);
9194 
9195         assert(st.wYear == result.wYear);
9196         assert(st.wMonth == result.wMonth);
9197         assert(st.wDayOfWeek == result.wDayOfWeek);
9198         assert(st.wDay == result.wDay);
9199         assert(st.wHour == result.wHour);
9200         assert(st.wMinute == result.wMinute);
9201         assert(st.wSecond == result.wSecond);
9202         assert(st.wMilliseconds == result.wMilliseconds);
9203     }
9204 
9205     private enum hnsecsFrom1601 = 504_911_232_000_000_000L;
9206 
9207     long FILETIMEToStdTime(scope const FILETIME* ft) @safe
9208     {
9209         ULARGE_INTEGER ul;
9210         ul.HighPart = ft.dwHighDateTime;
9211         ul.LowPart = ft.dwLowDateTime;
9212         ulong tempHNSecs = ul.QuadPart;
9213 
9214         if (tempHNSecs > long.max - hnsecsFrom1601)
9215             throw new DateTimeException("The given FILETIME cannot be represented as a stdTime value.");
9216 
9217         return cast(long) tempHNSecs + hnsecsFrom1601;
9218     }
9219 
9220     SysTime FILETIMEToSysTime(scope const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe
9221     {
9222         auto sysTime = SysTime(FILETIMEToStdTime(ft), UTC());
9223         sysTime.timezone = tz;
9224         return sysTime;
9225     }
9226 
9227     @system unittest
9228     {
9229         auto sysTime = Clock.currTime(UTC());
9230         SYSTEMTIME st = void;
9231         GetSystemTime(&st);
9232 
9233         FILETIME ft = void;
9234         SystemTimeToFileTime(&st, &ft);
9235 
9236         auto converted = FILETIMEToSysTime(&ft);
9237 
9238         assert(abs((converted - sysTime)) <= dur!"seconds"(2));
9239     }
9240 
9241 
9242     FILETIME stdTimeToFILETIME(long stdTime) @safe
9243     {
9244         if (stdTime < hnsecsFrom1601)
9245             throw new DateTimeException("The given stdTime value cannot be represented as a FILETIME.");
9246 
9247         ULARGE_INTEGER ul;
9248         ul.QuadPart = cast(ulong) stdTime - hnsecsFrom1601;
9249 
9250         FILETIME ft;
9251         ft.dwHighDateTime = ul.HighPart;
9252         ft.dwLowDateTime = ul.LowPart;
9253 
9254         return ft;
9255     }
9256 
9257     FILETIME SysTimeToFILETIME(SysTime sysTime) @safe
9258     {
9259         return stdTimeToFILETIME(sysTime.stdTime);
9260     }
9261 
9262     @system unittest
9263     {
9264         SYSTEMTIME st = void;
9265         GetSystemTime(&st);
9266 
9267         FILETIME ft = void;
9268         SystemTimeToFileTime(&st, &ft);
9269         auto sysTime = FILETIMEToSysTime(&ft, UTC());
9270 
9271         FILETIME result = SysTimeToFILETIME(sysTime);
9272 
9273         assert(ft.dwLowDateTime == result.dwLowDateTime);
9274         assert(ft.dwHighDateTime == result.dwHighDateTime);
9275     }
9276 }
9277 
9278 
9279 /++
9280     Type representing the DOS file date/time format.
9281   +/
9282 alias DosFileTime = uint;
9283 
9284 /++
9285     Converts from DOS file date/time to $(LREF SysTime).
9286 
9287     Params:
9288         dft = The DOS file time to convert.
9289         tz  = The time zone which the DOS file time is assumed to be in.
9290 
9291     Throws:
9292         $(REF DateTimeException,std,datetime,date) if the $(D DosFileTime) is
9293         invalid.
9294   +/
9295 SysTime DosFileTimeToSysTime(DosFileTime dft, immutable TimeZone tz = LocalTime()) @safe
9296 {
9297     uint dt = cast(uint) dft;
9298 
9299     if (dt == 0)
9300         throw new DateTimeException("Invalid DosFileTime.");
9301 
9302     int year = ((dt >> 25) & 0x7F) + 1980;
9303     int month = ((dt >> 21) & 0x0F);       // 1 .. 12
9304     int dayOfMonth = ((dt >> 16) & 0x1F);  // 1 .. 31
9305     int hour = (dt >> 11) & 0x1F;          // 0 .. 23
9306     int minute = (dt >> 5) & 0x3F;         // 0 .. 59
9307     int second = (dt << 1) & 0x3E;         // 0 .. 58 (in 2 second increments)
9308 
9309     try
9310         return SysTime(DateTime(year, month, dayOfMonth, hour, minute, second), tz);
9311     catch (DateTimeException dte)
9312         throw new DateTimeException("Invalid DosFileTime", __FILE__, __LINE__, dte);
9313 }
9314 
9315 @safe unittest
9316 {
9317     assert(DosFileTimeToSysTime(0b00000000001000010000000000000000) == SysTime(DateTime(1980, 1, 1, 0, 0, 0)));
9318     assert(DosFileTimeToSysTime(0b11111111100111111011111101111101) == SysTime(DateTime(2107, 12, 31, 23, 59, 58)));
9319     assert(DosFileTimeToSysTime(0x3E3F8456) == SysTime(DateTime(2011, 1, 31, 16, 34, 44)));
9320 }
9321 
9322 
9323 /++
9324     Converts from $(LREF SysTime) to DOS file date/time.
9325 
9326     Params:
9327         sysTime = The $(LREF SysTime) to convert.
9328 
9329     Throws:
9330         $(REF DateTimeException,std,datetime,date) if the given
9331         $(LREF SysTime) cannot be converted to a $(D DosFileTime).
9332   +/
9333 DosFileTime SysTimeToDosFileTime(SysTime sysTime) @safe
9334 {
9335     auto dateTime = cast(DateTime) sysTime;
9336 
9337     if (dateTime.year < 1980)
9338         throw new DateTimeException("DOS File Times cannot hold dates prior to 1980.");
9339 
9340     if (dateTime.year > 2107)
9341         throw new DateTimeException("DOS File Times cannot hold dates past 2107.");
9342 
9343     uint retval = 0;
9344     retval = (dateTime.year - 1980) << 25;
9345     retval |= (dateTime.month & 0x0F) << 21;
9346     retval |= (dateTime.day & 0x1F) << 16;
9347     retval |= (dateTime.hour & 0x1F) << 11;
9348     retval |= (dateTime.minute & 0x3F) << 5;
9349     retval |= (dateTime.second >> 1) & 0x1F;
9350 
9351     return cast(DosFileTime) retval;
9352 }
9353 
9354 @safe unittest
9355 {
9356     assert(SysTimeToDosFileTime(SysTime(DateTime(1980, 1, 1, 0, 0, 0))) == 0b00000000001000010000000000000000);
9357     assert(SysTimeToDosFileTime(SysTime(DateTime(2107, 12, 31, 23, 59, 58))) == 0b11111111100111111011111101111101);
9358     assert(SysTimeToDosFileTime(SysTime(DateTime(2011, 1, 31, 16, 34, 44))) == 0x3E3F8456);
9359 }
9360 
9361 
9362 /++
9363     The given array of $(D char) or random-access range of $(D char) or
9364     $(D ubyte) is expected to be in the format specified in
9365     $(HTTP tools.ietf.org/html/rfc5322, RFC 5322) section 3.3 with the
9366     grammar rule $(I date-time). It is the date-time format commonly used in
9367     internet messages such as e-mail and HTTP. The corresponding
9368     $(LREF SysTime) will be returned.
9369 
9370     RFC 822 was the original spec (hence the function's name), whereas RFC 5322
9371     is the current spec.
9372 
9373     The day of the week is ignored beyond verifying that it's a valid day of the
9374     week, as the day of the week can be inferred from the date. It is not
9375     checked whether the given day of the week matches the actual day of the week
9376     of the given date (though it is technically invalid per the spec if the
9377     day of the week doesn't match the actual day of the week of the given date).
9378 
9379     If the time zone is $(D "-0000") (or considered to be equivalent to
9380     $(D "-0000") by section 4.3 of the spec), a
9381     $(REF SimpleTimeZone,std,datetime,timezone) with a utc offset of $(D 0) is
9382     used rather than $(REF UTC,std,datetime,timezone), whereas $(D "+0000") uses
9383     $(REF UTC,std,datetime,timezone).
9384 
9385     Note that because $(LREF SysTime) does not currently support having a second
9386     value of 60 (as is sometimes done for leap seconds), if the date-time value
9387     does have a value of 60 for the seconds, it is treated as 59.
9388 
9389     The one area in which this function violates RFC 5322 is that it accepts
9390     $(D "\n") in folding whitespace in the place of $(D "\r\n"), because the
9391     HTTP spec requires it.
9392 
9393     Throws:
9394         $(REF DateTimeException,std,datetime,date) if the given string doesn't
9395         follow the grammar for a date-time field or if the resulting
9396         $(LREF SysTime) is invalid.
9397   +/
9398 SysTime parseRFC822DateTime()(in char[] value) @safe
9399 {
9400     import std.string : representation;
9401     return parseRFC822DateTime(value.representation);
9402 }
9403 
9404 /++ Ditto +/
9405 SysTime parseRFC822DateTime(R)(R value) @safe
9406 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
9407     (is(Unqual!(ElementType!R) == char) || is(Unqual!(ElementType!R) == ubyte)))
9408 {
9409     import std.algorithm.searching : find, all;
9410     import std.ascii : isDigit, isAlpha, isPrintable;
9411     import std.conv : to;
9412     import std.functional : not;
9413     import std.string : capitalize, format;
9414     import std.traits : EnumMembers, isArray;
9415     import std.typecons : Rebindable;
9416 
9417     void stripAndCheckLen(R valueBefore, size_t minLen, size_t line = __LINE__)
9418     {
9419         value = _stripCFWS(valueBefore);
9420         if (value.length < minLen)
9421             throw new DateTimeException("date-time value too short", __FILE__, line);
9422     }
9423     stripAndCheckLen(value, "7Dec1200:00A".length);
9424 
9425     static if (isArray!R && (is(ElementEncodingType!R == char) || is(ElementEncodingType!R == ubyte)))
9426     {
9427         static string sliceAsString(R str) @trusted
9428         {
9429             return cast(string) str;
9430         }
9431     }
9432     else
9433     {
9434         char[4] temp;
9435         char[] sliceAsString(R str) @trusted
9436         {
9437             size_t i = 0;
9438             foreach (c; str)
9439                 temp[i++] = cast(char) c;
9440             return temp[0 .. str.length];
9441         }
9442     }
9443 
9444     // day-of-week
9445     if (isAlpha(value[0]))
9446     {
9447         auto dowStr = sliceAsString(value[0 .. 3]);
9448         switch (dowStr)
9449         {
9450             foreach (dow; EnumMembers!DayOfWeek)
9451             {
9452                 enum dowC = capitalize(to!string(dow));
9453                 case dowC:
9454                     goto afterDoW;
9455             }
9456             default: throw new DateTimeException(format("Invalid day-of-week: %s", dowStr));
9457         }
9458 afterDoW: stripAndCheckLen(value[3 .. value.length], ",7Dec1200:00A".length);
9459         if (value[0] != ',')
9460             throw new DateTimeException("day-of-week missing comma");
9461         stripAndCheckLen(value[1 .. value.length], "7Dec1200:00A".length);
9462     }
9463 
9464     // day
9465     immutable digits = isDigit(value[1]) ? 2 : 1;
9466     immutable day = _convDigits!short(value[0 .. digits]);
9467     if (day == -1)
9468         throw new DateTimeException("Invalid day");
9469     stripAndCheckLen(value[digits .. value.length], "Dec1200:00A".length);
9470 
9471     // month
9472     Month month;
9473     {
9474         auto monStr = sliceAsString(value[0 .. 3]);
9475         switch (monStr)
9476         {
9477             foreach (mon; EnumMembers!Month)
9478             {
9479                 enum monC = capitalize(to!string(mon));
9480                 case monC:
9481                 {
9482                     month = mon;
9483                     goto afterMon;
9484                 }
9485             }
9486             default: throw new DateTimeException(format("Invalid month: %s", monStr));
9487         }
9488 afterMon: stripAndCheckLen(value[3 .. value.length], "1200:00A".length);
9489     }
9490 
9491     // year
9492     auto found = value[2 .. value.length].find!(not!(std.ascii.isDigit))();
9493     size_t yearLen = value.length - found.length;
9494     if (found.length == 0)
9495         throw new DateTimeException("Invalid year");
9496     if (found[0] == ':')
9497         yearLen -= 2;
9498     auto year = _convDigits!short(value[0 .. yearLen]);
9499     if (year < 1900)
9500     {
9501         if (year == -1)
9502             throw new DateTimeException("Invalid year");
9503         if (yearLen < 4)
9504         {
9505             if (yearLen == 3)
9506                 year += 1900;
9507             else if (yearLen == 2)
9508                 year += year < 50 ? 2000 : 1900;
9509             else
9510                 throw new DateTimeException("Invalid year. Too few digits.");
9511         }
9512         else
9513             throw new DateTimeException("Invalid year. Cannot be earlier than 1900.");
9514     }
9515     stripAndCheckLen(value[yearLen .. value.length], "00:00A".length);
9516 
9517     // hour
9518     immutable hour = _convDigits!short(value[0 .. 2]);
9519     stripAndCheckLen(value[2 .. value.length], ":00A".length);
9520     if (value[0] != ':')
9521         throw new DateTimeException("Invalid hour");
9522     stripAndCheckLen(value[1 .. value.length], "00A".length);
9523 
9524     // minute
9525     immutable minute = _convDigits!short(value[0 .. 2]);
9526     stripAndCheckLen(value[2 .. value.length], "A".length);
9527 
9528     // second
9529     short second;
9530     if (value[0] == ':')
9531     {
9532         stripAndCheckLen(value[1 .. value.length], "00A".length);
9533         second = _convDigits!short(value[0 .. 2]);
9534         // this is just if/until SysTime is sorted out to fully support leap seconds
9535         if (second == 60)
9536             second = 59;
9537         stripAndCheckLen(value[2 .. value.length], "A".length);
9538     }
9539 
9540     immutable(TimeZone) parseTZ(int sign)
9541     {
9542         if (value.length < 5)
9543             throw new DateTimeException("Invalid timezone");
9544         immutable zoneHours = _convDigits!short(value[1 .. 3]);
9545         immutable zoneMinutes = _convDigits!short(value[3 .. 5]);
9546         if (zoneHours == -1 || zoneMinutes == -1 || zoneMinutes > 59)
9547             throw new DateTimeException("Invalid timezone");
9548         value = value[5 .. value.length];
9549         immutable utcOffset = (dur!"hours"(zoneHours) + dur!"minutes"(zoneMinutes)) * sign;
9550         if (utcOffset == Duration.zero)
9551         {
9552             return sign == 1 ? cast(immutable(TimeZone))UTC()
9553                              : cast(immutable(TimeZone))new immutable SimpleTimeZone(Duration.zero);
9554         }
9555         return new immutable(SimpleTimeZone)(utcOffset);
9556     }
9557 
9558     // zone
9559     Rebindable!(immutable TimeZone) tz;
9560     if (value[0] == '-')
9561         tz = parseTZ(-1);
9562     else if (value[0] == '+')
9563         tz = parseTZ(1);
9564     else
9565     {
9566         // obs-zone
9567         immutable tzLen = value.length - find(value, ' ', '\t', '(')[0].length;
9568         switch (sliceAsString(value[0 .. tzLen <= 4 ? tzLen : 4]))
9569         {
9570             case "UT": case "GMT": tz = UTC(); break;
9571             case "EST": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
9572             case "EDT": tz = new immutable SimpleTimeZone(dur!"hours"(-4)); break;
9573             case "CST": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
9574             case "CDT": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
9575             case "MST": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
9576             case "MDT": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
9577             case "PST": tz = new immutable SimpleTimeZone(dur!"hours"(-8)); break;
9578             case "PDT": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
9579             case "J": case "j": throw new DateTimeException("Invalid timezone");
9580             default:
9581             {
9582                 if (all!(std.ascii.isAlpha)(value[0 .. tzLen]))
9583                 {
9584                     tz = new immutable SimpleTimeZone(Duration.zero);
9585                     break;
9586                 }
9587                 throw new DateTimeException("Invalid timezone");
9588             }
9589         }
9590         value = value[tzLen .. value.length];
9591     }
9592 
9593     // This is kind of arbitrary. Technically, nothing but CFWS is legal past
9594     // the end of the timezone, but we don't want to be picky about that in a
9595     // function that's just parsing rather than validating. So, the idea here is
9596     // that if the next character is printable (and not part of CFWS), then it
9597     // might be part of the timezone and thus affect what the timezone was
9598     // supposed to be, so we'll throw, but otherwise, we'll just ignore it.
9599     if (!value.empty && isPrintable(value[0]) && value[0] != ' ' && value[0] != '(')
9600         throw new DateTimeException("Invalid timezone");
9601 
9602     try
9603         return SysTime(DateTime(year, month, day, hour, minute, second), tz);
9604     catch (DateTimeException dte)
9605         throw new DateTimeException("date-time format is correct, but the resulting SysTime is invalid.", dte);
9606 }
9607 
9608 ///
9609 @safe unittest
9610 {
9611     import core.time : hours;
9612     import std.datetime.date : DateTime, DateTimeException;
9613     import std.datetime.timezone : SimpleTimeZone, UTC;
9614     import std.exception : assertThrown;
9615 
9616     auto tz = new immutable SimpleTimeZone(hours(-8));
9617     assert(parseRFC822DateTime("Sat, 6 Jan 1990 12:14:19 -0800") ==
9618            SysTime(DateTime(1990, 1, 6, 12, 14, 19), tz));
9619 
9620     assert(parseRFC822DateTime("9 Jul 2002 13:11 +0000") ==
9621            SysTime(DateTime(2002, 7, 9, 13, 11, 0), UTC()));
9622 
9623     auto badStr = "29 Feb 2001 12:17:16 +0200";
9624     assertThrown!DateTimeException(parseRFC822DateTime(badStr));
9625 }
9626 
version(unittest)9627 version (unittest) void testParse822(alias cr)(string str, SysTime expected, size_t line = __LINE__)
9628 {
9629     import std.format : format;
9630     auto value = cr(str);
9631     auto result = parseRFC822DateTime(value);
9632     if (result != expected)
9633         throw new AssertError(format("wrong result. expected [%s], actual[%s]", expected, result), __FILE__, line);
9634 }
9635 
version(unittest)9636 version (unittest) void testBadParse822(alias cr)(string str, size_t line = __LINE__)
9637 {
9638     try
9639         parseRFC822DateTime(cr(str));
9640     catch (DateTimeException)
9641         return;
9642     throw new AssertError("No DateTimeException was thrown", __FILE__, line);
9643 }
9644 
9645 @system unittest
9646 {
9647     import std.algorithm.iteration : filter, map;
9648     import std.algorithm.searching : canFind;
9649     import std.array : array;
9650     import std.ascii : letters;
9651     import std.format : format;
9652     import std.meta : AliasSeq;
9653     import std.range : chain, iota, take;
9654     import std.stdio : writefln, writeln;
9655     import std.string : representation;
9656 
9657     static struct Rand3Letters
9658     {
9659         enum empty = false;
frontRand3Letters9660         @property auto front() { return _mon; }
popFrontRand3Letters9661         void popFront()
9662         {
9663             import std.exception : assumeUnique;
9664             import std.random : rndGen;
9665             _mon = rndGen.map!(a => letters[a % letters.length])().take(3).array().assumeUnique();
9666         }
9667         string _mon;
startRand3Letters9668         static auto start() { Rand3Letters retval; retval.popFront(); return retval; }
9669     }
9670 
9671     foreach (cr; AliasSeq!(function(string a){return cast(char[]) a;},
9672                            function(string a){return cast(ubyte[]) a;},
9673                            function(string a){return a;},
9674                            function(string a){return map!(b => cast(char) b)(a.representation);}))
9675     (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
9676         scope(failure) writeln(typeof(cr).stringof);
9677         alias test = testParse822!cr;
9678         alias testBad = testBadParse822!cr;
9679 
9680         immutable std1 = DateTime(2012, 12, 21, 13, 14, 15);
9681         immutable std2 = DateTime(2012, 12, 21, 13, 14, 0);
9682         immutable dst1 = DateTime(1976, 7, 4, 5, 4, 22);
9683         immutable dst2 = DateTime(1976, 7, 4, 5, 4, 0);
9684 
9685         test("21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
9686         test("21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
9687         test("Fri, 21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
9688         test("Fri, 21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
9689 
9690         test("04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
9691         test("04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
9692         test("Sun, 04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
9693         test("Sun, 04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
9694 
9695         test("4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
9696         test("4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
9697         test("Sun, 4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
9698         test("Sun, 4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
9699 
9700         auto badTZ = new immutable SimpleTimeZone(Duration.zero);
9701         test("21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
9702         test("21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
9703         test("Fri, 21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
9704         test("Fri, 21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
9705 
9706         test("04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
9707         test("04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
9708         test("Sun, 04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
9709         test("Sun, 04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
9710 
9711         test("4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
9712         test("4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
9713         test("Sun, 4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
9714         test("Sun, 4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
9715 
9716         auto pst = new immutable SimpleTimeZone(dur!"hours"(-8));
9717         auto pdt = new immutable SimpleTimeZone(dur!"hours"(-7));
9718         test("21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
9719         test("21 Dec 2012 13:14 -0800", SysTime(std2, pst));
9720         test("Fri, 21 Dec 2012 13:14 -0800", SysTime(std2, pst));
9721         test("Fri, 21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
9722 
9723         test("04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
9724         test("04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
9725         test("Sun, 04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
9726         test("Sun, 04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
9727 
9728         test("4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
9729         test("4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
9730         test("Sun, 4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
9731         test("Sun, 4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
9732 
9733         auto cet = new immutable SimpleTimeZone(dur!"hours"(1));
9734         auto cest = new immutable SimpleTimeZone(dur!"hours"(2));
9735         test("21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
9736         test("21 Dec 2012 13:14 +0100", SysTime(std2, cet));
9737         test("Fri, 21 Dec 2012 13:14 +0100", SysTime(std2, cet));
9738         test("Fri, 21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
9739 
9740         test("04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
9741         test("04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
9742         test("Sun, 04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
9743         test("Sun, 04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
9744 
9745         test("4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
9746         test("4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
9747         test("Sun, 4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
9748         test("Sun, 4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
9749 
9750         // dst and std times are switched in the Southern Hemisphere which is why the
9751         // time zone names and DateTime variables don't match.
9752         auto cstStd = new immutable SimpleTimeZone(dur!"hours"(9) + dur!"minutes"(30));
9753         auto cstDST = new immutable SimpleTimeZone(dur!"hours"(10) + dur!"minutes"(30));
9754         test("21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
9755         test("21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
9756         test("Fri, 21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
9757         test("Fri, 21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
9758 
9759         test("04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
9760         test("04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
9761         test("Sun, 04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
9762         test("Sun, 04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
9763 
9764         test("4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
9765         test("4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
9766         test("Sun, 4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
9767         test("Sun, 4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
9768 
foreach(int i,mon;_monthNames)9769         foreach (int i, mon; _monthNames)
9770         {
9771             test(format("17 %s 2012 00:05:02 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 2), UTC()));
9772             test(format("17 %s 2012 00:05 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 0), UTC()));
9773         }
9774 
9775         import std.uni : toLower, toUpper;
9776         foreach (mon; chain(_monthNames[].map!(a => toLower(a))(),
9777                             _monthNames[].map!(a => toUpper(a))(),
9778                             ["Jam", "Jen", "Fec", "Fdb", "Mas", "Mbr", "Aps", "Aqr", "Mai", "Miy",
9779                              "Jum", "Jbn", "Jup", "Jal", "Aur", "Apg", "Sem", "Sap", "Ocm", "Odt",
9780                              "Nom", "Nav", "Dem", "Dac"],
9781                             Rand3Letters.start().filter!(a => !_monthNames[].canFind(a)).take(20)))
9782         {
9783             scope(failure) writefln("Month: %s", mon);
9784             testBad(format("17 %s 2012 00:05:02 +0000", mon));
9785             testBad(format("17 %s 2012 00:05 +0000", mon));
9786         }
9787 
9788         immutable string[7] daysOfWeekNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
9789 
9790         {
9791             auto start = SysTime(DateTime(2012, 11, 11, 9, 42, 0), UTC());
9792             int day = 11;
9793 
foreach(int i,dow;daysOfWeekNames)9794             foreach (int i, dow; daysOfWeekNames)
9795             {
9796                 auto curr = start + dur!"days"(i);
9797                 test(format("%s, %s Nov 2012 09:42:00 +0000", dow, day), curr);
9798                 test(format("%s, %s Nov 2012 09:42 +0000", dow, day++), curr);
9799 
9800                 // Whether the day of the week matches the date is ignored.
9801                 test(format("%s, 11 Nov 2012 09:42:00 +0000", dow), start);
9802                 test(format("%s, 11 Nov 2012 09:42 +0000", dow), start);
9803             }
9804         }
9805 
9806         foreach (dow; chain(daysOfWeekNames[].map!(a => toLower(a))(),
9807                             daysOfWeekNames[].map!(a => toUpper(a))(),
9808                             ["Sum", "Spn", "Mom", "Man", "Tuf", "Tae", "Wem", "Wdd", "The", "Tur",
9809                              "Fro", "Fai", "San", "Sut"],
9810                             Rand3Letters.start().filter!(a => !daysOfWeekNames[].canFind(a)).take(20)))
9811         {
9812             scope(failure) writefln("Day of Week: %s", dow);
9813             testBad(format("%s, 11 Nov 2012 09:42:00 +0000", dow));
9814             testBad(format("%s, 11 Nov 2012 09:42 +0000", dow));
9815         }
9816 
9817         testBad("31 Dec 1899 23:59:59 +0000");
9818         test("01 Jan 1900 00:00:00 +0000", SysTime(Date(1900, 1, 1), UTC()));
9819         test("01 Jan 1900 00:00:00 -0000", SysTime(Date(1900, 1, 1),
9820                                                    new immutable SimpleTimeZone(Duration.zero)));
9821         test("01 Jan 1900 00:00:00 -0700", SysTime(Date(1900, 1, 1),
9822                                                    new immutable SimpleTimeZone(dur!"hours"(-7))));
9823 
9824         {
9825             auto st1 = SysTime(Date(1900, 1, 1), UTC());
9826             auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
9827             foreach (i; 1900 .. 2102)
9828             {
9829                 test(format("1 Jan %05d 00:00 +0000", i), st1);
9830                 test(format("1 Jan %05d 00:00 -1100", i), st2);
9831                 st1.add!"years"(1);
9832                 st2.add!"years"(1);
9833             }
9834             st1.year = 9998;
9835             st2.year = 9998;
9836             foreach (i; 9998 .. 11_002)
9837             {
9838                 test(format("1 Jan %05d 00:00 +0000", i), st1);
9839                 test(format("1 Jan %05d 00:00 -1100", i), st2);
9840                 st1.add!"years"(1);
9841                 st2.add!"years"(1);
9842             }
9843         }
9844 
9845         testBad("12 Feb 1907 23:17:09 0000");
9846         testBad("12 Feb 1907 23:17:09 +000");
9847         testBad("12 Feb 1907 23:17:09 -000");
9848         testBad("12 Feb 1907 23:17:09 +00000");
9849         testBad("12 Feb 1907 23:17:09 -00000");
9850         testBad("12 Feb 1907 23:17:09 +A");
9851         testBad("12 Feb 1907 23:17:09 +PST");
9852         testBad("12 Feb 1907 23:17:09 -A");
9853         testBad("12 Feb 1907 23:17:09 -PST");
9854 
9855         // test trailing stuff that gets ignored
9856         {
9857             foreach (c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
9858             {
9859                 scope(failure) writefln("c: %d", c);
9860                 test(format("21 Dec 2012 13:14:15 +0000%c", cast(char) c), SysTime(std1, UTC()));
9861                 test(format("21 Dec 2012 13:14:15 +0000%c  ", cast(char) c), SysTime(std1, UTC()));
9862                 test(format("21 Dec 2012 13:14:15 +0000%chello", cast(char) c), SysTime(std1, UTC()));
9863             }
9864         }
9865 
9866         // test trailing stuff that doesn't get ignored
9867         {
9868             foreach (c; chain(iota(33, '('), iota('(' + 1, 127)))
9869             {
9870                 scope(failure) writefln("c: %d", c);
9871                 testBad(format("21 Dec 2012 13:14:15 +0000%c", cast(char) c));
9872                 testBad(format("21 Dec 2012 13:14:15 +0000%c   ", cast(char) c));
9873                 testBad(format("21 Dec 2012 13:14:15 +0000%chello", cast(char) c));
9874             }
9875         }
9876 
9877         testBad("32 Jan 2012 12:13:14 -0800");
9878         testBad("31 Jan 2012 24:13:14 -0800");
9879         testBad("31 Jan 2012 12:60:14 -0800");
9880         testBad("31 Jan 2012 12:13:61 -0800");
9881         testBad("31 Jan 2012 12:13:14 -0860");
9882         test("31 Jan 2012 12:13:14 -0859",
9883              SysTime(DateTime(2012, 1, 31, 12, 13, 14),
9884                      new immutable SimpleTimeZone(dur!"hours"(-8) + dur!"minutes"(-59))));
9885 
9886         // leap-seconds
9887         test("21 Dec 2012 15:59:60 -0800", SysTime(DateTime(2012, 12, 21, 15, 59, 59), pst));
9888 
9889         // FWS
9890         test("Sun,4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
9891         test("Sun,4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
9892         test("Sun,4 Jul 1976 05:04 +0930 (foo)", SysTime(dst2, cstStd));
9893         test("Sun,4 Jul 1976 05:04:22 +0930 (foo)", SysTime(dst1, cstStd));
9894         test("Sun,4  \r\n  Jul  \r\n  1976  \r\n  05:04  \r\n  +0930  \r\n  (foo)", SysTime(dst2, cstStd));
9895         test("Sun,4  \r\n  Jul  \r\n  1976  \r\n  05:04:22  \r\n  +0930  \r\n  (foo)", SysTime(dst1, cstStd));
9896 
9897         auto str = "01 Jan 2012 12:13:14 -0800 ";
9898         test(str, SysTime(DateTime(2012, 1, 1, 12, 13, 14), new immutable SimpleTimeZone(hours(-8))));
9899         foreach (i; 0 .. str.length)
9900         {
9901             auto currStr = str.dup;
9902             currStr[i] = 'x';
9903             scope(failure) writefln("failed: %s", currStr);
9904             testBad(cast(string) currStr);
9905         }
9906         foreach (i; 2 .. str.length)
9907         {
9908             auto currStr = str[0 .. $ - i];
9909             scope(failure) writefln("failed: %s", currStr);
9910             testBad(cast(string) currStr);
9911             testBad((cast(string) currStr) ~ "                                    ");
9912         }
9913     }();
9914 }
9915 
9916 // Obsolete Format per section 4.3 of RFC 5322.
9917 @system unittest
9918 {
9919     import std.algorithm.iteration : filter, map;
9920     import std.ascii : letters;
9921     import std.exception : collectExceptionMsg;
9922     import std.format : format;
9923     import std.meta : AliasSeq;
9924     import std.range : chain, iota;
9925     import std.stdio : writefln, writeln;
9926     import std.string : representation;
9927 
9928     auto std1 = SysTime(DateTime(2012, 12, 21, 13, 14, 15), UTC());
9929     auto std2 = SysTime(DateTime(2012, 12, 21, 13, 14, 0), UTC());
9930     auto std3 = SysTime(DateTime(1912, 12, 21, 13, 14, 15), UTC());
9931     auto std4 = SysTime(DateTime(1912, 12, 21, 13, 14, 0), UTC());
9932     auto dst1 = SysTime(DateTime(1976, 7, 4, 5, 4, 22), UTC());
9933     auto dst2 = SysTime(DateTime(1976, 7, 4, 5, 4, 0), UTC());
9934     auto tooLate1 = SysTime(Date(10_000, 1, 1), UTC());
9935     auto tooLate2 = SysTime(DateTime(12_007, 12, 31, 12, 22, 19), UTC());
9936 
9937     foreach (cr; AliasSeq!(function(string a){return cast(char[]) a;},
9938                            function(string a){return cast(ubyte[]) a;},
9939                            function(string a){return a;},
9940                            function(string a){return map!(b => cast(char) b)(a.representation);}))
9941     (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
9942         scope(failure) writeln(typeof(cr).stringof);
9943         alias test = testParse822!cr;
9944         {
9945             auto list = ["", " ", " \r\n\t", "\t\r\n (hello world( frien(dog)) silly \r\n )  \t\t \r\n ()",
9946                          " \n ", "\t\n\t", " \n\t (foo) \n (bar) \r\n (baz) \n "];
9947 
foreach(i,cfws;list)9948             foreach (i, cfws; list)
9949             {
9950                 scope(failure) writefln("i: %s", i);
9951 
9952                 test(format("%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
9953                 test(format("%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
9954                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
9955                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
9956 
9957                 test(format("%1$s04%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
9958                 test(format("%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
9959                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
9960                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04:22 +0000%1$s", cfws), dst1);
9961 
9962                 test(format("%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
9963                 test(format("%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
9964                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
9965                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
9966 
9967                 test(format("%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
9968                 test(format("%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
9969                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
9970                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
9971 
9972                 test(format("%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
9973                 test(format("%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
9974                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
9975                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
9976 
9977                 test(format("%1$s4%1$sJul%1$s76 05:04:22%1$s+0000%1$s", cfws), dst1);
9978                 test(format("%1$s4%1$sJul%1$s76 05:04%1$s+0000%1$s", cfws), dst2);
9979                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
9980                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
9981 
9982                 test(format("%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
9983                 test(format("%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
9984                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
9985                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
9986 
9987                 test(format("%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
9988                 test(format("%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
9989                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
9990                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
9991 
9992                 test(format("%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
9993                 test(format("%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
9994                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
9995                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
9996 
9997                 test(format("%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
9998                 test(format("%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
9999                 test(format("%1$sSat%1$s,%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
10000                 test(format("%1$sSun%1$s,%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
10001             }
10002         }
10003 
10004         // test years of 1, 2, and 3 digits.
10005         {
10006             auto st1 = SysTime(Date(2000, 1, 1), UTC());
10007             auto st2 = SysTime(Date(2000, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
10008             foreach (i; 0 .. 50)
10009             {
10010                 test(format("1 Jan %02d 00:00 GMT", i), st1);
10011                 test(format("1 Jan %02d 00:00 -1200", i), st2);
10012                 st1.add!"years"(1);
10013                 st2.add!"years"(1);
10014             }
10015         }
10016 
10017         {
10018             auto st1 = SysTime(Date(1950, 1, 1), UTC());
10019             auto st2 = SysTime(Date(1950, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
10020             foreach (i; 50 .. 100)
10021             {
10022                 test(format("1 Jan %02d 00:00 GMT", i), st1);
10023                 test(format("1 Jan %02d 00:00 -1200", i), st2);
10024                 st1.add!"years"(1);
10025                 st2.add!"years"(1);
10026             }
10027         }
10028 
10029         {
10030             auto st1 = SysTime(Date(1900, 1, 1), UTC());
10031             auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
10032             foreach (i; 0 .. 1000)
10033             {
10034                 test(format("1 Jan %03d 00:00 GMT", i), st1);
10035                 test(format("1 Jan %03d 00:00 -1100", i), st2);
10036                 st1.add!"years"(1);
10037                 st2.add!"years"(1);
10038             }
10039         }
10040 
10041         foreach (i; 0 .. 10)
10042         {
10043             auto str1 = cr(format("1 Jan %d 00:00 GMT", i));
10044             auto str2 = cr(format("1 Jan %d 00:00 -1200", i));
10045             assertThrown!DateTimeException(parseRFC822DateTime(str1));
10046             assertThrown!DateTimeException(parseRFC822DateTime(str1));
10047         }
10048 
10049         // test time zones
10050         {
10051             auto dt = DateTime(1982, 05, 03, 12, 22, 04);
10052             test("Wed, 03 May 1982 12:22:04 UT", SysTime(dt, UTC()));
10053             test("Wed, 03 May 1982 12:22:04 GMT", SysTime(dt, UTC()));
10054             test("Wed, 03 May 1982 12:22:04 EST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
10055             test("Wed, 03 May 1982 12:22:04 EDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-4))));
10056             test("Wed, 03 May 1982 12:22:04 CST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
10057             test("Wed, 03 May 1982 12:22:04 CDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
10058             test("Wed, 03 May 1982 12:22:04 MST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
10059             test("Wed, 03 May 1982 12:22:04 MDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
10060             test("Wed, 03 May 1982 12:22:04 PST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-8))));
10061             test("Wed, 03 May 1982 12:22:04 PDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
10062 
10063             auto badTZ = new immutable SimpleTimeZone(Duration.zero);
10064             foreach (dchar c; filter!(a => a != 'j' && a != 'J')(letters))
10065             {
10066                 scope(failure) writefln("c: %s", c);
10067                 test(format("Wed, 03 May 1982 12:22:04 %s", c), SysTime(dt, badTZ));
10068                 test(format("Wed, 03 May 1982 12:22:04%s", c), SysTime(dt, badTZ));
10069             }
10070 
foreach(dchar c;['j','J'])10071             foreach (dchar c; ['j', 'J'])
10072             {
10073                 scope(failure) writefln("c: %s", c);
10074                 assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04 %s", c))));
10075                 assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04%s", c))));
10076             }
10077 
foreach(string s;["AAA","GQW","DDT","PDA","GT","GM"])10078             foreach (string s; ["AAA", "GQW", "DDT", "PDA", "GT", "GM"])
10079             {
10080                 scope(failure) writefln("s: %s", s);
10081                 test(format("Wed, 03 May 1982 12:22:04 %s", s), SysTime(dt, badTZ));
10082             }
10083 
10084             // test trailing stuff that gets ignored
10085             {
10086                 foreach (c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
10087                 {
10088                     scope(failure) writefln("c: %d", c);
10089                     test(format("21Dec1213:14:15+0000%c", cast(char) c), std1);
10090                     test(format("21Dec1213:14:15+0000%c  ", cast(char) c), std1);
10091                     test(format("21Dec1213:14:15+0000%chello", cast(char) c), std1);
10092                 }
10093             }
10094 
10095             // test trailing stuff that doesn't get ignored
10096             {
10097                 foreach (c; chain(iota(33, '('), iota('(' + 1, 127)))
10098                 {
10099                     scope(failure) writefln("c: %d", c);
10100                     assertThrown!DateTimeException(
10101                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c", cast(char) c))));
10102                     assertThrown!DateTimeException(
10103                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c  ", cast(char) c))));
10104                     assertThrown!DateTimeException(
10105                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%chello", cast(char) c))));
10106                 }
10107             }
10108         }
10109 
10110         // test that the checks for minimum length work correctly and avoid
10111         // any RangeErrors.
10112         test("7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
10113                                      new immutable SimpleTimeZone(Duration.zero)));
10114         test("Fri,7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
10115                                          new immutable SimpleTimeZone(Duration.zero)));
10116         test("7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
10117                                         new immutable SimpleTimeZone(Duration.zero)));
10118         test("Fri,7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
10119                                             new immutable SimpleTimeZone(Duration.zero)));
10120 
10121         auto tooShortMsg = collectExceptionMsg!DateTimeException(parseRFC822DateTime(""));
foreach(str;["Fri,7Dec1200:00:00","7Dec1200:00:00"])10122         foreach (str; ["Fri,7Dec1200:00:00", "7Dec1200:00:00"])
10123         {
10124             foreach (i; 0 .. str.length)
10125             {
10126                 auto value = str[0 .. $ - i];
10127                 scope(failure) writeln(value);
10128                 assert(collectExceptionMsg!DateTimeException(parseRFC822DateTime(value)) == tooShortMsg);
10129             }
10130         }
10131     }();
10132 }
10133 
10134 
10135 private:
10136 
10137 /+
10138     Returns the given hnsecs as an ISO string of fractional seconds.
10139   +/
fracSecsToISOString(int hnsecs)10140 static string fracSecsToISOString(int hnsecs) @safe pure nothrow
10141 {
10142     assert(hnsecs >= 0);
10143 
10144     try
10145     {
10146         if (hnsecs == 0)
10147             return "";
10148 
10149         string isoString = format(".%07d", hnsecs);
10150 
10151         while (isoString[$ - 1] == '0')
10152             isoString.popBack();
10153 
10154         return isoString;
10155     }
10156     catch (Exception e)
10157         assert(0, "format() threw.");
10158 }
10159 
10160 @safe unittest
10161 {
10162     assert(fracSecsToISOString(0) == "");
10163     assert(fracSecsToISOString(1) == ".0000001");
10164     assert(fracSecsToISOString(10) == ".000001");
10165     assert(fracSecsToISOString(100) == ".00001");
10166     assert(fracSecsToISOString(1000) == ".0001");
10167     assert(fracSecsToISOString(10_000) == ".001");
10168     assert(fracSecsToISOString(100_000) == ".01");
10169     assert(fracSecsToISOString(1_000_000) == ".1");
10170     assert(fracSecsToISOString(1_000_001) == ".1000001");
10171     assert(fracSecsToISOString(1_001_001) == ".1001001");
10172     assert(fracSecsToISOString(1_071_601) == ".1071601");
10173     assert(fracSecsToISOString(1_271_641) == ".1271641");
10174     assert(fracSecsToISOString(9_999_999) == ".9999999");
10175     assert(fracSecsToISOString(9_999_990) == ".999999");
10176     assert(fracSecsToISOString(9_999_900) == ".99999");
10177     assert(fracSecsToISOString(9_999_000) == ".9999");
10178     assert(fracSecsToISOString(9_990_000) == ".999");
10179     assert(fracSecsToISOString(9_900_000) == ".99");
10180     assert(fracSecsToISOString(9_000_000) == ".9");
10181     assert(fracSecsToISOString(999) == ".0000999");
10182     assert(fracSecsToISOString(9990) == ".000999");
10183     assert(fracSecsToISOString(99_900) == ".00999");
10184     assert(fracSecsToISOString(999_000) == ".0999");
10185 }
10186 
10187 
10188 /+
10189     Returns a Duration corresponding to to the given ISO string of
10190     fractional seconds.
10191   +/
10192 static Duration fracSecsFromISOString(S)(in S isoString) @trusted pure
10193 if (isSomeString!S)
10194 {
10195     import std.algorithm.searching : all;
10196     import std.ascii : isDigit;
10197     import std.conv : to;
10198     import std.string : representation;
10199 
10200     if (isoString.empty)
10201         return Duration.zero;
10202 
10203     auto str = isoString.representation;
10204 
10205     enforce(str[0] == '.', new DateTimeException("Invalid ISO String"));
10206     str.popFront();
10207 
10208     enforce(!str.empty && all!isDigit(str), new DateTimeException("Invalid ISO String"));
10209 
10210     dchar[7] fullISOString = void;
foreach(i,ref dchar c;fullISOString)10211     foreach (i, ref dchar c; fullISOString)
10212     {
10213         if (i < str.length)
10214             c = str[i];
10215         else
10216             c = '0';
10217     }
10218 
10219     return hnsecs(to!int(fullISOString[]));
10220 }
10221 
10222 @safe unittest
10223 {
testFSInvalid(string isoString)10224     static void testFSInvalid(string isoString)
10225     {
10226         fracSecsFromISOString(isoString);
10227     }
10228 
10229     assertThrown!DateTimeException(testFSInvalid("."));
10230     assertThrown!DateTimeException(testFSInvalid("0."));
10231     assertThrown!DateTimeException(testFSInvalid("0"));
10232     assertThrown!DateTimeException(testFSInvalid("0000000"));
10233     assertThrown!DateTimeException(testFSInvalid("T"));
10234     assertThrown!DateTimeException(testFSInvalid("T."));
10235     assertThrown!DateTimeException(testFSInvalid(".T"));
10236     assertThrown!DateTimeException(testFSInvalid(".00000Q0"));
10237     assertThrown!DateTimeException(testFSInvalid(".000000Q"));
10238     assertThrown!DateTimeException(testFSInvalid(".0000000Q"));
10239     assertThrown!DateTimeException(testFSInvalid(".0000000000Q"));
10240 
10241     assert(fracSecsFromISOString("") == Duration.zero);
10242     assert(fracSecsFromISOString(".0000001") == hnsecs(1));
10243     assert(fracSecsFromISOString(".000001") == hnsecs(10));
10244     assert(fracSecsFromISOString(".00001") == hnsecs(100));
10245     assert(fracSecsFromISOString(".0001") == hnsecs(1000));
10246     assert(fracSecsFromISOString(".001") == hnsecs(10_000));
10247     assert(fracSecsFromISOString(".01") == hnsecs(100_000));
10248     assert(fracSecsFromISOString(".1") == hnsecs(1_000_000));
10249     assert(fracSecsFromISOString(".1000001") == hnsecs(1_000_001));
10250     assert(fracSecsFromISOString(".1001001") == hnsecs(1_001_001));
10251     assert(fracSecsFromISOString(".1071601") == hnsecs(1_071_601));
10252     assert(fracSecsFromISOString(".1271641") == hnsecs(1_271_641));
10253     assert(fracSecsFromISOString(".9999999") == hnsecs(9_999_999));
10254     assert(fracSecsFromISOString(".9999990") == hnsecs(9_999_990));
10255     assert(fracSecsFromISOString(".999999") == hnsecs(9_999_990));
10256     assert(fracSecsFromISOString(".9999900") == hnsecs(9_999_900));
10257     assert(fracSecsFromISOString(".99999") == hnsecs(9_999_900));
10258     assert(fracSecsFromISOString(".9999000") == hnsecs(9_999_000));
10259     assert(fracSecsFromISOString(".9999") == hnsecs(9_999_000));
10260     assert(fracSecsFromISOString(".9990000") == hnsecs(9_990_000));
10261     assert(fracSecsFromISOString(".999") == hnsecs(9_990_000));
10262     assert(fracSecsFromISOString(".9900000") == hnsecs(9_900_000));
10263     assert(fracSecsFromISOString(".9900") == hnsecs(9_900_000));
10264     assert(fracSecsFromISOString(".99") == hnsecs(9_900_000));
10265     assert(fracSecsFromISOString(".9000000") == hnsecs(9_000_000));
10266     assert(fracSecsFromISOString(".9") == hnsecs(9_000_000));
10267     assert(fracSecsFromISOString(".0000999") == hnsecs(999));
10268     assert(fracSecsFromISOString(".0009990") == hnsecs(9990));
10269     assert(fracSecsFromISOString(".000999") == hnsecs(9990));
10270     assert(fracSecsFromISOString(".0099900") == hnsecs(99_900));
10271     assert(fracSecsFromISOString(".00999") == hnsecs(99_900));
10272     assert(fracSecsFromISOString(".0999000") == hnsecs(999_000));
10273     assert(fracSecsFromISOString(".0999") == hnsecs(999_000));
10274     assert(fracSecsFromISOString(".00000000") == Duration.zero);
10275     assert(fracSecsFromISOString(".00000001") == Duration.zero);
10276     assert(fracSecsFromISOString(".00000009") == Duration.zero);
10277     assert(fracSecsFromISOString(".1234567890") == hnsecs(1_234_567));
10278     assert(fracSecsFromISOString(".12345678901234567890") == hnsecs(1_234_567));
10279 }
10280 
10281 
10282 /+
10283     This function is used to split out the units without getting the remaining
10284     hnsecs.
10285 
10286     Params:
10287         units  = The units to split out.
10288         hnsecs = The current total hnsecs.
10289 
10290     Returns:
10291         The split out value.
10292   +/
10293 long getUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
10294 if (validTimeUnits(units) &&
10295     CmpTimeUnits!(units, "months") < 0)
10296 {
10297     return convert!("hnsecs", units)(hnsecs);
10298 }
10299 
10300 @safe unittest
10301 {
10302     auto hnsecs = 2595000000007L;
10303     immutable days = getUnitsFromHNSecs!"days"(hnsecs);
10304     assert(days == 3);
10305     assert(hnsecs == 2595000000007L);
10306 }
10307 
10308 
10309 /+
10310     This function is used to split out the units without getting the units but
10311     just the remaining hnsecs.
10312 
10313     Params:
10314         units  = The units to split out.
10315         hnsecs = The current total hnsecs.
10316 
10317     Returns:
10318         The remaining hnsecs.
10319   +/
10320 long removeUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
10321 if (validTimeUnits(units) &&
10322     CmpTimeUnits!(units, "months") < 0)
10323 {
10324     immutable value = convert!("hnsecs", units)(hnsecs);
10325     return hnsecs - convert!(units, "hnsecs")(value);
10326 }
10327 
10328 @safe unittest
10329 {
10330     auto hnsecs = 2595000000007L;
10331     auto returned = removeUnitsFromHNSecs!"days"(hnsecs);
10332     assert(returned == 3000000007);
10333     assert(hnsecs == 2595000000007L);
10334 }
10335 
10336 
10337 /+
10338     Strips what RFC 5322, section 3.2.2 refers to as CFWS from the left-hand
10339     side of the given range (it strips comments delimited by $(D '(') and
10340     $(D ')') as well as folding whitespace).
10341 
10342     It is assumed that the given range contains the value of a header field and
10343     no terminating CRLF for the line (though the CRLF for folding whitespace is
10344     of course expected and stripped) and thus that the only case of CR or LF is
10345     in folding whitespace.
10346 
10347     If a comment does not terminate correctly (e.g. mismatched parens) or if the
10348     the FWS is malformed, then the range will be empty when stripCWFS is done.
10349     However, only minimal validation of the content is done (e.g. quoted pairs
10350     within a comment aren't validated beyond \$LPAREN or \$RPAREN, because
10351     they're inside a comment, and thus their value doesn't matter anyway). It's
10352     only when the content does not conform to the grammar rules for FWS and thus
10353     literally cannot be parsed that content is considered invalid, and an empty
10354     range is returned.
10355 
10356     Note that _stripCFWS is eager, not lazy. It does not create a new range.
10357     Rather, it pops off the CFWS from the range and returns it.
10358   +/
10359 R _stripCFWS(R)(R range)
10360 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
10361     (is(Unqual!(ElementType!R) == char) || is(Unqual!(ElementType!R) == ubyte)))
10362 {
10363     immutable e = range.length;
10364     outer: for (size_t i = 0; i < e; )
10365     {
10366         switch (range[i])
10367         {
10368             case ' ': case '\t':
10369             {
10370                 ++i;
10371                 break;
10372             }
10373             case '\r':
10374             {
10375                 if (i + 2 < e && range[i + 1] == '\n' && (range[i + 2] == ' ' || range[i + 2] == '\t'))
10376                 {
10377                     i += 3;
10378                     break;
10379                 }
10380                 break outer;
10381             }
10382             case '\n':
10383             {
10384                 if (i + 1 < e && (range[i + 1] == ' ' || range[i + 1] == '\t'))
10385                 {
10386                     i += 2;
10387                     break;
10388                 }
10389                 break outer;
10390             }
10391             case '(':
10392             {
10393                 ++i;
10394                 size_t commentLevel = 1;
10395                 while (i < e)
10396                 {
10397                     if (range[i] == '(')
10398                         ++commentLevel;
10399                     else if (range[i] == ')')
10400                     {
10401                         ++i;
10402                         if (--commentLevel == 0)
10403                             continue outer;
10404                         continue;
10405                     }
10406                     else if (range[i] == '\\')
10407                     {
10408                         if (++i == e)
10409                             break outer;
10410                     }
10411                     ++i;
10412                 }
10413                 break outer;
10414             }
10415             default: return range[i .. e];
10416         }
10417     }
10418     return range[e .. e];
10419 }
10420 
10421 @system unittest
10422 {
10423     import std.algorithm.comparison : equal;
10424     import std.algorithm.iteration : map;
10425     import std.meta : AliasSeq;
10426     import std.stdio : writeln;
10427     import std.string : representation;
10428 
10429     foreach (cr; AliasSeq!(function(string a){return cast(ubyte[]) a;},
10430                            function(string a){return map!(b => cast(char) b)(a.representation);}))
10431     (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
10432         scope(failure) writeln(typeof(cr).stringof);
10433 
10434         assert(_stripCFWS(cr("")).empty);
10435         assert(_stripCFWS(cr("\r")).empty);
10436         assert(_stripCFWS(cr("\r\n")).empty);
10437         assert(_stripCFWS(cr("\r\n ")).empty);
10438         assert(_stripCFWS(cr(" \t\r\n")).empty);
10439         assert(equal(_stripCFWS(cr(" \t\r\n hello")), cr("hello")));
10440         assert(_stripCFWS(cr(" \t\r\nhello")).empty);
10441         assert(_stripCFWS(cr(" \t\r\n\v")).empty);
10442         assert(equal(_stripCFWS(cr("\v \t\r\n\v")), cr("\v \t\r\n\v")));
10443         assert(_stripCFWS(cr("()")).empty);
10444         assert(_stripCFWS(cr("(hello world)")).empty);
10445         assert(_stripCFWS(cr("(hello world)(hello world)")).empty);
10446         assert(_stripCFWS(cr("(hello world\r\n foo\r where's\nwaldo)")).empty);
10447         assert(_stripCFWS(cr(" \t (hello \tworld\r\n foo\r where's\nwaldo)\t\t ")).empty);
10448         assert(_stripCFWS(cr("      ")).empty);
10449         assert(_stripCFWS(cr("\t\t\t")).empty);
10450         assert(_stripCFWS(cr("\t \r\n\r \n")).empty);
10451         assert(_stripCFWS(cr("(hello world) (can't find waldo) (he's lost)")).empty);
10452         assert(_stripCFWS(cr("(hello\\) world) (can't \\(find waldo) (he's \\(\\)lost)")).empty);
10453         assert(_stripCFWS(cr("(((((")).empty);
10454         assert(_stripCFWS(cr("(((()))")).empty);
10455         assert(_stripCFWS(cr("(((())))")).empty);
10456         assert(equal(_stripCFWS(cr("(((()))))")), cr(")")));
10457         assert(equal(_stripCFWS(cr(")))))")), cr(")))))")));
10458         assert(equal(_stripCFWS(cr("()))))")), cr("))))")));
10459         assert(equal(_stripCFWS(cr(" hello hello ")), cr("hello hello ")));
10460         assert(equal(_stripCFWS(cr("\thello (world)")), cr("hello (world)")));
10461         assert(equal(_stripCFWS(cr(" \r\n \\((\\))  foo")), cr("\\((\\))  foo")));
10462         assert(equal(_stripCFWS(cr(" \r\n (\\((\\)))  foo")), cr("foo")));
10463         assert(equal(_stripCFWS(cr(" \r\n (\\(()))  foo")), cr(")  foo")));
10464         assert(_stripCFWS(cr(" \r\n (((\\)))  foo")).empty);
10465 
10466         assert(_stripCFWS(cr("(hello)(hello)")).empty);
10467         assert(_stripCFWS(cr(" \r\n (hello)\r\n (hello)")).empty);
10468         assert(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n ")).empty);
10469         assert(_stripCFWS(cr("\t\t\t\t(hello)\t\t\t\t(hello)\t\t\t\t")).empty);
10470         assert(equal(_stripCFWS(cr(" \r\n (hello)\r\n (hello) \r\n hello")), cr("hello")));
10471         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n hello")), cr("hello")));
10472         assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\r\n\t(hello)\t\r\n hello")), cr("hello")));
10473         assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\t\r\n\t(hello)\t\r\n hello")), cr("hello")));
10474         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n \r\n (hello) \r\n hello")), cr("hello")));
10475         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n \r\n hello")), cr("hello")));
10476         assert(equal(_stripCFWS(cr(" \r\n \r\n (hello)\t\r\n (hello) \r\n hello")), cr("hello")));
10477         assert(equal(_stripCFWS(cr(" \r\n\t\r\n\t(hello)\t\r\n (hello) \r\n hello")), cr("hello")));
10478 
10479         assert(equal(_stripCFWS(cr(" (\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
10480         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) foo")), cr("foo")));
10481         assert(equal(_stripCFWS(cr(" (\t\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
10482         assert(equal(_stripCFWS(cr(" (\r\n\t( \r\n ) \r\n ) foo")), cr("foo")));
10483         assert(equal(_stripCFWS(cr(" ( \r\n (\t\r\n ) \r\n ) foo")), cr("foo")));
10484         assert(equal(_stripCFWS(cr(" ( \r\n (\r\n ) \r\n ) foo")), cr("foo")));
10485         assert(equal(_stripCFWS(cr(" ( \r\n (\r\n\t) \r\n ) foo")), cr("foo")));
10486         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n) \r\n ) foo")), cr("foo")));
10487         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\t\r\n ) foo")), cr("foo")));
10488         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\r\n ) foo")), cr("foo")));
10489         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n) foo")), cr("foo")));
10490         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n\t) foo")), cr("foo")));
10491         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) \r\n foo")), cr("foo")));
10492         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\t\r\n foo")), cr("foo")));
10493         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\r\n foo")), cr("foo")));
10494 
10495         assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
10496         assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
10497         assert(equal(_stripCFWS(cr(" (\t\r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
10498         assert(equal(_stripCFWS(cr(" (\r\n \r\n\t( \r\n \r\n ) \r\n ) foo")), cr("foo")));
10499         assert(equal(_stripCFWS(cr(" (\r\n \r\n( \r\n \r\n ) \r\n ) foo")), cr("foo")));
10500         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n\t) \r\n ) foo")), cr("foo")));
10501         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\t\r\n ) foo")), cr("foo")));
10502         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\r\n ) foo")), cr("foo")));
10503 
10504         assert(equal(_stripCFWS(cr(" ( \r\n bar \r\n ( \r\n bar \r\n ) \r\n ) foo")), cr("foo")));
10505         assert(equal(_stripCFWS(cr(" ( \r\n () \r\n ( \r\n () \r\n ) \r\n ) foo")), cr("foo")));
10506         assert(equal(_stripCFWS(cr(" ( \r\n \\\\ \r\n ( \r\n \\\\ \r\n ) \r\n ) foo")), cr("foo")));
10507 
10508         assert(_stripCFWS(cr("(hello)(hello)")).empty);
10509         assert(_stripCFWS(cr(" \n (hello)\n (hello) \n ")).empty);
10510         assert(_stripCFWS(cr(" \n (hello) \n (hello) \n ")).empty);
10511         assert(equal(_stripCFWS(cr(" \n (hello)\n (hello) \n hello")), cr("hello")));
10512         assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n hello")), cr("hello")));
10513         assert(equal(_stripCFWS(cr("\t\n\t(hello)\n\t(hello)\t\n hello")), cr("hello")));
10514         assert(equal(_stripCFWS(cr("\t\n\t(hello)\t\n\t(hello)\t\n hello")), cr("hello")));
10515         assert(equal(_stripCFWS(cr(" \n (hello) \n \n (hello) \n hello")), cr("hello")));
10516         assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n \n hello")), cr("hello")));
10517         assert(equal(_stripCFWS(cr(" \n \n (hello)\t\n (hello) \n hello")), cr("hello")));
10518         assert(equal(_stripCFWS(cr(" \n\t\n\t(hello)\t\n (hello) \n hello")), cr("hello")));
10519     }();
10520 }
10521 
10522 // This is so that we don't have to worry about std.conv.to throwing. It also
10523 // doesn't have to worry about quite as many cases as std.conv.to, since it
10524 // doesn't have to worry about a sign on the value or about whether it fits.
10525 T _convDigits(T, R)(R str)
10526 if (isIntegral!T && isSigned!T) // The constraints on R were already covered by parseRFC822DateTime.
10527 {
10528     import std.ascii : isDigit;
10529 
10530     assert(!str.empty);
10531     T num = 0;
10532     foreach (i; 0 .. str.length)
10533     {
10534         if (i != 0)
10535             num *= 10;
10536         if (!isDigit(str[i]))
10537             return -1;
10538         num += str[i] - '0';
10539     }
10540     return num;
10541 }
10542 
10543 @safe unittest
10544 {
10545     import std.conv : to;
10546     import std.range : chain, iota;
10547     import std.stdio : writeln;
10548     foreach (i; chain(iota(0, 101), [250, 999, 1000, 1001, 2345, 9999]))
10549     {
10550         scope(failure) writeln(i);
10551         assert(_convDigits!int(to!string(i)) == i);
10552     }
foreach(str;["-42","+42","1a","1 "," "," 42 "])10553     foreach (str; ["-42", "+42", "1a", "1 ", " ", " 42 "])
10554     {
10555         scope(failure) writeln(str);
10556         assert(_convDigits!int(str) == -1);
10557     }
10558 }
10559 
10560 
version(unittest)10561 version (unittest)
10562 {
10563     // Variables to help in testing.
10564     Duration currLocalDiffFromUTC;
10565     immutable (TimeZone)[] testTZs;
10566 
10567     // All of these helper arrays are sorted in ascending order.
10568     auto testYearsBC = [-1999, -1200, -600, -4, -1, 0];
10569     auto testYearsAD = [1, 4, 1000, 1999, 2000, 2012];
10570 
10571     // I'd use a Tuple, but I get forward reference errors if I try.
10572     struct MonthDay
10573     {
10574         Month month;
10575         short day;
10576 
10577         this(int m, short d)
10578         {
10579             month = cast(Month) m;
10580             day = d;
10581         }
10582     }
10583 
10584     MonthDay[] testMonthDays = [MonthDay(1, 1),
10585                                 MonthDay(1, 2),
10586                                 MonthDay(3, 17),
10587                                 MonthDay(7, 4),
10588                                 MonthDay(10, 27),
10589                                 MonthDay(12, 30),
10590                                 MonthDay(12, 31)];
10591 
10592     auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31];
10593 
10594     auto testTODs = [TimeOfDay(0, 0, 0),
10595                      TimeOfDay(0, 0, 1),
10596                      TimeOfDay(0, 1, 0),
10597                      TimeOfDay(1, 0, 0),
10598                      TimeOfDay(13, 13, 13),
10599                      TimeOfDay(23, 59, 59)];
10600 
10601     auto testHours = [0, 1, 12, 22, 23];
10602     auto testMinSecs = [0, 1, 30, 58, 59];
10603 
10604     // Throwing exceptions is incredibly expensive, so we want to use a smaller
10605     // set of values for tests using assertThrown.
10606     auto testTODsThrown = [TimeOfDay(0, 0, 0),
10607                            TimeOfDay(13, 13, 13),
10608                            TimeOfDay(23, 59, 59)];
10609 
10610     Date[] testDatesBC;
10611     Date[] testDatesAD;
10612 
10613     DateTime[] testDateTimesBC;
10614     DateTime[] testDateTimesAD;
10615 
10616     Duration[] testFracSecs;
10617 
10618     SysTime[] testSysTimesBC;
10619     SysTime[] testSysTimesAD;
10620 
10621     // I'd use a Tuple, but I get forward reference errors if I try.
10622     struct GregDay { int day; Date date; }
10623     auto testGregDaysBC = [GregDay(-1_373_427, Date(-3760, 9, 7)), // Start of the Hebrew Calendar
10624                            GregDay(-735_233, Date(-2012, 1, 1)),
10625                            GregDay(-735_202, Date(-2012, 2, 1)),
10626                            GregDay(-735_175, Date(-2012, 2, 28)),
10627                            GregDay(-735_174, Date(-2012, 2, 29)),
10628                            GregDay(-735_173, Date(-2012, 3, 1)),
10629                            GregDay(-734_502, Date(-2010, 1, 1)),
10630                            GregDay(-734_472, Date(-2010, 1, 31)),
10631                            GregDay(-734_471, Date(-2010, 2, 1)),
10632                            GregDay(-734_444, Date(-2010, 2, 28)),
10633                            GregDay(-734_443, Date(-2010, 3, 1)),
10634                            GregDay(-734_413, Date(-2010, 3, 31)),
10635                            GregDay(-734_412, Date(-2010, 4, 1)),
10636                            GregDay(-734_383, Date(-2010, 4, 30)),
10637                            GregDay(-734_382, Date(-2010, 5, 1)),
10638                            GregDay(-734_352, Date(-2010, 5, 31)),
10639                            GregDay(-734_351, Date(-2010, 6, 1)),
10640                            GregDay(-734_322, Date(-2010, 6, 30)),
10641                            GregDay(-734_321, Date(-2010, 7, 1)),
10642                            GregDay(-734_291, Date(-2010, 7, 31)),
10643                            GregDay(-734_290, Date(-2010, 8, 1)),
10644                            GregDay(-734_260, Date(-2010, 8, 31)),
10645                            GregDay(-734_259, Date(-2010, 9, 1)),
10646                            GregDay(-734_230, Date(-2010, 9, 30)),
10647                            GregDay(-734_229, Date(-2010, 10, 1)),
10648                            GregDay(-734_199, Date(-2010, 10, 31)),
10649                            GregDay(-734_198, Date(-2010, 11, 1)),
10650                            GregDay(-734_169, Date(-2010, 11, 30)),
10651                            GregDay(-734_168, Date(-2010, 12, 1)),
10652                            GregDay(-734_139, Date(-2010, 12, 30)),
10653                            GregDay(-734_138, Date(-2010, 12, 31)),
10654                            GregDay(-731_215, Date(-2001, 1, 1)),
10655                            GregDay(-730_850, Date(-2000, 1, 1)),
10656                            GregDay(-730_849, Date(-2000, 1, 2)),
10657                            GregDay(-730_486, Date(-2000, 12, 30)),
10658                            GregDay(-730_485, Date(-2000, 12, 31)),
10659                            GregDay(-730_484, Date(-1999, 1, 1)),
10660                            GregDay(-694_690, Date(-1901, 1, 1)),
10661                            GregDay(-694_325, Date(-1900, 1, 1)),
10662                            GregDay(-585_118, Date(-1601, 1, 1)),
10663                            GregDay(-584_753, Date(-1600, 1, 1)),
10664                            GregDay(-584_388, Date(-1600, 12, 31)),
10665                            GregDay(-584_387, Date(-1599, 1, 1)),
10666                            GregDay(-365_972, Date(-1001, 1, 1)),
10667                            GregDay(-365_607, Date(-1000, 1, 1)),
10668                            GregDay(-183_351, Date(-501, 1, 1)),
10669                            GregDay(-182_986, Date(-500, 1, 1)),
10670                            GregDay(-182_621, Date(-499, 1, 1)),
10671                            GregDay(-146_827, Date(-401, 1, 1)),
10672                            GregDay(-146_462, Date(-400, 1, 1)),
10673                            GregDay(-146_097, Date(-400, 12, 31)),
10674                            GregDay(-110_302, Date(-301, 1, 1)),
10675                            GregDay(-109_937, Date(-300, 1, 1)),
10676                            GregDay(-73_778, Date(-201, 1, 1)),
10677                            GregDay(-73_413, Date(-200, 1, 1)),
10678                            GregDay(-38_715, Date(-105, 1, 1)),
10679                            GregDay(-37_254, Date(-101, 1, 1)),
10680                            GregDay(-36_889, Date(-100, 1, 1)),
10681                            GregDay(-36_524, Date(-99, 1, 1)),
10682                            GregDay(-36_160, Date(-99, 12, 31)),
10683                            GregDay(-35_794, Date(-97, 1, 1)),
10684                            GregDay(-18_627, Date(-50, 1, 1)),
10685                            GregDay(-18_262, Date(-49, 1, 1)),
10686                            GregDay(-3652, Date(-9, 1, 1)),
10687                            GregDay(-2191, Date(-5, 1, 1)),
10688                            GregDay(-1827, Date(-5, 12, 31)),
10689                            GregDay(-1826, Date(-4, 1, 1)),
10690                            GregDay(-1825, Date(-4, 1, 2)),
10691                            GregDay(-1462, Date(-4, 12, 30)),
10692                            GregDay(-1461, Date(-4, 12, 31)),
10693                            GregDay(-1460, Date(-3, 1, 1)),
10694                            GregDay(-1096, Date(-3, 12, 31)),
10695                            GregDay(-1095, Date(-2, 1, 1)),
10696                            GregDay(-731, Date(-2, 12, 31)),
10697                            GregDay(-730, Date(-1, 1, 1)),
10698                            GregDay(-367, Date(-1, 12, 30)),
10699                            GregDay(-366, Date(-1, 12, 31)),
10700                            GregDay(-365, Date(0, 1, 1)),
10701                            GregDay(-31, Date(0, 11, 30)),
10702                            GregDay(-30, Date(0, 12, 1)),
10703                            GregDay(-1, Date(0, 12, 30)),
10704                            GregDay(0, Date(0, 12, 31))];
10705 
10706     auto testGregDaysAD = [GregDay(1, Date(1, 1, 1)),
10707                            GregDay(2, Date(1, 1, 2)),
10708                            GregDay(32, Date(1, 2, 1)),
10709                            GregDay(365, Date(1, 12, 31)),
10710                            GregDay(366, Date(2, 1, 1)),
10711                            GregDay(731, Date(3, 1, 1)),
10712                            GregDay(1096, Date(4, 1, 1)),
10713                            GregDay(1097, Date(4, 1, 2)),
10714                            GregDay(1460, Date(4, 12, 30)),
10715                            GregDay(1461, Date(4, 12, 31)),
10716                            GregDay(1462, Date(5, 1, 1)),
10717                            GregDay(17_898, Date(50, 1, 1)),
10718                            GregDay(35_065, Date(97, 1, 1)),
10719                            GregDay(36_160, Date(100, 1, 1)),
10720                            GregDay(36_525, Date(101, 1, 1)),
10721                            GregDay(37_986, Date(105, 1, 1)),
10722                            GregDay(72_684, Date(200, 1, 1)),
10723                            GregDay(73_049, Date(201, 1, 1)),
10724                            GregDay(109_208, Date(300, 1, 1)),
10725                            GregDay(109_573, Date(301, 1, 1)),
10726                            GregDay(145_732, Date(400, 1, 1)),
10727                            GregDay(146_098, Date(401, 1, 1)),
10728                            GregDay(182_257, Date(500, 1, 1)),
10729                            GregDay(182_622, Date(501, 1, 1)),
10730                            GregDay(364_878, Date(1000, 1, 1)),
10731                            GregDay(365_243, Date(1001, 1, 1)),
10732                            GregDay(584_023, Date(1600, 1, 1)),
10733                            GregDay(584_389, Date(1601, 1, 1)),
10734                            GregDay(693_596, Date(1900, 1, 1)),
10735                            GregDay(693_961, Date(1901, 1, 1)),
10736                            GregDay(729_755, Date(1999, 1, 1)),
10737                            GregDay(730_120, Date(2000, 1, 1)),
10738                            GregDay(730_121, Date(2000, 1, 2)),
10739                            GregDay(730_484, Date(2000, 12, 30)),
10740                            GregDay(730_485, Date(2000, 12, 31)),
10741                            GregDay(730_486, Date(2001, 1, 1)),
10742                            GregDay(733_773, Date(2010, 1, 1)),
10743                            GregDay(733_774, Date(2010, 1, 2)),
10744                            GregDay(733_803, Date(2010, 1, 31)),
10745                            GregDay(733_804, Date(2010, 2, 1)),
10746                            GregDay(733_831, Date(2010, 2, 28)),
10747                            GregDay(733_832, Date(2010, 3, 1)),
10748                            GregDay(733_862, Date(2010, 3, 31)),
10749                            GregDay(733_863, Date(2010, 4, 1)),
10750                            GregDay(733_892, Date(2010, 4, 30)),
10751                            GregDay(733_893, Date(2010, 5, 1)),
10752                            GregDay(733_923, Date(2010, 5, 31)),
10753                            GregDay(733_924, Date(2010, 6, 1)),
10754                            GregDay(733_953, Date(2010, 6, 30)),
10755                            GregDay(733_954, Date(2010, 7, 1)),
10756                            GregDay(733_984, Date(2010, 7, 31)),
10757                            GregDay(733_985, Date(2010, 8, 1)),
10758                            GregDay(734_015, Date(2010, 8, 31)),
10759                            GregDay(734_016, Date(2010, 9, 1)),
10760                            GregDay(734_045, Date(2010, 9, 30)),
10761                            GregDay(734_046, Date(2010, 10, 1)),
10762                            GregDay(734_076, Date(2010, 10, 31)),
10763                            GregDay(734_077, Date(2010, 11, 1)),
10764                            GregDay(734_106, Date(2010, 11, 30)),
10765                            GregDay(734_107, Date(2010, 12, 1)),
10766                            GregDay(734_136, Date(2010, 12, 30)),
10767                            GregDay(734_137, Date(2010, 12, 31)),
10768                            GregDay(734_503, Date(2012, 1, 1)),
10769                            GregDay(734_534, Date(2012, 2, 1)),
10770                            GregDay(734_561, Date(2012, 2, 28)),
10771                            GregDay(734_562, Date(2012, 2, 29)),
10772                            GregDay(734_563, Date(2012, 3, 1)),
10773                            GregDay(734_858, Date(2012, 12, 21))];
10774 
10775     // I'd use a Tuple, but I get forward reference errors if I try.
10776     struct DayOfYear { int day; MonthDay md; }
10777     auto testDaysOfYear = [DayOfYear(1, MonthDay(1, 1)),
10778                            DayOfYear(2, MonthDay(1, 2)),
10779                            DayOfYear(3, MonthDay(1, 3)),
10780                            DayOfYear(31, MonthDay(1, 31)),
10781                            DayOfYear(32, MonthDay(2, 1)),
10782                            DayOfYear(59, MonthDay(2, 28)),
10783                            DayOfYear(60, MonthDay(3, 1)),
10784                            DayOfYear(90, MonthDay(3, 31)),
10785                            DayOfYear(91, MonthDay(4, 1)),
10786                            DayOfYear(120, MonthDay(4, 30)),
10787                            DayOfYear(121, MonthDay(5, 1)),
10788                            DayOfYear(151, MonthDay(5, 31)),
10789                            DayOfYear(152, MonthDay(6, 1)),
10790                            DayOfYear(181, MonthDay(6, 30)),
10791                            DayOfYear(182, MonthDay(7, 1)),
10792                            DayOfYear(212, MonthDay(7, 31)),
10793                            DayOfYear(213, MonthDay(8, 1)),
10794                            DayOfYear(243, MonthDay(8, 31)),
10795                            DayOfYear(244, MonthDay(9, 1)),
10796                            DayOfYear(273, MonthDay(9, 30)),
10797                            DayOfYear(274, MonthDay(10, 1)),
10798                            DayOfYear(304, MonthDay(10, 31)),
10799                            DayOfYear(305, MonthDay(11, 1)),
10800                            DayOfYear(334, MonthDay(11, 30)),
10801                            DayOfYear(335, MonthDay(12, 1)),
10802                            DayOfYear(363, MonthDay(12, 29)),
10803                            DayOfYear(364, MonthDay(12, 30)),
10804                            DayOfYear(365, MonthDay(12, 31))];
10805 
10806     auto testDaysOfLeapYear = [DayOfYear(1, MonthDay(1, 1)),
10807                                DayOfYear(2, MonthDay(1, 2)),
10808                                DayOfYear(3, MonthDay(1, 3)),
10809                                DayOfYear(31, MonthDay(1, 31)),
10810                                DayOfYear(32, MonthDay(2, 1)),
10811                                DayOfYear(59, MonthDay(2, 28)),
10812                                DayOfYear(60, MonthDay(2, 29)),
10813                                DayOfYear(61, MonthDay(3, 1)),
10814                                DayOfYear(91, MonthDay(3, 31)),
10815                                DayOfYear(92, MonthDay(4, 1)),
10816                                DayOfYear(121, MonthDay(4, 30)),
10817                                DayOfYear(122, MonthDay(5, 1)),
10818                                DayOfYear(152, MonthDay(5, 31)),
10819                                DayOfYear(153, MonthDay(6, 1)),
10820                                DayOfYear(182, MonthDay(6, 30)),
10821                                DayOfYear(183, MonthDay(7, 1)),
10822                                DayOfYear(213, MonthDay(7, 31)),
10823                                DayOfYear(214, MonthDay(8, 1)),
10824                                DayOfYear(244, MonthDay(8, 31)),
10825                                DayOfYear(245, MonthDay(9, 1)),
10826                                DayOfYear(274, MonthDay(9, 30)),
10827                                DayOfYear(275, MonthDay(10, 1)),
10828                                DayOfYear(305, MonthDay(10, 31)),
10829                                DayOfYear(306, MonthDay(11, 1)),
10830                                DayOfYear(335, MonthDay(11, 30)),
10831                                DayOfYear(336, MonthDay(12, 1)),
10832                                DayOfYear(364, MonthDay(12, 29)),
10833                                DayOfYear(365, MonthDay(12, 30)),
10834                                DayOfYear(366, MonthDay(12, 31))];
10835 
10836     void initializeTests() @safe
10837     {
10838         import std.algorithm.sorting : sort;
10839         import std.typecons : Rebindable;
10840         immutable lt = LocalTime().utcToTZ(0);
10841         currLocalDiffFromUTC = dur!"hnsecs"(lt);
10842 
10843         version (Posix)
10844         {
10845             immutable otherTZ = lt < 0 ? PosixTimeZone.getTimeZone("Australia/Sydney")
10846                                        : PosixTimeZone.getTimeZone("America/Denver");
10847         }
10848         else version (Windows)
10849         {
10850             immutable otherTZ = lt < 0 ? WindowsTimeZone.getTimeZone("AUS Eastern Standard Time")
10851                                        : WindowsTimeZone.getTimeZone("Mountain Standard Time");
10852         }
10853 
10854         immutable ot = otherTZ.utcToTZ(0);
10855 
10856         auto diffs = [0L, lt, ot];
10857         auto diffAA = [0L : Rebindable!(immutable TimeZone)(UTC())];
10858         diffAA[lt] = Rebindable!(immutable TimeZone)(LocalTime());
10859         diffAA[ot] = Rebindable!(immutable TimeZone)(otherTZ);
10860 
10861         sort(diffs);
10862         testTZs = [diffAA[diffs[0]], diffAA[diffs[1]], diffAA[diffs[2]]];
10863 
10864         testFracSecs = [Duration.zero, hnsecs(1), hnsecs(5007), hnsecs(9_999_999)];
10865 
10866         foreach (year; testYearsBC)
10867         {
10868             foreach (md; testMonthDays)
10869                 testDatesBC ~= Date(year, md.month, md.day);
10870         }
10871 
10872         foreach (year; testYearsAD)
10873         {
10874             foreach (md; testMonthDays)
10875                 testDatesAD ~= Date(year, md.month, md.day);
10876         }
10877 
10878         foreach (dt; testDatesBC)
10879         {
10880             foreach (tod; testTODs)
10881                 testDateTimesBC ~= DateTime(dt, tod);
10882         }
10883 
10884         foreach (dt; testDatesAD)
10885         {
10886             foreach (tod; testTODs)
10887                 testDateTimesAD ~= DateTime(dt, tod);
10888         }
10889 
10890         foreach (dt; testDateTimesBC)
10891         {
10892             foreach (tz; testTZs)
10893             {
10894                 foreach (fs; testFracSecs)
10895                     testSysTimesBC ~= SysTime(dt, fs, tz);
10896             }
10897         }
10898 
10899         foreach (dt; testDateTimesAD)
10900         {
10901             foreach (tz; testTZs)
10902             {
10903                 foreach (fs; testFracSecs)
10904                     testSysTimesAD ~= SysTime(dt, fs, tz);
10905             }
10906         }
10907     }
10908 }
10909