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 version (OSX)
11     version = Darwin;
12 else version (iOS)
13     version = Darwin;
14 else version (TVOS)
15     version = Darwin;
16 else version (WatchOS)
17     version = Darwin;
18 
19 import core.time;
20 import std.datetime.date;
21 import std.datetime.timezone;
22 import std.exception : enforce;
23 import std.format : format;
24 import std.range.primitives;
25 import std.traits : isIntegral, isSigned, isSomeString, Unqual;
26 
version(Windows)27 version (Windows)
28 {
29     import core.stdc.time : time_t;
30     import core.sys.windows.windows;
31     import core.sys.windows.winsock2;
32 }
version(Posix)33 else version (Posix)
34 {
35     import core.sys.posix.signal : timespec;
36     import core.sys.posix.sys.types : time_t;
37 }
38 
version(unittest)39 version (unittest)
40 {
41     import core.exception : AssertError;
42     import std.exception : assertThrown;
43 }
44 
45 
46 @safe unittest
47 {
48     initializeTests();
49 }
50 
version(unittest)51 version (unittest) private bool clockSupported(ClockType c)
52 {
53     // Skip unsupported clocks on older linux kernels, assume that only
54     // CLOCK_MONOTONIC and CLOCK_REALTIME exist, as that is the lowest
55     // common denominator supported by all versions of Linux pre-2.6.12.
56     version (Linux_Pre_2639)
57         return c == ClockType.normal || c == ClockType.precise;
58     else
59         return true;
60 }
61 
62 /++
63     Effectively a namespace to make it clear that the methods it contains are
64     getting the time from the system clock. It cannot be instantiated.
65  +/
66 final class Clock
67 {
68 public:
69 
70     /++
71         Returns the current time in the given time zone.
72 
73         Params:
74             clockType = The $(REF ClockType, core,time) indicates which system
75                         clock to use to get the current time. Very few programs
76                         need to use anything other than the default.
77             tz = The time zone for the SysTime that's returned.
78 
79         Throws:
80             $(REF DateTimeException,std,datetime,date) if it fails to get the
81             time.
82       +/
83     static SysTime currTime(ClockType clockType = ClockType.normal)(immutable TimeZone tz = LocalTime()) @safe
84     {
85         return SysTime(currStdTime!clockType, tz);
86     }
87 
88     @safe unittest
89     {
90         import std.format : format;
91         import std.stdio : writefln;
92         assert(currTime().timezone is LocalTime());
93         assert(currTime(UTC()).timezone is UTC());
94 
95         // core.stdc.time.time does not always use unix time on Windows systems.
96         // In particular, dmc does not use unix time. If we can guarantee that
97         // the MS runtime uses unix time, then we may be able run this test
98         // then, but for now, we're just not going to run this test on Windows.
version(Posix)99         version (Posix)
100         {
101             static import core.stdc.time;
102             static import std.math;
103             immutable unixTimeD = currTime().toUnixTime();
104             immutable unixTimeC = core.stdc.time.time(null);
105             assert(std.math.abs(unixTimeC - unixTimeD) <= 2);
106         }
107 
108         auto norm1 = Clock.currTime;
109         auto norm2 = Clock.currTime(UTC());
110         assert(norm1 <= norm2, format("%s %s", norm1, norm2));
111         assert(abs(norm1 - norm2) <= seconds(2));
112 
113         import std.meta : AliasSeq;
114         foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
115         {
116             scope(failure) writefln("ClockType.%s", ct);
117             static if (clockSupported(ct))
118             {
119                 auto value1 = Clock.currTime!ct;
120                 auto value2 = Clock.currTime!ct(UTC());
121                 assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
122                 assert(abs(value1 - value2) <= seconds(2), format("ClockType.%s", ct));
123             }
124         }
125     }
126 
127 
128     /++
129         Returns the number of hnsecs since midnight, January 1st, 1 A.D. for the
130         current time.
131 
132         Params:
133             clockType = The $(REF ClockType, core,time) indicates which system
134                         clock to use to get the current time. Very few programs
135                         need to use anything other than the default.
136 
137         Throws:
138             $(REF DateTimeException,std,datetime,date) if it fails to get the
139             time.
140       +/
141     static @property long currStdTime(ClockType clockType = ClockType.normal)() @trusted
142     {
143         static if (clockType != ClockType.coarse &&
144                    clockType != ClockType.normal &&
145                    clockType != ClockType.precise &&
146                    clockType != ClockType.second)
147         {
148             static assert(0, format("ClockType.%s is not supported by Clock.currTime or Clock.currStdTime", clockType));
149         }
150 
version(Windows)151         version (Windows)
152         {
153             FILETIME fileTime;
154             GetSystemTimeAsFileTime(&fileTime);
155             immutable result = FILETIMEToStdTime(&fileTime);
156             static if (clockType == ClockType.second)
157             {
158                 // Ideally, this would use core.std.time.time, but the C runtime
159                 // has to be using unix time for that to work, and that's not
160                 // guaranteed on Windows. Digital Mars does not use unix time.
161                 // MS may or may not. If it does, then this can be made to use
162                 // core.stdc.time for MS, but for now, we'll leave it like this.
163                 return convert!("seconds", "hnsecs")(convert!("hnsecs", "seconds")(result));
164             }
165             else
166                 return result;
167         }
version(Posix)168         else version (Posix)
169         {
170             static import core.stdc.time;
171             enum hnsecsToUnixEpoch = unixTimeToStdTime(0);
172 
173             version (Darwin)
174             {
175                 static if (clockType == ClockType.second)
176                     return unixTimeToStdTime(core.stdc.time.time(null));
177                 else
178                 {
179                     import core.sys.posix.sys.time : gettimeofday, timeval;
180                     timeval tv = void;
181                     // Posix gettimeofday called with a valid timeval address
182                     // and a null second parameter doesn't fail.
183                     gettimeofday(&tv, null);
184                     return convert!("seconds", "hnsecs")(tv.tv_sec) +
185                            tv.tv_usec * 10 +
186                            hnsecsToUnixEpoch;
187                 }
188             }
189             else version (linux)
190             {
191                 static if (clockType == ClockType.second)
192                     return unixTimeToStdTime(core.stdc.time.time(null));
193                 else
194                 {
195                     import core.sys.linux.time : CLOCK_REALTIME_COARSE;
196                     import core.sys.posix.time : clock_gettime, CLOCK_REALTIME;
197                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_COARSE;
198                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
199                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
200                     else static assert(0, "Previous static if is wrong.");
201                     timespec ts = void;
202                     immutable error = clock_gettime(clockArg, &ts);
203                     // Posix clock_gettime called with a valid address and valid clock_id is only
204                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
205                     // is long or larger overflow won't happen before 292 billion years A.D.
206                     static if (ts.tv_sec.max < long.max)
207                     {
208                         if (error)
209                             throw new TimeException("Call to clock_gettime() failed");
210                     }
211                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
212                            ts.tv_nsec / 100 +
213                            hnsecsToUnixEpoch;
214                 }
215             }
216             else version (FreeBSD)
217             {
218                 import core.sys.freebsd.time : clock_gettime, CLOCK_REALTIME,
219                     CLOCK_REALTIME_FAST, CLOCK_REALTIME_PRECISE, CLOCK_SECOND;
220                 static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_FAST;
221                 else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
222                 else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE;
223                 else static if (clockType == ClockType.second)  alias clockArg = CLOCK_SECOND;
224                 else static assert(0, "Previous static if is wrong.");
225                 timespec ts = void;
226                 immutable error = clock_gettime(clockArg, &ts);
227                 // Posix clock_gettime called with a valid address and valid clock_id is only
228                 // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
229                 // is long or larger overflow won't happen before 292 billion years A.D.
230                 static if (ts.tv_sec.max < long.max)
231                 {
232                     if (error)
233                         throw new TimeException("Call to clock_gettime() failed");
234                 }
235                 return convert!("seconds", "hnsecs")(ts.tv_sec) +
236                        ts.tv_nsec / 100 +
237                        hnsecsToUnixEpoch;
238             }
239             else version (NetBSD)
240             {
241                 static if (clockType == ClockType.second)
242                     return unixTimeToStdTime(core.stdc.time.time(null));
243                 else
244                 {
245                     import core.sys.netbsd.time : clock_gettime, CLOCK_REALTIME;
246                     timespec ts = void;
247                     immutable error = clock_gettime(CLOCK_REALTIME, &ts);
248                     // Posix clock_gettime called with a valid address and valid clock_id is only
249                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
250                     // is long or larger overflow won't happen before 292 billion years A.D.
251                     static if (ts.tv_sec.max < long.max)
252                     {
253                         if (error)
254                             throw new TimeException("Call to clock_gettime() failed");
255                     }
256                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
257                            ts.tv_nsec / 100 +
258                            hnsecsToUnixEpoch;
259                 }
260             }
261             else version (OpenBSD)
262             {
263                 static if (clockType == ClockType.second)
264                     return unixTimeToStdTime(core.stdc.time.time(null));
265                 else
266                 {
267                     import core.sys.openbsd.time : clock_gettime, CLOCK_REALTIME;
268                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME;
269                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
270                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
271                     else static assert(0, "Previous static if is wrong.");
272                     timespec ts;
273                     if (clock_gettime(clockArg, &ts) != 0)
274                         throw new TimeException("Call to clock_gettime() failed");
275                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
276                            ts.tv_nsec / 100 +
277                            hnsecsToUnixEpoch;
278                 }
279             }
280             else version (DragonFlyBSD)
281             {
282                 import core.sys.dragonflybsd.time : clock_gettime, CLOCK_REALTIME,
283                     CLOCK_REALTIME_FAST, CLOCK_REALTIME_PRECISE, CLOCK_SECOND;
284                 static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_FAST;
285                 else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
286                 else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE;
287                 else static if (clockType == ClockType.second)  alias clockArg = CLOCK_SECOND;
288                 else static assert(0, "Previous static if is wrong.");
289                 timespec ts = void;
290                 immutable error = clock_gettime(clockArg, &ts);
291                 // Posix clock_gettime called with a valid address and valid clock_id is only
292                 // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
293                 // is long or larger overflow won't happen before 292 billion years A.D.
294                 static if (ts.tv_sec.max < long.max)
295                 {
296                     if (error)
297                         throw new TimeException("Call to clock_gettime() failed");
298                 }
299                 return convert!("seconds", "hnsecs")(ts.tv_sec) +
300                        ts.tv_nsec / 100 +
301                        hnsecsToUnixEpoch;
302             }
303             else version (Solaris)
304             {
305                 static if (clockType == ClockType.second)
306                     return unixTimeToStdTime(core.stdc.time.time(null));
307                 else
308                 {
309                     import core.sys.solaris.time : clock_gettime, CLOCK_REALTIME;
310                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME;
311                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
312                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
313                     else static assert(0, "Previous static if is wrong.");
314                     timespec ts = void;
315                     immutable error = clock_gettime(clockArg, &ts);
316                     // Posix clock_gettime called with a valid address and valid clock_id is only
317                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
318                     // is long or larger overflow won't happen before 292 billion years A.D.
319                     static if (ts.tv_sec.max < long.max)
320                     {
321                         if (error)
322                             throw new TimeException("Call to clock_gettime() failed");
323                     }
324                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
325                            ts.tv_nsec / 100 +
326                            hnsecsToUnixEpoch;
327                 }
328             }
329             else static assert(0, "Unsupported OS");
330         }
331         else static assert(0, "Unsupported OS");
332     }
333 
334     @safe unittest
335     {
336         import std.format : format;
337         import std.math : abs;
338         import std.meta : AliasSeq;
339         import std.stdio : writefln;
340         enum limit = convert!("seconds", "hnsecs")(2);
341 
342         auto norm1 = Clock.currStdTime;
343         auto norm2 = Clock.currStdTime;
344         assert(norm1 <= norm2, format("%s %s", norm1, norm2));
345         assert(abs(norm1 - norm2) <= limit);
346 
347         foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
348         {
349             scope(failure) writefln("ClockType.%s", ct);
350             static if (clockSupported(ct))
351             {
352                 auto value1 = Clock.currStdTime!ct;
353                 auto value2 = Clock.currStdTime!ct;
354                 assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
355                 assert(abs(value1 - value2) <= limit);
356             }
357         }
358     }
359 
360 
361 private:
362 
this()363     @disable this() {}
364 }
365 
366 
367 /++
368     $(D SysTime) is the type used to get the current time from the
369     system or doing anything that involves time zones. Unlike
370     $(REF DateTime,std,datetime,date), the time zone is an integral part of
371     $(D SysTime) (though for local time applications, time zones can be ignored
372     and it will work, since it defaults to using the local time zone). It holds
373     its internal time in std time (hnsecs since midnight, January 1st, 1 A.D.
374     UTC), so it interfaces well with the system time. However, that means that,
375     unlike $(REF DateTime,std,datetime,date), it is not optimized for
376     calendar-based operations, and getting individual units from it such as
377     years or days is going to involve conversions and be less efficient.
378 
379     For calendar-based operations that don't
380     care about time zones, then $(REF DateTime,std,datetime,date) would be
381     the type to use. For system time, use $(D SysTime).
382 
383     $(LREF Clock.currTime) will return the current time as a $(D SysTime).
384     To convert a $(D SysTime) to a $(REF Date,std,datetime,date) or
385     $(REF DateTime,std,datetime,date), simply cast it. To convert a
386     $(REF Date,std,datetime,date) or $(REF DateTime,std,datetime,date) to a
387     $(D SysTime), use $(D SysTime)'s constructor, and pass in the ntended time
388     zone with it (or don't pass in a $(REF TimeZone,std,datetime,timezone), and
389     the local time zone will be used). Be aware, however, that converting from a
390     $(REF DateTime,std,datetime,date) to a $(D SysTime) will not necessarily
391     be 100% accurate due to DST (one hour of the year doesn't exist and another
392     occurs twice). To not risk any conversion errors, keep times as
393     $(D SysTime)s. Aside from DST though, there shouldn't be any conversion
394     problems.
395 
396     For using time zones other than local time or UTC, use
397     $(REF PosixTimeZone,std,datetime,timezone) on Posix systems (or on Windows,
398     if providing the TZ Database files), and use
399     $(REF WindowsTimeZone,std,datetime,timezone) on Windows systems. The time in
400     $(D SysTime) is kept internally in hnsecs from midnight, January 1st, 1 A.D.
401     UTC. Conversion error cannot happen when changing the time zone of a
402     $(D SysTime). $(REF LocalTime,std,datetime,timezone) is the
403     $(REF TimeZone,std,datetime,timezone) class which represents the local time,
404     and $(D UTC) is the $(REF TimeZone,std,datetime,timezone) class which
405     represents UTC. $(D SysTime) uses $(REF LocalTime,std,datetime,timezone) if
406     no $(REF TimeZone,std,datetime,timezone) is provided. For more details on
407     time zones, see the documentation for $(REF TimeZone,std,datetime,timezone),
408     $(REF PosixTimeZone,std,datetime,timezone), and
409     $(REF WindowsTimeZone,std,datetime,timezone).
410 
411     $(D SysTime)'s range is from approximately 29,000 B.C. to approximately
412     29,000 A.D.
413   +/
414 struct SysTime
415 {
416     import core.stdc.time : tm;
417     version (Posix) import core.sys.posix.sys.time : timeval;
418     import std.typecons : Rebindable;
419 
420 public:
421 
422     /++
423         Params:
424             dateTime = The $(REF DateTime,std,datetime,date) to use to set
425                        this $(LREF SysTime)'s internal std time. As
426                        $(REF DateTime,std,datetime,date) has no concept of
427                        time zone, tz is used as its time zone.
428             tz       = The $(REF TimeZone,std,datetime,timezone) to use for this
429                        $(LREF SysTime). If null,
430                        $(REF LocalTime,std,datetime,timezone) will be used. The
431                        given $(REF DateTime,std,datetime,date) is assumed to
432                        be in the given time zone.
433       +/
434     this(in DateTime dateTime, immutable TimeZone tz = null) @safe nothrow
435     {
436         try
437             this(dateTime, Duration.zero, tz);
438         catch (Exception e)
439             assert(0, "SysTime's constructor threw when it shouldn't have.");
440     }
441 
442     @safe unittest
443     {
testSysTime444         static void test(DateTime dt, immutable TimeZone tz, long expected)
445         {
446             auto sysTime = SysTime(dt, tz);
447             assert(sysTime._stdTime == expected);
448             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given DateTime: %s", dt));
449         }
450 
451         test(DateTime.init, UTC(), 0);
452         test(DateTime(1, 1, 1, 12, 30, 33), UTC(), 450_330_000_000L);
453         test(DateTime(0, 12, 31, 12, 30, 33), UTC(), -413_670_000_000L);
454         test(DateTime(1, 1, 1, 0, 0, 0), UTC(), 0);
455         test(DateTime(1, 1, 1, 0, 0, 1), UTC(), 10_000_000L);
456         test(DateTime(0, 12, 31, 23, 59, 59), UTC(), -10_000_000L);
457 
458         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(-60)), 36_000_000_000L);
459         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(Duration.zero), 0);
460         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(60)), -36_000_000_000L);
461     }
462 
463     /++
464         Params:
465             dateTime = The $(REF DateTime,std,datetime,date) to use to set
466                        this $(LREF SysTime)'s internal std time. As
467                        $(REF DateTime,std,datetime,date) has no concept of
468                        time zone, tz is used as its time zone.
469             fracSecs = The fractional seconds portion of the time.
470             tz       = The $(REF TimeZone,std,datetime,timezone) to use for this
471                        $(LREF SysTime). If null,
472                        $(REF LocalTime,std,datetime,timezone) will be used. The
473                        given $(REF DateTime,std,datetime,date) is assumed to
474                        be in the given time zone.
475 
476         Throws:
477             $(REF DateTimeException,std,datetime,date) if $(D fracSecs) is negative or if it's
478             greater than or equal to one second.
479       +/
480     this(in DateTime dateTime, in Duration fracSecs, immutable TimeZone tz = null) @safe
481     {
482         enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
483         enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
484         auto nonNullTZ = tz is null ? LocalTime() : tz;
485 
486         immutable dateDiff = dateTime.date - Date.init;
487         immutable todDiff = dateTime.timeOfDay - TimeOfDay.init;
488 
489         immutable adjustedTime = dateDiff + todDiff + fracSecs;
490         immutable standardTime = nonNullTZ.tzToUTC(adjustedTime.total!"hnsecs");
491 
492         this(standardTime, nonNullTZ);
493     }
494 
495     @safe unittest
496     {
497         static void test(DateTime dt, Duration fracSecs, immutable TimeZone tz, long expected)
498         {
499             auto sysTime = SysTime(dt, fracSecs, tz);
500             assert(sysTime._stdTime == expected);
501             assert(sysTime._timezone is (tz is null ? LocalTime() : tz),
502                    format("Given DateTime: %s, Given Duration: %s", dt, fracSecs));
503         }
504 
505         test(DateTime.init, Duration.zero, UTC(), 0);
506         test(DateTime(1, 1, 1, 12, 30, 33), Duration.zero, UTC(), 450_330_000_000L);
507         test(DateTime(0, 12, 31, 12, 30, 33), Duration.zero, UTC(), -413_670_000_000L);
508         test(DateTime(1, 1, 1, 0, 0, 0), msecs(1), UTC(), 10_000L);
509         test(DateTime(0, 12, 31, 23, 59, 59), msecs(999), UTC(), -10_000L);
510 
511         test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC(), -1);
512         test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC(), -9_999_999);
513         test(DateTime(0, 12, 31, 23, 59, 59), Duration.zero, UTC(), -10_000_000);
514 
515         assertThrown!DateTimeException(SysTime(DateTime.init, hnsecs(-1), UTC()));
516         assertThrown!DateTimeException(SysTime(DateTime.init, seconds(1), UTC()));
517     }
518 
519     /++
520         Params:
521             date = The $(REF Date,std,datetime,date) to use to set this
522                    $(LREF SysTime)'s internal std time. As
523                    $(REF Date,std,datetime,date) has no concept of time zone, tz
524                    is used as its time zone.
525             tz   = The $(REF TimeZone,std,datetime,timezone) to use for this
526                    $(LREF SysTime). If null,
527                    $(REF LocalTime,std,datetime,timezone) will be used. The
528                    given $(REF Date,std,datetime,date) is assumed to be in the
529                    given time zone.
530       +/
531     this(in Date date, immutable TimeZone tz = null) @safe nothrow
532     {
533         _timezone = tz is null ? LocalTime() : tz;
534 
535         try
536         {
537             immutable adjustedTime = (date - Date(1, 1, 1)).total!"hnsecs";
538             immutable standardTime = _timezone.tzToUTC(adjustedTime);
539 
540             this(standardTime, _timezone);
541         }
542         catch (Exception e)
543             assert(0, "Date's constructor through when it shouldn't have.");
544     }
545 
546     @safe unittest
547     {
testSysTime548         static void test(Date d, immutable TimeZone tz, long expected)
549         {
550             auto sysTime = SysTime(d, tz);
551             assert(sysTime._stdTime == expected);
552             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given Date: %s", d));
553         }
554 
555         test(Date.init, UTC(), 0);
556         test(Date(1, 1, 1), UTC(), 0);
557         test(Date(1, 1, 2), UTC(), 864000000000);
558         test(Date(0, 12, 31), UTC(), -864000000000);
559     }
560 
561     /++
562         Note:
563             Whereas the other constructors take in the given date/time, assume
564             that it's in the given time zone, and convert it to hnsecs in UTC
565             since midnight, January 1st, 1 A.D. UTC - i.e. std time - this
566             constructor takes a std time, which is specifically already in UTC,
567             so no conversion takes place. Of course, the various getter
568             properties and functions will use the given time zone's conversion
569             function to convert the results to that time zone, but no conversion
570             of the arguments to this constructor takes place.
571 
572         Params:
573             stdTime = The number of hnsecs since midnight, January 1st, 1 A.D.
574                       UTC.
575             tz      = The $(REF TimeZone,std,datetime,timezone) to use for this
576                       $(LREF SysTime). If null,
577                       $(REF LocalTime,std,datetime,timezone) will be used.
578       +/
579     this(long stdTime, immutable TimeZone tz = null) @safe pure nothrow
580     {
581         _stdTime = stdTime;
582         _timezone = tz is null ? LocalTime() : tz;
583     }
584 
585     @safe unittest
586     {
testSysTime587         static void test(long stdTime, immutable TimeZone tz)
588         {
589             auto sysTime = SysTime(stdTime, tz);
590             assert(sysTime._stdTime == stdTime);
591             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given stdTime: %s", stdTime));
592         }
593 
foreachSysTime594         foreach (stdTime; [-1234567890L, -250, 0, 250, 1235657390L])
595         {
596             foreach (tz; testTZs)
597                 test(stdTime, tz);
598         }
599     }
600 
601     /++
602         Params:
603             rhs = The $(LREF SysTime) to assign to this one.
604       +/
605     ref SysTime opAssign(const ref SysTime rhs) return @safe pure nothrow
606     {
607         _stdTime = rhs._stdTime;
608         _timezone = rhs._timezone;
609         return this;
610     }
611 
612     /++
613         Params:
614             rhs = The $(LREF SysTime) to assign to this one.
615       +/
616     ref SysTime opAssign(SysTime rhs) scope return @safe pure nothrow
617     {
618         _stdTime = rhs._stdTime;
619         _timezone = rhs._timezone;
620         return this;
621     }
622 
623     /++
624         Checks for equality between this $(LREF SysTime) and the given
625         $(LREF SysTime).
626 
627         Note that the time zone is ignored. Only the internal
628         std times (which are in UTC) are compared.
629      +/
630     bool opEquals(const SysTime rhs) @safe const pure nothrow
631     {
632         return opEquals(rhs);
633     }
634 
635     /// ditto
636     bool opEquals(const ref SysTime rhs) @safe const pure nothrow
637     {
638         return _stdTime == rhs._stdTime;
639     }
640 
641     @safe unittest
642     {
643         import std.range : chain;
644 
645         assert(SysTime(DateTime.init, UTC()) == SysTime(0, UTC()));
646         assert(SysTime(DateTime.init, UTC()) == SysTime(0));
647         assert(SysTime(Date.init, UTC()) == SysTime(0));
648         assert(SysTime(0) == SysTime(0));
649 
650         static void test(DateTime dt, immutable TimeZone tz1, immutable TimeZone tz2)
651         {
652             auto st1 = SysTime(dt);
653             st1.timezone = tz1;
654 
655             auto st2 = SysTime(dt);
656             st2.timezone = tz2;
657 
658             assert(st1 == st2);
659         }
660 
661         foreach (tz1; testTZs)
662         {
663             foreach (tz2; testTZs)
664             {
665                 foreach (dt; chain(testDateTimesBC, testDateTimesAD))
666                     test(dt, tz1, tz2);
667             }
668         }
669 
670         auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
671         const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
672         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
673         assert(st == st);
674         assert(st == cst);
675         //assert(st == ist);
676         assert(cst == st);
677         assert(cst == cst);
678         //assert(cst == ist);
679         //assert(ist == st);
680         //assert(ist == cst);
681         //assert(ist == ist);
682     }
683 
684     /++
685         Compares this $(LREF SysTime) with the given $(LREF SysTime).
686 
687         Time zone is irrelevant when comparing $(LREF SysTime)s.
688 
689         Returns:
690             $(BOOKTABLE,
691             $(TR $(TD this &lt; rhs) $(TD &lt; 0))
692             $(TR $(TD this == rhs) $(TD 0))
693             $(TR $(TD this &gt; rhs) $(TD &gt; 0))
694             )
695      +/
696     int opCmp(in SysTime rhs) @safe const pure nothrow
697     {
698         if (_stdTime < rhs._stdTime)
699             return -1;
700         if (_stdTime > rhs._stdTime)
701             return 1;
702         return 0;
703     }
704 
705     @safe unittest
706     {
707         import std.algorithm.iteration : map;
708         import std.array : array;
709         import std.range : chain;
710 
711         assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0, UTC())) == 0);
712         assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0)) == 0);
713         assert(SysTime(Date.init, UTC()).opCmp(SysTime(0)) == 0);
714         assert(SysTime(0).opCmp(SysTime(0)) == 0);
715 
716         static void testEqual(SysTime st, immutable TimeZone tz1, immutable TimeZone tz2)
717         {
718             auto st1 = st;
719             st1.timezone = tz1;
720 
721             auto st2 = st;
722             st2.timezone = tz2;
723 
724             assert(st1.opCmp(st2) == 0);
725         }
726 
727         auto sts = array(map!SysTime(chain(testDateTimesBC, testDateTimesAD)));
728 
729         foreach (st; sts)
730         {
731             foreach (tz1; testTZs)
732             {
733                 foreach (tz2; testTZs)
734                     testEqual(st, tz1, tz2);
735             }
736         }
737 
738         static void testCmp(SysTime st1, immutable TimeZone tz1, SysTime st2, immutable TimeZone tz2)
739         {
740             st1.timezone = tz1;
741             st2.timezone = tz2;
742             assert(st1.opCmp(st2) < 0);
743             assert(st2.opCmp(st1) > 0);
744         }
745 
746         foreach (si, st1; sts)
747         {
748             foreach (st2; sts[si + 1 .. $])
749             {
750                 foreach (tz1; testTZs)
751                 {
752                     foreach (tz2; testTZs)
753                         testCmp(st1, tz1, st2, tz2);
754                 }
755             }
756         }
757 
758         auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
759         const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
760         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
761         assert(st.opCmp(st) == 0);
762         assert(st.opCmp(cst) == 0);
763         //assert(st.opCmp(ist) == 0);
764         assert(cst.opCmp(st) == 0);
765         assert(cst.opCmp(cst) == 0);
766         //assert(cst.opCmp(ist) == 0);
767         //assert(ist.opCmp(st) == 0);
768         //assert(ist.opCmp(cst) == 0);
769         //assert(ist.opCmp(ist) == 0);
770     }
771 
772     /**
773      * Returns: A hash of the $(LREF SysTime)
774      */
775     size_t toHash() const @nogc pure nothrow @safe
776     {
777         static if (is(size_t == ulong))
778             return _stdTime;
779         else
780         {
781             // MurmurHash2
782             enum ulong m = 0xc6a4a7935bd1e995UL;
783             enum ulong n = m * 16;
784             enum uint r = 47;
785 
786             ulong k = _stdTime;
787             k *= m;
788             k ^= k >> r;
789             k *= m;
790 
791             ulong h = n;
792             h ^= k;
793             h *= m;
794 
795             return cast(size_t) h;
796         }
797     }
798 
799     @safe unittest
800     {
801         assert(SysTime(0).toHash == SysTime(0).toHash);
802         assert(SysTime(DateTime(2000, 1, 1)).toHash == SysTime(DateTime(2000, 1, 1)).toHash);
803         assert(SysTime(DateTime(2000, 1, 1)).toHash != SysTime(DateTime(2000, 1, 2)).toHash);
804 
805         // test that timezones aren't taken into account
806         assert(SysTime(0, LocalTime()).toHash == SysTime(0, LocalTime()).toHash);
807         assert(SysTime(0, LocalTime()).toHash == SysTime(0, UTC()).toHash);
808         assert(SysTime(DateTime(2000, 1, 1), LocalTime()).toHash == SysTime(DateTime(2000, 1, 1), LocalTime()).toHash);
809         immutable zone = new SimpleTimeZone(dur!"minutes"(60));
810         assert(SysTime(DateTime(2000, 1, 1, 1), zone).toHash == SysTime(DateTime(2000, 1, 1), UTC()).toHash);
811         assert(SysTime(DateTime(2000, 1, 1), zone).toHash != SysTime(DateTime(2000, 1, 1), UTC()).toHash);
812     }
813 
814     /++
815         Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
816         are B.C.
817      +/
818     @property short year() @safe const nothrow
819     {
820         return (cast(Date) this).year;
821     }
822 
823     @safe unittest
824     {
825         import std.range : chain;
826         static void test(SysTime sysTime, long expected)
827         {
828             assert(sysTime.year == expected, format("Value given: %s", sysTime));
829         }
830 
831         test(SysTime(0, UTC()), 1);
832         test(SysTime(1, UTC()), 1);
833         test(SysTime(-1, UTC()), 0);
834 
835         foreach (year; chain(testYearsBC, testYearsAD))
836         {
837             foreach (md; testMonthDays)
838             {
839                 foreach (tod; testTODs)
840                 {
841                     auto dt = DateTime(Date(year, md.month, md.day), tod);
842                     foreach (tz; testTZs)
843                     {
844                         foreach (fs; testFracSecs)
845                             test(SysTime(dt, fs, tz), year);
846                     }
847                 }
848             }
849         }
850 
851         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
852         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
853         assert(cst.year == 1999);
854         //assert(ist.year == 1999);
855     }
856 
857     /++
858         Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
859         are B.C.
860 
861         Params:
862             year = The year to set this $(LREF SysTime)'s year to.
863 
864         Throws:
865             $(REF DateTimeException,std,datetime,date) if the new year is not
866             a leap year and the resulting date would be on February 29th.
867      +/
868     @property void year(int year) @safe
869     {
870         auto hnsecs = adjTime;
871         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
872 
873         if (hnsecs < 0)
874         {
875             hnsecs += convert!("hours", "hnsecs")(24);
876             --days;
877         }
878 
879         auto date = Date(cast(int) days);
880         date.year = year;
881 
882         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
883         adjTime = newDaysHNSecs + hnsecs;
884     }
885 
886     ///
887     @safe unittest
888     {
889         import std.datetime.date : DateTime;
890 
891         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).year == 1999);
892         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).year == 2010);
893         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).year == -7);
894     }
895 
896     @safe unittest
897     {
898         import std.range : chain;
899 
900         static void test(SysTime st, int year, in SysTime expected)
901         {
902             st.year = year;
903             assert(st == expected);
904         }
905 
906         foreach (st; chain(testSysTimesBC, testSysTimesAD))
907         {
908             auto dt = cast(DateTime) st;
909 
910             foreach (year; chain(testYearsBC, testYearsAD))
911             {
912                 auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
913                                  st.fracSecs,
914                                  st.timezone);
915                 test(st, year, e);
916             }
917         }
918 
919         foreach (fs; testFracSecs)
920         {
921             foreach (tz; testTZs)
922             {
923                 foreach (tod; testTODs)
924                 {
925                     test(SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz), 2000,
926                          SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz));
927                     test(SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz), 1999,
928                          SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz));
929                 }
930 
931                 foreach (tod; testTODsThrown)
932                 {
933                     auto st = SysTime(DateTime(Date(2000, 2, 29), tod), fs, tz);
934                     assertThrown!DateTimeException(st.year = 1999);
935                 }
936             }
937         }
938 
939         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
940         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
941         static assert(!__traits(compiles, cst.year = 7));
942         //static assert(!__traits(compiles, ist.year = 7));
943     }
944 
945     /++
946         Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
947 
948         Throws:
949             $(REF DateTimeException,std,datetime,date) if $(D isAD) is true.
950      +/
951     @property ushort yearBC() @safe const
952     {
953         return (cast(Date) this).yearBC;
954     }
955 
956     ///
957     @safe unittest
958     {
959         import std.datetime.date : DateTime;
960 
961         assert(SysTime(DateTime(0, 1, 1, 12, 30, 33)).yearBC == 1);
962         assert(SysTime(DateTime(-1, 1, 1, 10, 7, 2)).yearBC == 2);
963         assert(SysTime(DateTime(-100, 1, 1, 4, 59, 0)).yearBC == 101);
964     }
965 
966     @safe unittest
967     {
968         import std.exception : assertNotThrown;
969         foreach (st; testSysTimesBC)
970         {
971             auto msg = format("SysTime: %s", st);
972             assertNotThrown!DateTimeException(st.yearBC, msg);
973             assert(st.yearBC == (st.year * -1) + 1, msg);
974         }
975 
976         foreach (st; [testSysTimesAD[0], testSysTimesAD[$/2], testSysTimesAD[$-1]])
977             assertThrown!DateTimeException(st.yearBC, format("SysTime: %s", st));
978 
979         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
980         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
981         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
982         st.year = 12;
983         assert(st.year == 12);
984         static assert(!__traits(compiles, cst.year = 12));
985         //static assert(!__traits(compiles, ist.year = 12));
986     }
987 
988 
989     /++
990         Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
991 
992         Params:
993             year = The year B.C. to set this $(LREF SysTime)'s year to.
994 
995         Throws:
996             $(REF DateTimeException,std,datetime,date) if a non-positive value
997             is given.
998      +/
999     @property void yearBC(int year) @safe
1000     {
1001         auto hnsecs = adjTime;
1002         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1003 
1004         if (hnsecs < 0)
1005         {
1006             hnsecs += convert!("hours", "hnsecs")(24);
1007             --days;
1008         }
1009 
1010         auto date = Date(cast(int) days);
1011         date.yearBC = year;
1012 
1013         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1014         adjTime = newDaysHNSecs + hnsecs;
1015     }
1016 
1017     @safe unittest
1018     {
1019         auto st = SysTime(DateTime(2010, 1, 1, 7, 30, 0));
1020         st.yearBC = 1;
1021         assert(st == SysTime(DateTime(0, 1, 1, 7, 30, 0)));
1022 
1023         st.yearBC = 10;
1024         assert(st == SysTime(DateTime(-9, 1, 1, 7, 30, 0)));
1025     }
1026 
1027     @safe unittest
1028     {
1029         import std.range : chain;
1030         static void test(SysTime st, int year, in SysTime expected)
1031         {
1032             st.yearBC = year;
1033             assert(st == expected, format("SysTime: %s", st));
1034         }
1035 
1036         foreach (st; chain(testSysTimesBC, testSysTimesAD))
1037         {
1038             auto dt = cast(DateTime) st;
1039 
1040             foreach (year; testYearsBC)
1041             {
1042                 auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
1043                                  st.fracSecs,
1044                                  st.timezone);
1045                 test(st, (year * -1) + 1, e);
1046             }
1047         }
1048 
1049         foreach (st; [testSysTimesBC[0], testSysTimesBC[$ - 1], testSysTimesAD[0], testSysTimesAD[$ - 1]])
1050         {
1051             foreach (year; testYearsBC)
1052                 assertThrown!DateTimeException(st.yearBC = year);
1053         }
1054 
1055         foreach (fs; testFracSecs)
1056         {
1057             foreach (tz; testTZs)
1058             {
1059                 foreach (tod; testTODs)
1060                 {
1061                     test(SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz), 2001,
1062                          SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz));
1063                     test(SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz), 2000,
1064                          SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz));
1065                 }
1066 
1067                 foreach (tod; testTODsThrown)
1068                 {
1069                     auto st = SysTime(DateTime(Date(-2000, 2, 29), tod), fs, tz);
1070                     assertThrown!DateTimeException(st.year = -1999);
1071                 }
1072             }
1073         }
1074 
1075         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1076         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1077         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1078         st.yearBC = 12;
1079         assert(st.yearBC == 12);
1080         static assert(!__traits(compiles, cst.yearBC = 12));
1081         //static assert(!__traits(compiles, ist.yearBC = 12));
1082     }
1083 
1084     /++
1085         Month of a Gregorian Year.
1086      +/
1087     @property Month month() @safe const nothrow
1088     {
1089         return (cast(Date) this).month;
1090     }
1091 
1092     ///
1093     @safe unittest
1094     {
1095         import std.datetime.date : DateTime;
1096 
1097         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).month == 7);
1098         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).month == 10);
1099         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).month == 4);
1100     }
1101 
1102     @safe unittest
1103     {
1104         import std.range : chain;
1105 
1106         static void test(SysTime sysTime, Month expected)
1107         {
1108             assert(sysTime.month == expected, format("Value given: %s", sysTime));
1109         }
1110 
1111         test(SysTime(0, UTC()), Month.jan);
1112         test(SysTime(1, UTC()), Month.jan);
1113         test(SysTime(-1, UTC()), Month.dec);
1114 
1115         foreach (year; chain(testYearsBC, testYearsAD))
1116         {
1117             foreach (md; testMonthDays)
1118             {
1119                 foreach (tod; testTODs)
1120                 {
1121                     auto dt = DateTime(Date(year, md.month, md.day), tod);
1122                     foreach (fs; testFracSecs)
1123                     {
1124                         foreach (tz; testTZs)
1125                             test(SysTime(dt, fs, tz), md.month);
1126                     }
1127                 }
1128             }
1129         }
1130 
1131         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1132         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1133         assert(cst.month == 7);
1134         //assert(ist.month == 7);
1135     }
1136 
1137 
1138     /++
1139         Month of a Gregorian Year.
1140 
1141         Params:
1142             month = The month to set this $(LREF SysTime)'s month to.
1143 
1144         Throws:
1145             $(REF DateTimeException,std,datetime,date) if the given month is
1146             not a valid month.
1147      +/
1148     @property void month(Month month) @safe
1149     {
1150         auto hnsecs = adjTime;
1151         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1152 
1153         if (hnsecs < 0)
1154         {
1155             hnsecs += convert!("hours", "hnsecs")(24);
1156             --days;
1157         }
1158 
1159         auto date = Date(cast(int) days);
1160         date.month = month;
1161 
1162         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1163         adjTime = newDaysHNSecs + hnsecs;
1164     }
1165 
1166     @safe unittest
1167     {
1168         import std.algorithm.iteration : filter;
1169         import std.range : chain;
1170 
1171         static void test(SysTime st, Month month, in SysTime expected)
1172         {
1173             st.month = cast(Month) month;
1174             assert(st == expected);
1175         }
1176 
1177         foreach (st; chain(testSysTimesBC, testSysTimesAD))
1178         {
1179             auto dt = cast(DateTime) st;
1180 
1181             foreach (md; testMonthDays)
1182             {
1183                 if (st.day > maxDay(dt.year, md.month))
1184                     continue;
1185                 auto e = SysTime(DateTime(dt.year, md.month, dt.day, dt.hour, dt.minute, dt.second),
1186                                  st.fracSecs,
1187                                  st.timezone);
1188                 test(st, md.month, e);
1189             }
1190         }
1191 
1192         foreach (fs; testFracSecs)
1193         {
1194             foreach (tz; testTZs)
1195             {
1196                 foreach (tod; testTODs)
1197                 {
1198                     foreach (year; filter!((a){return yearIsLeapYear(a);}) (chain(testYearsBC, testYearsAD)))
1199                     {
1200                         test(SysTime(DateTime(Date(year, 1, 29), tod), fs, tz),
1201                              Month.feb,
1202                              SysTime(DateTime(Date(year, 2, 29), tod), fs, tz));
1203                     }
1204 
1205                     foreach (year; chain(testYearsBC, testYearsAD))
1206                     {
1207                         test(SysTime(DateTime(Date(year, 1, 28), tod), fs, tz),
1208                              Month.feb,
1209                              SysTime(DateTime(Date(year, 2, 28), tod), fs, tz));
1210                         test(SysTime(DateTime(Date(year, 7, 30), tod), fs, tz),
1211                              Month.jun,
1212                              SysTime(DateTime(Date(year, 6, 30), tod), fs, tz));
1213                     }
1214                 }
1215             }
1216         }
1217 
1218         foreach (fs; [testFracSecs[0], testFracSecs[$-1]])
1219         {
1220             foreach (tz; testTZs)
1221             {
1222                 foreach (tod; testTODsThrown)
1223                 {
1224                     foreach (year; [testYearsBC[$-3], testYearsBC[$-2],
1225                                     testYearsBC[$-2], testYearsAD[0],
1226                                     testYearsAD[$-2], testYearsAD[$-1]])
1227                     {
1228                         auto day = yearIsLeapYear(year) ? 30 : 29;
1229                         auto st1 = SysTime(DateTime(Date(year, 1, day), tod), fs, tz);
1230                         assertThrown!DateTimeException(st1.month = Month.feb);
1231 
1232                         auto st2 = SysTime(DateTime(Date(year, 7, 31), tod), fs, tz);
1233                         assertThrown!DateTimeException(st2.month = Month.jun);
1234                     }
1235                 }
1236             }
1237         }
1238 
1239         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1240         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1241         static assert(!__traits(compiles, cst.month = 12));
1242         //static assert(!__traits(compiles, ist.month = 12));
1243     }
1244 
1245     /++
1246         Day of a Gregorian Month.
1247      +/
1248     @property ubyte day() @safe const nothrow
1249     {
1250         return (cast(Date) this).day;
1251     }
1252 
1253     ///
1254     @safe unittest
1255     {
1256         import std.datetime.date : DateTime;
1257 
1258         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).day == 6);
1259         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).day == 4);
1260         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).day == 5);
1261     }
1262 
1263     @safe unittest
1264     {
1265         import std.range : chain;
1266 
1267         static void test(SysTime sysTime, int expected)
1268         {
1269             assert(sysTime.day == expected, format("Value given: %s", sysTime));
1270         }
1271 
1272         test(SysTime(0, UTC()), 1);
1273         test(SysTime(1, UTC()), 1);
1274         test(SysTime(-1, UTC()), 31);
1275 
1276         foreach (year; chain(testYearsBC, testYearsAD))
1277         {
1278             foreach (md; testMonthDays)
1279             {
1280                 foreach (tod; testTODs)
1281                 {
1282                     auto dt = DateTime(Date(year, md.month, md.day), tod);
1283 
1284                     foreach (tz; testTZs)
1285                     {
1286                         foreach (fs; testFracSecs)
1287                             test(SysTime(dt, fs, tz), md.day);
1288                     }
1289                 }
1290             }
1291         }
1292 
1293         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1294         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1295          assert(cst.day == 6);
1296         //assert(ist.day == 6);
1297     }
1298 
1299 
1300     /++
1301         Day of a Gregorian Month.
1302 
1303         Params:
1304             day = The day of the month to set this $(LREF SysTime)'s day to.
1305 
1306         Throws:
1307             $(REF DateTimeException,std,datetime,date) if the given day is not
1308             a valid day of the current month.
1309      +/
1310     @property void day(int day) @safe
1311     {
1312         auto hnsecs = adjTime;
1313         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1314 
1315         if (hnsecs < 0)
1316         {
1317             hnsecs += convert!("hours", "hnsecs")(24);
1318             --days;
1319         }
1320 
1321         auto date = Date(cast(int) days);
1322         date.day = day;
1323 
1324         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1325         adjTime = newDaysHNSecs + hnsecs;
1326     }
1327 
1328     @safe unittest
1329     {
1330         import std.range : chain;
1331         import std.traits : EnumMembers;
1332 
1333         foreach (day; chain(testDays))
1334         {
1335             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1336             {
1337                 auto dt = cast(DateTime) st;
1338 
1339                 if (day > maxDay(dt.year, dt.month))
1340                     continue;
1341                 auto expected = SysTime(DateTime(dt.year, dt.month, day, dt.hour, dt.minute, dt.second),
1342                                         st.fracSecs,
1343                                         st.timezone);
1344                 st.day = day;
1345                 assert(st == expected, format("[%s] [%s]", st, expected));
1346             }
1347         }
1348 
1349         foreach (tz; testTZs)
1350         {
1351             foreach (tod; testTODs)
1352             {
1353                 foreach (fs; testFracSecs)
1354                 {
1355                     foreach (year; chain(testYearsBC, testYearsAD))
1356                     {
1357                         foreach (month; EnumMembers!Month)
1358                         {
1359                             auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz);
1360                             immutable max = maxDay(year, month);
1361                             auto expected = SysTime(DateTime(Date(year, month, max), tod), fs, tz);
1362 
1363                             st.day = max;
1364                             assert(st == expected, format("[%s] [%s]", st, expected));
1365                         }
1366                     }
1367                 }
1368             }
1369         }
1370 
1371         foreach (tz; testTZs)
1372         {
1373             foreach (tod; testTODsThrown)
1374             {
1375                 foreach (fs; [testFracSecs[0], testFracSecs[$-1]])
1376                 {
1377                     foreach (year; [testYearsBC[$-3], testYearsBC[$-2],
1378                                     testYearsBC[$-2], testYearsAD[0],
1379                                     testYearsAD[$-2], testYearsAD[$-1]])
1380                     {
1381                         foreach (month; EnumMembers!Month)
1382                         {
1383                             auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz);
1384                             immutable max = maxDay(year, month);
1385 
1386                             assertThrown!DateTimeException(st.day = max + 1);
1387                         }
1388                     }
1389                 }
1390             }
1391         }
1392 
1393         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1394         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1395         static assert(!__traits(compiles, cst.day = 27));
1396         //static assert(!__traits(compiles, ist.day = 27));
1397     }
1398 
1399 
1400     /++
1401         Hours past midnight.
1402      +/
1403     @property ubyte hour() @safe const nothrow
1404     {
1405         auto hnsecs = adjTime;
1406         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1407 
1408         if (hnsecs < 0)
1409         {
1410             hnsecs += convert!("hours", "hnsecs")(24);
1411             --days;
1412         }
1413 
1414         return cast(ubyte) getUnitsFromHNSecs!"hours"(hnsecs);
1415     }
1416 
1417     @safe unittest
1418     {
1419         import std.range : chain;
1420 
1421         static void test(SysTime sysTime, int expected)
1422         {
1423             assert(sysTime.hour == expected, format("Value given: %s", sysTime));
1424         }
1425 
1426         test(SysTime(0, UTC()), 0);
1427         test(SysTime(1, UTC()), 0);
1428         test(SysTime(-1, UTC()), 23);
1429 
1430         foreach (tz; testTZs)
1431         {
1432             foreach (year; chain(testYearsBC, testYearsAD))
1433             {
1434                 foreach (md; testMonthDays)
1435                 {
1436                     foreach (hour; testHours)
1437                     {
1438                         foreach (minute; testMinSecs)
1439                         {
1440                             foreach (second; testMinSecs)
1441                             {
1442                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1443                                 foreach (fs; testFracSecs)
1444                                     test(SysTime(dt, fs, tz), hour);
1445                             }
1446                         }
1447                     }
1448                 }
1449             }
1450         }
1451 
1452         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1453         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1454         assert(cst.hour == 12);
1455         //assert(ist.hour == 12);
1456     }
1457 
1458 
1459     /++
1460         Hours past midnight.
1461 
1462         Params:
1463             hour = The hours to set this $(LREF SysTime)'s hour to.
1464 
1465         Throws:
1466             $(REF DateTimeException,std,datetime,date) if the given hour are
1467             not a valid hour of the day.
1468      +/
1469     @property void hour(int hour) @safe
1470     {
1471         enforceValid!"hours"(hour);
1472 
1473         auto hnsecs = adjTime;
1474         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1475         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1476         immutable negative = hnsecs < 0;
1477 
1478         if (negative)
1479             hnsecs += convert!("hours", "hnsecs")(24);
1480 
1481         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1482         hnsecs += convert!("hours", "hnsecs")(hour);
1483 
1484         if (negative)
1485             hnsecs -= convert!("hours", "hnsecs")(24);
1486 
1487         adjTime = daysHNSecs + hnsecs;
1488     }
1489 
1490     @safe unittest
1491     {
1492         import std.range : chain;
1493 
1494         foreach (hour; chain(testHours))
1495         {
1496             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1497             {
1498                 auto dt = cast(DateTime) st;
1499                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, hour, dt.minute, dt.second),
1500                                         st.fracSecs,
1501                                         st.timezone);
1502                 st.hour = hour;
1503                 assert(st == expected, format("[%s] [%s]", st, expected));
1504             }
1505         }
1506 
1507         auto st = testSysTimesAD[0];
1508         assertThrown!DateTimeException(st.hour = -1);
1509         assertThrown!DateTimeException(st.hour = 60);
1510 
1511         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1512         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1513         static assert(!__traits(compiles, cst.hour = 27));
1514         //static assert(!__traits(compiles, ist.hour = 27));
1515     }
1516 
1517 
1518     /++
1519         Minutes past the current hour.
1520      +/
1521     @property ubyte minute() @safe const nothrow
1522     {
1523         auto hnsecs = adjTime;
1524         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1525 
1526         if (hnsecs < 0)
1527         {
1528             hnsecs += convert!("hours", "hnsecs")(24);
1529             --days;
1530         }
1531 
1532         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1533 
1534         return cast(ubyte) getUnitsFromHNSecs!"minutes"(hnsecs);
1535     }
1536 
1537     @safe unittest
1538     {
1539         import std.range : chain;
1540 
1541         static void test(SysTime sysTime, int expected)
1542         {
1543             assert(sysTime.minute == expected, format("Value given: %s", sysTime));
1544         }
1545 
1546         test(SysTime(0, UTC()), 0);
1547         test(SysTime(1, UTC()), 0);
1548         test(SysTime(-1, UTC()), 59);
1549 
1550         foreach (tz; testTZs)
1551         {
1552             foreach (year; chain(testYearsBC, testYearsAD))
1553             {
1554                 foreach (md; testMonthDays)
1555                 {
1556                     foreach (hour; testHours)
1557                     {
1558                         foreach (minute; testMinSecs)
1559                         {
1560                             foreach (second; testMinSecs)
1561                             {
1562                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1563                                 foreach (fs; testFracSecs)
1564                                     test(SysTime(dt, fs, tz), minute);
1565                             }
1566                         }
1567                     }
1568                 }
1569             }
1570         }
1571 
1572         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1573         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1574         assert(cst.minute == 30);
1575         //assert(ist.minute == 30);
1576     }
1577 
1578 
1579     /++
1580         Minutes past the current hour.
1581 
1582         Params:
1583             minute = The minute to set this $(LREF SysTime)'s minute to.
1584 
1585         Throws:
1586             $(REF DateTimeException,std,datetime,date) if the given minute are
1587             not a valid minute of an hour.
1588      +/
1589     @property void minute(int minute) @safe
1590     {
1591         enforceValid!"minutes"(minute);
1592 
1593         auto hnsecs = adjTime;
1594         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1595         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1596         immutable negative = hnsecs < 0;
1597 
1598         if (negative)
1599             hnsecs += convert!("hours", "hnsecs")(24);
1600 
1601         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
1602         hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs);
1603 
1604         hnsecs += convert!("hours", "hnsecs")(hour);
1605         hnsecs += convert!("minutes", "hnsecs")(minute);
1606 
1607         if (negative)
1608             hnsecs -= convert!("hours", "hnsecs")(24);
1609 
1610         adjTime = daysHNSecs + hnsecs;
1611     }
1612 
1613     @safe unittest
1614     {
1615         import std.range : chain;
1616 
1617         foreach (minute; testMinSecs)
1618         {
1619             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1620             {
1621                 auto dt = cast(DateTime) st;
1622                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, minute, dt.second),
1623                                         st.fracSecs,
1624                                         st.timezone);
1625                 st.minute = minute;
1626                 assert(st == expected, format("[%s] [%s]", st, expected));
1627             }
1628         }
1629 
1630         auto st = testSysTimesAD[0];
1631         assertThrown!DateTimeException(st.minute = -1);
1632         assertThrown!DateTimeException(st.minute = 60);
1633 
1634         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1635         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1636         static assert(!__traits(compiles, cst.minute = 27));
1637         //static assert(!__traits(compiles, ist.minute = 27));
1638     }
1639 
1640 
1641     /++
1642         Seconds past the current minute.
1643      +/
1644     @property ubyte second() @safe const nothrow
1645     {
1646         auto hnsecs = adjTime;
1647         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1648 
1649         if (hnsecs < 0)
1650         {
1651             hnsecs += convert!("hours", "hnsecs")(24);
1652             --days;
1653         }
1654 
1655         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1656         hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs);
1657 
1658         return cast(ubyte) getUnitsFromHNSecs!"seconds"(hnsecs);
1659     }
1660 
1661     @safe unittest
1662     {
1663         import std.range : chain;
1664 
1665         static void test(SysTime sysTime, int expected)
1666         {
1667             assert(sysTime.second == expected, format("Value given: %s", sysTime));
1668         }
1669 
1670         test(SysTime(0, UTC()), 0);
1671         test(SysTime(1, UTC()), 0);
1672         test(SysTime(-1, UTC()), 59);
1673 
1674         foreach (tz; testTZs)
1675         {
1676             foreach (year; chain(testYearsBC, testYearsAD))
1677             {
1678                 foreach (md; testMonthDays)
1679                 {
1680                     foreach (hour; testHours)
1681                     {
1682                         foreach (minute; testMinSecs)
1683                         {
1684                             foreach (second; testMinSecs)
1685                             {
1686                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1687                                 foreach (fs; testFracSecs)
1688                                     test(SysTime(dt, fs, tz), second);
1689                             }
1690                         }
1691                     }
1692                 }
1693             }
1694         }
1695 
1696         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1697         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1698         assert(cst.second == 33);
1699         //assert(ist.second == 33);
1700     }
1701 
1702 
1703     /++
1704         Seconds past the current minute.
1705 
1706         Params:
1707             second = The second to set this $(LREF SysTime)'s second to.
1708 
1709         Throws:
1710             $(REF DateTimeException,std,datetime,date) if the given second are
1711             not a valid second of a minute.
1712      +/
1713     @property void second(int second) @safe
1714     {
1715         enforceValid!"seconds"(second);
1716 
1717         auto hnsecs = adjTime;
1718         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1719         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1720         immutable negative = hnsecs < 0;
1721 
1722         if (negative)
1723             hnsecs += convert!("hours", "hnsecs")(24);
1724 
1725         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
1726         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
1727         hnsecs = removeUnitsFromHNSecs!"seconds"(hnsecs);
1728 
1729         hnsecs += convert!("hours", "hnsecs")(hour);
1730         hnsecs += convert!("minutes", "hnsecs")(minute);
1731         hnsecs += convert!("seconds", "hnsecs")(second);
1732 
1733         if (negative)
1734             hnsecs -= convert!("hours", "hnsecs")(24);
1735 
1736         adjTime = daysHNSecs + hnsecs;
1737     }
1738 
1739     @safe unittest
1740     {
1741         import std.range : chain;
1742 
1743         foreach (second; testMinSecs)
1744         {
1745             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1746             {
1747                 auto dt = cast(DateTime) st;
1748                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, second),
1749                                         st.fracSecs,
1750                                         st.timezone);
1751                 st.second = second;
1752                 assert(st == expected, format("[%s] [%s]", st, expected));
1753             }
1754         }
1755 
1756         auto st = testSysTimesAD[0];
1757         assertThrown!DateTimeException(st.second = -1);
1758         assertThrown!DateTimeException(st.second = 60);
1759 
1760         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1761         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1762         static assert(!__traits(compiles, cst.seconds = 27));
1763         //static assert(!__traits(compiles, ist.seconds = 27));
1764     }
1765 
1766 
1767     /++
1768         Fractional seconds past the second (i.e. the portion of a
1769         $(LREF SysTime) which is less than a second).
1770      +/
1771     @property Duration fracSecs() @safe const nothrow
1772     {
1773         auto hnsecs = removeUnitsFromHNSecs!"days"(adjTime);
1774 
1775         if (hnsecs < 0)
1776             hnsecs += convert!("hours", "hnsecs")(24);
1777 
1778         return dur!"hnsecs"(removeUnitsFromHNSecs!"seconds"(hnsecs));
1779     }
1780 
1781     ///
1782     @safe unittest
1783     {
1784         import core.time : msecs, usecs, hnsecs, nsecs;
1785         import std.datetime.date : DateTime;
1786 
1787         auto dt = DateTime(1982, 4, 1, 20, 59, 22);
1788         assert(SysTime(dt, msecs(213)).fracSecs == msecs(213));
1789         assert(SysTime(dt, usecs(5202)).fracSecs == usecs(5202));
1790         assert(SysTime(dt, hnsecs(1234567)).fracSecs == hnsecs(1234567));
1791 
1792         // SysTime and Duration both have a precision of hnsecs (100 ns),
1793         // so nsecs are going to be truncated.
1794         assert(SysTime(dt, nsecs(123456789)).fracSecs == nsecs(123456700));
1795     }
1796 
1797     @safe unittest
1798     {
1799         import std.range : chain;
1800 
1801         assert(SysTime(0, UTC()).fracSecs == Duration.zero);
1802         assert(SysTime(1, UTC()).fracSecs == hnsecs(1));
1803         assert(SysTime(-1, UTC()).fracSecs == hnsecs(9_999_999));
1804 
1805         foreach (tz; testTZs)
1806         {
1807             foreach (year; chain(testYearsBC, testYearsAD))
1808             {
1809                 foreach (md; testMonthDays)
1810                 {
1811                     foreach (hour; testHours)
1812                     {
1813                         foreach (minute; testMinSecs)
1814                         {
1815                             foreach (second; testMinSecs)
1816                             {
1817                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1818                                 foreach (fs; testFracSecs)
1819                                     assert(SysTime(dt, fs, tz).fracSecs == fs);
1820                             }
1821                         }
1822                     }
1823                 }
1824             }
1825         }
1826 
1827         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1828         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1829         assert(cst.fracSecs == Duration.zero);
1830         //assert(ist.fracSecs == Duration.zero);
1831     }
1832 
1833 
1834     /++
1835         Fractional seconds past the second (i.e. the portion of a
1836         $(LREF SysTime) which is less than a second).
1837 
1838         Params:
1839             fracSecs = The duration to set this $(LREF SysTime)'s fractional
1840                        seconds to.
1841 
1842         Throws:
1843             $(REF DateTimeException,std,datetime,date) if the given duration
1844             is negative or if it's greater than or equal to one second.
1845      +/
1846     @property void fracSecs(Duration fracSecs) @safe
1847     {
1848         enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
1849         enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
1850 
1851         auto oldHNSecs = adjTime;
1852         auto days = splitUnitsFromHNSecs!"days"(oldHNSecs);
1853         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1854         immutable negative = oldHNSecs < 0;
1855 
1856         if (negative)
1857             oldHNSecs += convert!("hours", "hnsecs")(24);
1858 
1859         immutable seconds = splitUnitsFromHNSecs!"seconds"(oldHNSecs);
1860         immutable secondsHNSecs = convert!("seconds", "hnsecs")(seconds);
1861         auto newHNSecs = fracSecs.total!"hnsecs" + secondsHNSecs;
1862 
1863         if (negative)
1864             newHNSecs -= convert!("hours", "hnsecs")(24);
1865 
1866         adjTime = daysHNSecs + newHNSecs;
1867     }
1868 
1869     ///
1870     @safe unittest
1871     {
1872         import core.time : Duration, msecs, hnsecs, nsecs;
1873         import std.datetime.date : DateTime;
1874 
1875         auto st = SysTime(DateTime(1982, 4, 1, 20, 59, 22));
1876         assert(st.fracSecs == Duration.zero);
1877 
1878         st.fracSecs = msecs(213);
1879         assert(st.fracSecs == msecs(213));
1880 
1881         st.fracSecs = hnsecs(1234567);
1882         assert(st.fracSecs == hnsecs(1234567));
1883 
1884         // SysTime has a precision of hnsecs (100 ns), so nsecs are
1885         // going to be truncated.
1886         st.fracSecs = nsecs(123456789);
1887         assert(st.fracSecs == hnsecs(1234567));
1888     }
1889 
1890     @safe unittest
1891     {
1892         import std.range : chain;
1893 
1894         foreach (fracSec; testFracSecs)
1895         {
1896             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1897             {
1898                 auto dt = cast(DateTime) st;
1899                 auto expected = SysTime(dt, fracSec, st.timezone);
1900                 st.fracSecs = fracSec;
1901                 assert(st == expected, format("[%s] [%s]", st, expected));
1902             }
1903         }
1904 
1905         auto st = testSysTimesAD[0];
1906         assertThrown!DateTimeException(st.fracSecs = hnsecs(-1));
1907         assertThrown!DateTimeException(st.fracSecs = seconds(1));
1908 
1909         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1910         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1911         static assert(!__traits(compiles, cst.fracSecs = msecs(7)));
1912         //static assert(!__traits(compiles, ist.fracSecs = msecs(7)));
1913     }
1914 
1915 
1916     /++
1917         The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the
1918         internal representation of $(LREF SysTime).
1919      +/
1920     @property long stdTime() @safe const pure nothrow
1921     {
1922         return _stdTime;
1923     }
1924 
1925     @safe unittest
1926     {
1927         assert(SysTime(0).stdTime == 0);
1928         assert(SysTime(1).stdTime == 1);
1929         assert(SysTime(-1).stdTime == -1);
1930         assert(SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC()).stdTime == 330_000_502L);
1931         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC()).stdTime == 621_355_968_000_000_000L);
1932 
1933         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1934         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1935         assert(cst.stdTime > 0);
1936         //assert(ist.stdTime > 0);
1937     }
1938 
1939 
1940     /++
1941         The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the
1942         internal representation of $(LREF SysTime).
1943 
1944         Params:
1945             stdTime = The number of hnsecs since January 1st, 1 A.D. UTC.
1946      +/
1947     @property void stdTime(long stdTime) @safe pure nothrow
1948     {
1949         _stdTime = stdTime;
1950     }
1951 
1952     @safe unittest
1953     {
1954         static void test(long stdTime, in SysTime expected, size_t line = __LINE__)
1955         {
1956             auto st = SysTime(0, UTC());
1957             st.stdTime = stdTime;
1958             assert(st == expected);
1959         }
1960 
1961         test(0, SysTime(Date(1, 1, 1), UTC()));
1962         test(1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()));
1963         test(-1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()));
1964         test(330_000_502L, SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC()));
1965         test(621_355_968_000_000_000L, SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC()));
1966 
1967         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1968         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1969         static assert(!__traits(compiles, cst.stdTime = 27));
1970         //static assert(!__traits(compiles, ist.stdTime = 27));
1971     }
1972 
1973 
1974     /++
1975         The current time zone of this $(LREF SysTime). Its internal time is
1976         always kept in UTC, so there are no conversion issues between time zones
1977         due to DST. Functions which return all or part of the time - such as
1978         hours - adjust the time to this $(LREF SysTime)'s time zone before
1979         returning.
1980       +/
1981     @property immutable(TimeZone) timezone() @safe const pure nothrow
1982     {
1983         return _timezone;
1984     }
1985 
1986 
1987     /++
1988         The current time zone of this $(LREF SysTime). It's internal time is
1989         always kept in UTC, so there are no conversion issues between time zones
1990         due to DST. Functions which return all or part of the time - such as
1991         hours - adjust the time to this $(LREF SysTime)'s time zone before
1992         returning.
1993 
1994         Params:
1995             timezone = The $(REF _TimeZone,std,datetime,_timezone) to set this
1996                        $(LREF SysTime)'s time zone to.
1997       +/
1998     @property void timezone(immutable TimeZone timezone) @safe pure nothrow
1999     {
2000         if (timezone is null)
2001             _timezone = LocalTime();
2002         else
2003             _timezone = timezone;
2004     }
2005 
2006 
2007     /++
2008         Returns whether DST is in effect for this $(LREF SysTime).
2009       +/
2010     @property bool dstInEffect() @safe const nothrow
2011     {
2012         return _timezone.dstInEffect(_stdTime);
2013         // This function's unit testing is done in the time zone classes.
2014     }
2015 
2016 
2017     /++
2018         Returns what the offset from UTC is for this $(LREF SysTime).
2019         It includes the DST offset in effect at that time (if any).
2020       +/
2021     @property Duration utcOffset() @safe const nothrow
2022     {
2023         return _timezone.utcOffsetAt(_stdTime);
2024     }
2025 
2026 
2027     /++
2028         Returns a $(LREF SysTime) with the same std time as this one, but with
2029         $(REF LocalTime,std,datetime,timezone) as its time zone.
2030       +/
2031     SysTime toLocalTime() @safe const pure nothrow
2032     {
2033         return SysTime(_stdTime, LocalTime());
2034     }
2035 
2036     @safe unittest
2037     {
2038         {
2039             auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2040             assert(sysTime == sysTime.toLocalTime());
2041             assert(sysTime._stdTime == sysTime.toLocalTime()._stdTime);
2042             assert(sysTime.toLocalTime().timezone is LocalTime());
2043             assert(sysTime.toLocalTime().timezone is sysTime.timezone);
2044             assert(sysTime.toLocalTime().timezone !is UTC());
2045         }
2046 
2047         {
2048             auto stz = new immutable SimpleTimeZone(dur!"minutes"(-3 * 60));
2049             auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27), stz);
2050             assert(sysTime == sysTime.toLocalTime());
2051             assert(sysTime._stdTime == sysTime.toLocalTime()._stdTime);
2052             assert(sysTime.toLocalTime().timezone is LocalTime());
2053             assert(sysTime.toLocalTime().timezone !is UTC());
2054             assert(sysTime.toLocalTime().timezone !is stz);
2055         }
2056     }
2057 
2058 
2059     /++
2060         Returns a $(LREF SysTime) with the same std time as this one, but with
2061         $(D UTC) as its time zone.
2062       +/
2063     SysTime toUTC() @safe const pure nothrow
2064     {
2065         return SysTime(_stdTime, UTC());
2066     }
2067 
2068     @safe unittest
2069     {
2070         auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2071         assert(sysTime == sysTime.toUTC());
2072         assert(sysTime._stdTime == sysTime.toUTC()._stdTime);
2073         assert(sysTime.toUTC().timezone is UTC());
2074         assert(sysTime.toUTC().timezone !is LocalTime());
2075         assert(sysTime.toUTC().timezone !is sysTime.timezone);
2076     }
2077 
2078 
2079     /++
2080         Returns a $(LREF SysTime) with the same std time as this one, but with
2081         given time zone as its time zone.
2082       +/
2083     SysTime toOtherTZ(immutable TimeZone tz) @safe const pure nothrow
2084     {
2085         if (tz is null)
2086             return SysTime(_stdTime, LocalTime());
2087         else
2088             return SysTime(_stdTime, tz);
2089     }
2090 
2091     @safe unittest
2092     {
2093         auto stz = new immutable SimpleTimeZone(dur!"minutes"(11 * 60));
2094         auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2095         assert(sysTime == sysTime.toOtherTZ(stz));
2096         assert(sysTime._stdTime == sysTime.toOtherTZ(stz)._stdTime);
2097         assert(sysTime.toOtherTZ(stz).timezone is stz);
2098         assert(sysTime.toOtherTZ(stz).timezone !is LocalTime());
2099         assert(sysTime.toOtherTZ(stz).timezone !is UTC());
2100     }
2101 
2102 
2103     /++
2104         Converts this $(LREF SysTime) to unix time (i.e. seconds from midnight,
2105         January 1st, 1970 in UTC).
2106 
2107         The C standard does not specify the representation of time_t, so it is
2108         implementation defined. On POSIX systems, unix time is equivalent to
2109         time_t, but that's not necessarily true on other systems (e.g. it is
2110         not true for the Digital Mars C runtime). So, be careful when using unix
2111         time with C functions on non-POSIX systems.
2112 
2113         By default, the return type is time_t (which is normally an alias for
2114         int on 32-bit systems and long on 64-bit systems), but if a different
2115         size is required than either int or long can be passed as a template
2116         argument to get the desired size.
2117 
2118         If the return type is int, and the result can't fit in an int, then the
2119         closest value that can be held in 32 bits will be used (so $(D int.max)
2120         if it goes over and $(D int.min) if it goes under). However, no attempt
2121         is made to deal with integer overflow if the return type is long.
2122 
2123         Params:
2124             T = The return type (int or long). It defaults to time_t, which is
2125                 normally 32 bits on a 32-bit system and 64 bits on a 64-bit
2126                 system.
2127 
2128         Returns:
2129             A signed integer representing the unix time which is equivalent to
2130             this SysTime.
2131       +/
2132     T toUnixTime(T = time_t)() @safe const pure nothrow
2133         if (is(T == int) || is(T == long))
2134     {
2135         return stdTimeToUnixTime!T(_stdTime);
2136     }
2137 
2138     ///
2139     @safe unittest
2140     {
2141         import core.time : hours;
2142         import std.datetime.date : DateTime;
2143         import std.datetime.timezone : SimpleTimeZone, UTC;
2144 
2145         assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0);
2146 
2147         auto pst = new immutable SimpleTimeZone(hours(-8));
2148         assert(SysTime(DateTime(1970, 1, 1), pst).toUnixTime() == 28800);
2149 
2150         auto utc = SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC());
2151         assert(utc.toUnixTime() == 1_198_311_285);
2152 
2153         auto ca = SysTime(DateTime(2007, 12, 22, 8, 14, 45), pst);
2154         assert(ca.toUnixTime() == 1_198_340_085);
2155     }
2156 
2157     @safe unittest
2158     {
2159         import std.meta : AliasSeq;
2160         assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0);
2161         foreach (units; AliasSeq!("hnsecs", "usecs", "msecs"))
2162             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), dur!units(1), UTC()).toUnixTime() == 0);
2163         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toUnixTime() == 1);
2164         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toUnixTime() == 0);
2165         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toUnixTime() == 0);
2166         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toUnixTime() == 0);
2167         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toUnixTime() == -1);
2168     }
2169 
2170 
2171     /++
2172         Converts from unix time (i.e. seconds from midnight, January 1st, 1970
2173         in UTC) to a $(LREF SysTime).
2174 
2175         The C standard does not specify the representation of time_t, so it is
2176         implementation defined. On POSIX systems, unix time is equivalent to
2177         time_t, but that's not necessarily true on other systems (e.g. it is
2178         not true for the Digital Mars C runtime). So, be careful when using unix
2179         time with C functions on non-POSIX systems.
2180 
2181         Params:
2182             unixTime = Seconds from midnight, January 1st, 1970 in UTC.
2183             tz = The time zone for the SysTime that's returned.
2184       +/
2185     static SysTime fromUnixTime(long unixTime, immutable TimeZone tz = LocalTime()) @safe pure nothrow
2186     {
2187         return SysTime(unixTimeToStdTime(unixTime), tz);
2188     }
2189 
2190     ///
2191     @safe unittest
2192     {
2193         import core.time : hours;
2194         import std.datetime.date : DateTime;
2195         import std.datetime.timezone : SimpleTimeZone, UTC;
2196 
2197         assert(SysTime.fromUnixTime(0) ==
2198                SysTime(DateTime(1970, 1, 1), UTC()));
2199 
2200         auto pst = new immutable SimpleTimeZone(hours(-8));
2201         assert(SysTime.fromUnixTime(28800) ==
2202                SysTime(DateTime(1970, 1, 1), pst));
2203 
2204         auto st1 = SysTime.fromUnixTime(1_198_311_285, UTC());
2205         assert(st1 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC()));
2206         assert(st1.timezone is UTC());
2207         assert(st1 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst));
2208 
2209         auto st2 = SysTime.fromUnixTime(1_198_311_285, pst);
2210         assert(st2 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC()));
2211         assert(st2.timezone is pst);
2212         assert(st2 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst));
2213     }
2214 
2215     @safe unittest
2216     {
2217         assert(SysTime.fromUnixTime(0) == SysTime(DateTime(1970, 1, 1), UTC()));
2218         assert(SysTime.fromUnixTime(1) == SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()));
2219         assert(SysTime.fromUnixTime(-1) == SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()));
2220 
2221         auto st = SysTime.fromUnixTime(0);
2222         auto dt = cast(DateTime) st;
2223         assert(dt <= DateTime(1970, 2, 1) && dt >= DateTime(1969, 12, 31));
2224         assert(st.timezone is LocalTime());
2225 
2226         auto aest = new immutable SimpleTimeZone(hours(10));
2227         assert(SysTime.fromUnixTime(-36000) == SysTime(DateTime(1970, 1, 1), aest));
2228     }
2229 
2230 
2231     /++
2232         Returns a $(D timeval) which represents this $(LREF SysTime).
2233 
2234         Note that like all conversions in std.datetime, this is a truncating
2235         conversion.
2236 
2237         If $(D timeval.tv_sec) is int, and the result can't fit in an int, then
2238         the closest value that can be held in 32 bits will be used for
2239         $(D tv_sec). (so $(D int.max) if it goes over and $(D int.min) if it
2240         goes under).
2241       +/
2242     timeval toTimeVal() @safe const pure nothrow
2243     {
2244         immutable tv_sec = toUnixTime!(typeof(timeval.tv_sec))();
2245         immutable fracHNSecs = removeUnitsFromHNSecs!"seconds"(_stdTime - 621_355_968_000_000_000L);
2246         immutable tv_usec = cast(typeof(timeval.tv_usec))convert!("hnsecs", "usecs")(fracHNSecs);
2247         return timeval(tv_sec, tv_usec);
2248     }
2249 
2250     @safe unittest
2251     {
2252         assert(SysTime(DateTime(1970, 1, 1), UTC()).toTimeVal() == timeval(0, 0));
2253         assert(SysTime(DateTime(1970, 1, 1), hnsecs(9), UTC()).toTimeVal() == timeval(0, 0));
2254         assert(SysTime(DateTime(1970, 1, 1), hnsecs(10), UTC()).toTimeVal() == timeval(0, 1));
2255         assert(SysTime(DateTime(1970, 1, 1), usecs(7), UTC()).toTimeVal() == timeval(0, 7));
2256 
2257         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toTimeVal() == timeval(1, 0));
2258         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(9), UTC()).toTimeVal() == timeval(1, 0));
2259         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(10), UTC()).toTimeVal() == timeval(1, 1));
2260         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), usecs(7), UTC()).toTimeVal() == timeval(1, 7));
2261 
2262         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toTimeVal() == timeval(0, 0));
2263         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_990), UTC()).toTimeVal() == timeval(0, -1));
2264 
2265         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toTimeVal() == timeval(0, -1));
2266         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999), UTC()).toTimeVal() == timeval(0, -999_001));
2267         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toTimeVal() == timeval(0, -1000));
2268         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toTimeVal() == timeval(-1, 0));
2269         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 58), usecs(17), UTC()).toTimeVal() == timeval(-1, -999_983));
2270     }
2271 
2272 
2273     version (StdDdoc)
2274     {
2275         private struct timespec {}
2276         /++
2277             Returns a $(D timespec) which represents this $(LREF SysTime).
2278 
2279             $(BLUE This function is Posix-Only.)
2280           +/
2281         timespec toTimeSpec() @safe const pure nothrow;
2282     }
2283     else version (Posix)
2284     {
2285         timespec toTimeSpec() @safe const pure nothrow
2286         {
2287             immutable tv_sec = toUnixTime!(typeof(timespec.tv_sec))();
2288             immutable fracHNSecs = removeUnitsFromHNSecs!"seconds"(_stdTime - 621_355_968_000_000_000L);
2289             immutable tv_nsec = cast(typeof(timespec.tv_nsec))convert!("hnsecs", "nsecs")(fracHNSecs);
2290             return timespec(tv_sec, tv_nsec);
2291         }
2292 
2293         @safe unittest
2294         {
2295             assert(SysTime(DateTime(1970, 1, 1), UTC()).toTimeSpec() == timespec(0, 0));
2296             assert(SysTime(DateTime(1970, 1, 1), hnsecs(9), UTC()).toTimeSpec() == timespec(0, 900));
2297             assert(SysTime(DateTime(1970, 1, 1), hnsecs(10), UTC()).toTimeSpec() == timespec(0, 1000));
2298             assert(SysTime(DateTime(1970, 1, 1), usecs(7), UTC()).toTimeSpec() == timespec(0, 7000));
2299 
2300             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toTimeSpec() == timespec(1, 0));
2301             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(9), UTC()).toTimeSpec() == timespec(1, 900));
2302             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(10), UTC()).toTimeSpec() == timespec(1, 1000));
2303             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), usecs(7), UTC()).toTimeSpec() == timespec(1, 7000));
2304 
2305             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toTimeSpec() ==
2306                    timespec(0, -100));
2307             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_990), UTC()).toTimeSpec() ==
2308                    timespec(0, -1000));
2309 
2310             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toTimeSpec() ==
2311                    timespec(0, -1_000));
2312             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999), UTC()).toTimeSpec() ==
2313                    timespec(0, -999_001_000));
2314             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toTimeSpec() ==
2315                    timespec(0, -1_000_000));
2316             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toTimeSpec() ==
2317                    timespec(-1, 0));
2318             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 58), usecs(17), UTC()).toTimeSpec() ==
2319                    timespec(-1, -999_983_000));
2320         }
2321     }
2322 
2323     /++
2324         Returns a $(D tm) which represents this $(LREF SysTime).
2325       +/
2326     tm toTM() @safe const nothrow
2327     {
2328         auto dateTime = cast(DateTime) this;
2329         tm timeInfo;
2330 
2331         timeInfo.tm_sec = dateTime.second;
2332         timeInfo.tm_min = dateTime.minute;
2333         timeInfo.tm_hour = dateTime.hour;
2334         timeInfo.tm_mday = dateTime.day;
2335         timeInfo.tm_mon = dateTime.month - 1;
2336         timeInfo.tm_year = dateTime.year - 1900;
2337         timeInfo.tm_wday = dateTime.dayOfWeek;
2338         timeInfo.tm_yday = dateTime.dayOfYear - 1;
2339         timeInfo.tm_isdst = _timezone.dstInEffect(_stdTime);
2340 
2341         version (Posix)
2342         {
2343             import std.utf : toUTFz;
2344             timeInfo.tm_gmtoff = cast(int) convert!("hnsecs", "seconds")(adjTime - _stdTime);
2345             auto zone = (timeInfo.tm_isdst ? _timezone.dstName : _timezone.stdName);
2346             timeInfo.tm_zone = zone.toUTFz!(char*)();
2347         }
2348 
2349         return timeInfo;
2350     }
2351 
2352     @system unittest
2353     {
2354         import std.conv : to;
2355 
2356         version (Posix)
2357         {
2358             scope(exit) clearTZEnvVar();
2359             setTZEnvVar("America/Los_Angeles");
2360         }
2361 
2362         {
2363             auto timeInfo = SysTime(DateTime(1970, 1, 1)).toTM();
2364 
2365             assert(timeInfo.tm_sec == 0);
2366             assert(timeInfo.tm_min == 0);
2367             assert(timeInfo.tm_hour == 0);
2368             assert(timeInfo.tm_mday == 1);
2369             assert(timeInfo.tm_mon == 0);
2370             assert(timeInfo.tm_year == 70);
2371             assert(timeInfo.tm_wday == 4);
2372             assert(timeInfo.tm_yday == 0);
2373 
2374             version (Posix)
2375                 assert(timeInfo.tm_isdst == 0);
2376             else version (Windows)
2377                 assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
2378 
2379             version (Posix)
2380             {
2381                 assert(timeInfo.tm_gmtoff == -8 * 60 * 60);
2382                 assert(to!string(timeInfo.tm_zone) == "PST");
2383             }
2384         }
2385 
2386         {
2387             auto timeInfo = SysTime(DateTime(2010, 7, 4, 12, 15, 7), hnsecs(15)).toTM();
2388 
2389             assert(timeInfo.tm_sec == 7);
2390             assert(timeInfo.tm_min == 15);
2391             assert(timeInfo.tm_hour == 12);
2392             assert(timeInfo.tm_mday == 4);
2393             assert(timeInfo.tm_mon == 6);
2394             assert(timeInfo.tm_year == 110);
2395             assert(timeInfo.tm_wday == 0);
2396             assert(timeInfo.tm_yday == 184);
2397 
2398             version (Posix)
2399                 assert(timeInfo.tm_isdst == 1);
2400             else version (Windows)
2401                 assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
2402 
2403             version (Posix)
2404             {
2405                 assert(timeInfo.tm_gmtoff == -7 * 60 * 60);
2406                 assert(to!string(timeInfo.tm_zone) == "PDT");
2407             }
2408         }
2409     }
2410 
2411 
2412     /++
2413         Adds the given number of years or months to this $(LREF SysTime). A
2414         negative number will subtract.
2415 
2416         Note that if day overflow is allowed, and the date with the adjusted
2417         year/month overflows the number of days in the new month, then the month
2418         will be incremented by one, and the day set to the number of days
2419         overflowed. (e.g. if the day were 31 and the new month were June, then
2420         the month would be incremented to July, and the new day would be 1). If
2421         day overflow is not allowed, then the day will be set to the last valid
2422         day in the month (e.g. June 31st would become June 30th).
2423 
2424         Params:
2425             units         = The type of units to add ("years" or "months").
2426             value         = The number of months or years to add to this
2427                             $(LREF SysTime).
2428             allowOverflow = Whether the days should be allowed to overflow,
2429                             causing the month to increment.
2430       +/
2431     ref SysTime add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow
2432         if (units == "years" || units == "months")
2433     {
2434         auto hnsecs = adjTime;
2435         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
2436 
2437         if (hnsecs < 0)
2438         {
2439             hnsecs += convert!("hours", "hnsecs")(24);
2440             --days;
2441         }
2442 
2443         auto date = Date(cast(int) days);
2444         date.add!units(value, allowOverflow);
2445         days = date.dayOfGregorianCal - 1;
2446 
2447         if (days < 0)
2448         {
2449             hnsecs -= convert!("hours", "hnsecs")(24);
2450             ++days;
2451         }
2452 
2453         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
2454 
2455         adjTime = newDaysHNSecs + hnsecs;
2456 
2457         return this;
2458     }
2459 
2460     @safe unittest
2461     {
2462         auto st1 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
2463         st1.add!"months"(11);
2464         assert(st1 == SysTime(DateTime(2010, 12, 1, 12, 30, 33)));
2465 
2466         auto st2 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
2467         st2.add!"months"(-11);
2468         assert(st2 == SysTime(DateTime(2009, 2, 1, 12, 30, 33)));
2469 
2470         auto st3 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
2471         st3.add!"years"(1);
2472         assert(st3 == SysTime(DateTime(2001, 3, 1, 12, 30, 33)));
2473 
2474         auto st4 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
2475         st4.add!"years"(1, AllowDayOverflow.no);
2476         assert(st4 == SysTime(DateTime(2001, 2, 28, 12, 30, 33)));
2477     }
2478 
2479     // Test add!"years"() with AllowDayOverflow.yes
2480     @safe unittest
2481     {
2482         // Test A.D.
2483         {
2484             auto sysTime = SysTime(Date(1999, 7, 6));
2485             sysTime.add!"years"(7);
2486             assert(sysTime == SysTime(Date(2006, 7, 6)));
2487             sysTime.add!"years"(-9);
2488             assert(sysTime == SysTime(Date(1997, 7, 6)));
2489         }
2490 
2491         {
2492             auto sysTime = SysTime(Date(1999, 2, 28));
2493             sysTime.add!"years"(1);
2494             assert(sysTime == SysTime(Date(2000, 2, 28)));
2495         }
2496 
2497         {
2498             auto sysTime = SysTime(Date(2000, 2, 29));
2499             sysTime.add!"years"(-1);
2500             assert(sysTime == SysTime(Date(1999, 3, 1)));
2501         }
2502 
2503         {
2504             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234));
2505             sysTime.add!"years"(7);
2506             assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234)));
2507             sysTime.add!"years"(-9);
2508             assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234)));
2509         }
2510 
2511         {
2512             auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207));
2513             sysTime.add!"years"(1);
2514             assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207)));
2515         }
2516 
2517         {
2518             auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207));
2519             sysTime.add!"years"(-1);
2520             assert(sysTime == SysTime(DateTime(1999, 3, 1, 0, 7, 2), usecs(1207)));
2521         }
2522 
2523         // Test B.C.
2524         {
2525             auto sysTime = SysTime(Date(-1999, 7, 6));
2526             sysTime.add!"years"(-7);
2527             assert(sysTime == SysTime(Date(-2006, 7, 6)));
2528             sysTime.add!"years"(9);
2529             assert(sysTime == SysTime(Date(-1997, 7, 6)));
2530         }
2531 
2532         {
2533             auto sysTime = SysTime(Date(-1999, 2, 28));
2534             sysTime.add!"years"(-1);
2535             assert(sysTime == SysTime(Date(-2000, 2, 28)));
2536         }
2537 
2538         {
2539             auto sysTime = SysTime(Date(-2000, 2, 29));
2540             sysTime.add!"years"(1);
2541             assert(sysTime == SysTime(Date(-1999, 3, 1)));
2542         }
2543 
2544         {
2545             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234));
2546             sysTime.add!"years"(-7);
2547             assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234)));
2548             sysTime.add!"years"(9);
2549             assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234)));
2550         }
2551 
2552         {
2553             auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3));
2554             sysTime.add!"years"(-1);
2555             assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3)));
2556         }
2557 
2558         {
2559             auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3));
2560             sysTime.add!"years"(1);
2561             assert(sysTime == SysTime(DateTime(-1999, 3, 1, 3, 3, 3), hnsecs(3)));
2562         }
2563 
2564         // Test Both
2565         {
2566             auto sysTime = SysTime(Date(4, 7, 6));
2567             sysTime.add!"years"(-5);
2568             assert(sysTime == SysTime(Date(-1, 7, 6)));
2569             sysTime.add!"years"(5);
2570             assert(sysTime == SysTime(Date(4, 7, 6)));
2571         }
2572 
2573         {
2574             auto sysTime = SysTime(Date(-4, 7, 6));
2575             sysTime.add!"years"(5);
2576             assert(sysTime == SysTime(Date(1, 7, 6)));
2577             sysTime.add!"years"(-5);
2578             assert(sysTime == SysTime(Date(-4, 7, 6)));
2579         }
2580 
2581         {
2582             auto sysTime = SysTime(Date(4, 7, 6));
2583             sysTime.add!"years"(-8);
2584             assert(sysTime == SysTime(Date(-4, 7, 6)));
2585             sysTime.add!"years"(8);
2586             assert(sysTime == SysTime(Date(4, 7, 6)));
2587         }
2588 
2589         {
2590             auto sysTime = SysTime(Date(-4, 7, 6));
2591             sysTime.add!"years"(8);
2592             assert(sysTime == SysTime(Date(4, 7, 6)));
2593             sysTime.add!"years"(-8);
2594             assert(sysTime == SysTime(Date(-4, 7, 6)));
2595         }
2596 
2597         {
2598             auto sysTime = SysTime(Date(-4, 2, 29));
2599             sysTime.add!"years"(5);
2600             assert(sysTime == SysTime(Date(1, 3, 1)));
2601         }
2602 
2603         {
2604             auto sysTime = SysTime(Date(4, 2, 29));
2605             sysTime.add!"years"(-5);
2606             assert(sysTime == SysTime(Date(-1, 3, 1)));
2607         }
2608 
2609         {
2610             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
2611             sysTime.add!"years"(-1);
2612             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2613             sysTime.add!"years"(1);
2614             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2615         }
2616 
2617         {
2618             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2619             sysTime.add!"years"(-1);
2620             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2621             sysTime.add!"years"(1);
2622             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2623         }
2624 
2625         {
2626             auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0));
2627             sysTime.add!"years"(1);
2628             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2629             sysTime.add!"years"(-1);
2630             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2631         }
2632 
2633         {
2634             auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2635             sysTime.add!"years"(1);
2636             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2637             sysTime.add!"years"(-1);
2638             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2639         }
2640 
2641         {
2642             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
2643             sysTime.add!"years"(-5);
2644             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
2645             sysTime.add!"years"(5);
2646             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
2647         }
2648 
2649         {
2650             auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329));
2651             sysTime.add!"years"(5);
2652             assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329)));
2653             sysTime.add!"years"(-5);
2654             assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)));
2655         }
2656 
2657         {
2658             auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555));
2659             sysTime.add!"years"(5);
2660             assert(sysTime == SysTime(DateTime(1, 3, 1, 5, 5, 5), msecs(555)));
2661         }
2662 
2663         {
2664             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
2665             sysTime.add!"years"(-5);
2666             assert(sysTime == SysTime(DateTime(-1, 3, 1, 5, 5, 5), msecs(555)));
2667         }
2668 
2669         {
2670             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
2671             sysTime.add!"years"(-5).add!"years"(7);
2672             assert(sysTime == SysTime(DateTime(6, 3, 1, 5, 5, 5), msecs(555)));
2673         }
2674 
2675         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2676         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2677         static assert(!__traits(compiles, cst.add!"years"(4)));
2678         //static assert(!__traits(compiles, ist.add!"years"(4)));
2679     }
2680 
2681     // Test add!"years"() with AllowDayOverflow.no
2682     @safe unittest
2683     {
2684         // Test A.D.
2685         {
2686             auto sysTime = SysTime(Date(1999, 7, 6));
2687             sysTime.add!"years"(7, AllowDayOverflow.no);
2688             assert(sysTime == SysTime(Date(2006, 7, 6)));
2689             sysTime.add!"years"(-9, AllowDayOverflow.no);
2690             assert(sysTime == SysTime(Date(1997, 7, 6)));
2691         }
2692 
2693         {
2694             auto sysTime = SysTime(Date(1999, 2, 28));
2695             sysTime.add!"years"(1, AllowDayOverflow.no);
2696             assert(sysTime == SysTime(Date(2000, 2, 28)));
2697         }
2698 
2699         {
2700             auto sysTime = SysTime(Date(2000, 2, 29));
2701             sysTime.add!"years"(-1, AllowDayOverflow.no);
2702             assert(sysTime == SysTime(Date(1999, 2, 28)));
2703         }
2704 
2705         {
2706             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234));
2707             sysTime.add!"years"(7, AllowDayOverflow.no);
2708             assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234)));
2709             sysTime.add!"years"(-9, AllowDayOverflow.no);
2710             assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234)));
2711         }
2712 
2713         {
2714             auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207));
2715             sysTime.add!"years"(1, AllowDayOverflow.no);
2716             assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207)));
2717         }
2718 
2719         {
2720             auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207));
2721             sysTime.add!"years"(-1, AllowDayOverflow.no);
2722             assert(sysTime == SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207)));
2723         }
2724 
2725         // Test B.C.
2726         {
2727             auto sysTime = SysTime(Date(-1999, 7, 6));
2728             sysTime.add!"years"(-7, AllowDayOverflow.no);
2729             assert(sysTime == SysTime(Date(-2006, 7, 6)));
2730             sysTime.add!"years"(9, AllowDayOverflow.no);
2731             assert(sysTime == SysTime(Date(-1997, 7, 6)));
2732         }
2733 
2734         {
2735             auto sysTime = SysTime(Date(-1999, 2, 28));
2736             sysTime.add!"years"(-1, AllowDayOverflow.no);
2737             assert(sysTime == SysTime(Date(-2000, 2, 28)));
2738         }
2739 
2740         {
2741             auto sysTime = SysTime(Date(-2000, 2, 29));
2742             sysTime.add!"years"(1, AllowDayOverflow.no);
2743             assert(sysTime == SysTime(Date(-1999, 2, 28)));
2744         }
2745 
2746         {
2747             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234));
2748             sysTime.add!"years"(-7, AllowDayOverflow.no);
2749             assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234)));
2750             sysTime.add!"years"(9, AllowDayOverflow.no);
2751             assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234)));
2752         }
2753 
2754         {
2755             auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3));
2756             sysTime.add!"years"(-1, AllowDayOverflow.no);
2757             assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3)));
2758         }
2759 
2760         {
2761             auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3));
2762             sysTime.add!"years"(1, AllowDayOverflow.no);
2763             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3)));
2764         }
2765 
2766         // Test Both
2767         {
2768             auto sysTime = SysTime(Date(4, 7, 6));
2769             sysTime.add!"years"(-5, AllowDayOverflow.no);
2770             assert(sysTime == SysTime(Date(-1, 7, 6)));
2771             sysTime.add!"years"(5, AllowDayOverflow.no);
2772             assert(sysTime == SysTime(Date(4, 7, 6)));
2773         }
2774 
2775         {
2776             auto sysTime = SysTime(Date(-4, 7, 6));
2777             sysTime.add!"years"(5, AllowDayOverflow.no);
2778             assert(sysTime == SysTime(Date(1, 7, 6)));
2779             sysTime.add!"years"(-5, AllowDayOverflow.no);
2780             assert(sysTime == SysTime(Date(-4, 7, 6)));
2781         }
2782 
2783         {
2784             auto sysTime = SysTime(Date(4, 7, 6));
2785             sysTime.add!"years"(-8, AllowDayOverflow.no);
2786             assert(sysTime == SysTime(Date(-4, 7, 6)));
2787             sysTime.add!"years"(8, AllowDayOverflow.no);
2788             assert(sysTime == SysTime(Date(4, 7, 6)));
2789         }
2790 
2791         {
2792             auto sysTime = SysTime(Date(-4, 7, 6));
2793             sysTime.add!"years"(8, AllowDayOverflow.no);
2794             assert(sysTime == SysTime(Date(4, 7, 6)));
2795             sysTime.add!"years"(-8, AllowDayOverflow.no);
2796             assert(sysTime == SysTime(Date(-4, 7, 6)));
2797         }
2798 
2799         {
2800             auto sysTime = SysTime(Date(-4, 2, 29));
2801             sysTime.add!"years"(5, AllowDayOverflow.no);
2802             assert(sysTime == SysTime(Date(1, 2, 28)));
2803         }
2804 
2805         {
2806             auto sysTime = SysTime(Date(4, 2, 29));
2807             sysTime.add!"years"(-5, AllowDayOverflow.no);
2808             assert(sysTime == SysTime(Date(-1, 2, 28)));
2809         }
2810 
2811         {
2812             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
2813             sysTime.add!"years"(-1, AllowDayOverflow.no);
2814             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2815             sysTime.add!"years"(1, AllowDayOverflow.no);
2816             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2817         }
2818 
2819         {
2820             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2821             sysTime.add!"years"(-1, AllowDayOverflow.no);
2822             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2823             sysTime.add!"years"(1, AllowDayOverflow.no);
2824             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2825         }
2826 
2827         {
2828             auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0));
2829             sysTime.add!"years"(1, AllowDayOverflow.no);
2830             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2831             sysTime.add!"years"(-1, AllowDayOverflow.no);
2832             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2833         }
2834 
2835         {
2836             auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2837             sysTime.add!"years"(1, AllowDayOverflow.no);
2838             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2839             sysTime.add!"years"(-1, AllowDayOverflow.no);
2840             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2841         }
2842 
2843         {
2844             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
2845             sysTime.add!"years"(-5);
2846             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
2847             sysTime.add!"years"(5);
2848             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
2849         }
2850 
2851         {
2852             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
2853             sysTime.add!"years"(-5, AllowDayOverflow.no);
2854             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
2855             sysTime.add!"years"(5, AllowDayOverflow.no);
2856             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
2857         }
2858 
2859         {
2860             auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329));
2861             sysTime.add!"years"(5, AllowDayOverflow.no);
2862             assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329)));
2863             sysTime.add!"years"(-5, AllowDayOverflow.no);
2864             assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)));
2865         }
2866 
2867         {
2868             auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555));
2869             sysTime.add!"years"(5, AllowDayOverflow.no);
2870             assert(sysTime == SysTime(DateTime(1, 2, 28, 5, 5, 5), msecs(555)));
2871         }
2872 
2873         {
2874             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
2875             sysTime.add!"years"(-5, AllowDayOverflow.no);
2876             assert(sysTime == SysTime(DateTime(-1, 2, 28, 5, 5, 5), msecs(555)));
2877         }
2878 
2879         {
2880             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
2881             sysTime.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no);
2882             assert(sysTime == SysTime(DateTime(6, 2, 28, 5, 5, 5), msecs(555)));
2883         }
2884     }
2885 
2886     // Test add!"months"() with AllowDayOverflow.yes
2887     @safe unittest
2888     {
2889         // Test A.D.
2890         {
2891             auto sysTime = SysTime(Date(1999, 7, 6));
2892             sysTime.add!"months"(3);
2893             assert(sysTime == SysTime(Date(1999, 10, 6)));
2894             sysTime.add!"months"(-4);
2895             assert(sysTime == SysTime(Date(1999, 6, 6)));
2896         }
2897 
2898         {
2899             auto sysTime = SysTime(Date(1999, 7, 6));
2900             sysTime.add!"months"(6);
2901             assert(sysTime == SysTime(Date(2000, 1, 6)));
2902             sysTime.add!"months"(-6);
2903             assert(sysTime == SysTime(Date(1999, 7, 6)));
2904         }
2905 
2906         {
2907             auto sysTime = SysTime(Date(1999, 7, 6));
2908             sysTime.add!"months"(27);
2909             assert(sysTime == SysTime(Date(2001, 10, 6)));
2910             sysTime.add!"months"(-28);
2911             assert(sysTime == SysTime(Date(1999, 6, 6)));
2912         }
2913 
2914         {
2915             auto sysTime = SysTime(Date(1999, 5, 31));
2916             sysTime.add!"months"(1);
2917             assert(sysTime == SysTime(Date(1999, 7, 1)));
2918         }
2919 
2920         {
2921             auto sysTime = SysTime(Date(1999, 5, 31));
2922             sysTime.add!"months"(-1);
2923             assert(sysTime == SysTime(Date(1999, 5, 1)));
2924         }
2925 
2926         {
2927             auto sysTime = SysTime(Date(1999, 2, 28));
2928             sysTime.add!"months"(12);
2929             assert(sysTime == SysTime(Date(2000, 2, 28)));
2930         }
2931 
2932         {
2933             auto sysTime = SysTime(Date(2000, 2, 29));
2934             sysTime.add!"months"(12);
2935             assert(sysTime == SysTime(Date(2001, 3, 1)));
2936         }
2937 
2938         {
2939             auto sysTime = SysTime(Date(1999, 7, 31));
2940             sysTime.add!"months"(1);
2941             assert(sysTime == SysTime(Date(1999, 8, 31)));
2942             sysTime.add!"months"(1);
2943             assert(sysTime == SysTime(Date(1999, 10, 1)));
2944         }
2945 
2946         {
2947             auto sysTime = SysTime(Date(1998, 8, 31));
2948             sysTime.add!"months"(13);
2949             assert(sysTime == SysTime(Date(1999, 10, 1)));
2950             sysTime.add!"months"(-13);
2951             assert(sysTime == SysTime(Date(1998, 9, 1)));
2952         }
2953 
2954         {
2955             auto sysTime = SysTime(Date(1997, 12, 31));
2956             sysTime.add!"months"(13);
2957             assert(sysTime == SysTime(Date(1999, 1, 31)));
2958             sysTime.add!"months"(-13);
2959             assert(sysTime == SysTime(Date(1997, 12, 31)));
2960         }
2961 
2962         {
2963             auto sysTime = SysTime(Date(1997, 12, 31));
2964             sysTime.add!"months"(14);
2965             assert(sysTime == SysTime(Date(1999, 3, 3)));
2966             sysTime.add!"months"(-14);
2967             assert(sysTime == SysTime(Date(1998, 1, 3)));
2968         }
2969 
2970         {
2971             auto sysTime = SysTime(Date(1998, 12, 31));
2972             sysTime.add!"months"(14);
2973             assert(sysTime == SysTime(Date(2000, 3, 2)));
2974             sysTime.add!"months"(-14);
2975             assert(sysTime == SysTime(Date(1999, 1, 2)));
2976         }
2977 
2978         {
2979             auto sysTime = SysTime(Date(1999, 12, 31));
2980             sysTime.add!"months"(14);
2981             assert(sysTime == SysTime(Date(2001, 3, 3)));
2982             sysTime.add!"months"(-14);
2983             assert(sysTime == SysTime(Date(2000, 1, 3)));
2984         }
2985 
2986         {
2987             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
2988             sysTime.add!"months"(3);
2989             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
2990             sysTime.add!"months"(-4);
2991             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
2992         }
2993 
2994         {
2995             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
2996             sysTime.add!"months"(14);
2997             assert(sysTime == SysTime(DateTime(2000, 3, 2, 7, 7, 7), hnsecs(422202)));
2998             sysTime.add!"months"(-14);
2999             assert(sysTime == SysTime(DateTime(1999, 1, 2, 7, 7, 7), hnsecs(422202)));
3000         }
3001 
3002         {
3003             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
3004             sysTime.add!"months"(14);
3005             assert(sysTime == SysTime(DateTime(2001, 3, 3, 7, 7, 7), hnsecs(422202)));
3006             sysTime.add!"months"(-14);
3007             assert(sysTime == SysTime(DateTime(2000, 1, 3, 7, 7, 7), hnsecs(422202)));
3008         }
3009 
3010         // Test B.C.
3011         {
3012             auto sysTime = SysTime(Date(-1999, 7, 6));
3013             sysTime.add!"months"(3);
3014             assert(sysTime == SysTime(Date(-1999, 10, 6)));
3015             sysTime.add!"months"(-4);
3016             assert(sysTime == SysTime(Date(-1999, 6, 6)));
3017         }
3018 
3019         {
3020             auto sysTime = SysTime(Date(-1999, 7, 6));
3021             sysTime.add!"months"(6);
3022             assert(sysTime == SysTime(Date(-1998, 1, 6)));
3023             sysTime.add!"months"(-6);
3024             assert(sysTime == SysTime(Date(-1999, 7, 6)));
3025         }
3026 
3027         {
3028             auto sysTime = SysTime(Date(-1999, 7, 6));
3029             sysTime.add!"months"(-27);
3030             assert(sysTime == SysTime(Date(-2001, 4, 6)));
3031             sysTime.add!"months"(28);
3032             assert(sysTime == SysTime(Date(-1999, 8, 6)));
3033         }
3034 
3035         {
3036             auto sysTime = SysTime(Date(-1999, 5, 31));
3037             sysTime.add!"months"(1);
3038             assert(sysTime == SysTime(Date(-1999, 7, 1)));
3039         }
3040 
3041         {
3042             auto sysTime = SysTime(Date(-1999, 5, 31));
3043             sysTime.add!"months"(-1);
3044             assert(sysTime == SysTime(Date(-1999, 5, 1)));
3045         }
3046 
3047         {
3048             auto sysTime = SysTime(Date(-1999, 2, 28));
3049             sysTime.add!"months"(-12);
3050             assert(sysTime == SysTime(Date(-2000, 2, 28)));
3051         }
3052 
3053         {
3054             auto sysTime = SysTime(Date(-2000, 2, 29));
3055             sysTime.add!"months"(-12);
3056             assert(sysTime == SysTime(Date(-2001, 3, 1)));
3057         }
3058 
3059         {
3060             auto sysTime = SysTime(Date(-1999, 7, 31));
3061             sysTime.add!"months"(1);
3062             assert(sysTime == SysTime(Date(-1999, 8, 31)));
3063             sysTime.add!"months"(1);
3064             assert(sysTime == SysTime(Date(-1999, 10, 1)));
3065         }
3066 
3067         {
3068             auto sysTime = SysTime(Date(-1998, 8, 31));
3069             sysTime.add!"months"(13);
3070             assert(sysTime == SysTime(Date(-1997, 10, 1)));
3071             sysTime.add!"months"(-13);
3072             assert(sysTime == SysTime(Date(-1998, 9, 1)));
3073         }
3074 
3075         {
3076             auto sysTime = SysTime(Date(-1997, 12, 31));
3077             sysTime.add!"months"(13);
3078             assert(sysTime == SysTime(Date(-1995, 1, 31)));
3079             sysTime.add!"months"(-13);
3080             assert(sysTime == SysTime(Date(-1997, 12, 31)));
3081         }
3082 
3083         {
3084             auto sysTime = SysTime(Date(-1997, 12, 31));
3085             sysTime.add!"months"(14);
3086             assert(sysTime == SysTime(Date(-1995, 3, 3)));
3087             sysTime.add!"months"(-14);
3088             assert(sysTime == SysTime(Date(-1996, 1, 3)));
3089         }
3090 
3091         {
3092             auto sysTime = SysTime(Date(-2002, 12, 31));
3093             sysTime.add!"months"(14);
3094             assert(sysTime == SysTime(Date(-2000, 3, 2)));
3095             sysTime.add!"months"(-14);
3096             assert(sysTime == SysTime(Date(-2001, 1, 2)));
3097         }
3098 
3099         {
3100             auto sysTime = SysTime(Date(-2001, 12, 31));
3101             sysTime.add!"months"(14);
3102             assert(sysTime == SysTime(Date(-1999, 3, 3)));
3103             sysTime.add!"months"(-14);
3104             assert(sysTime == SysTime(Date(-2000, 1, 3)));
3105         }
3106 
3107         {
3108             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
3109             sysTime.add!"months"(3);
3110             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
3111             sysTime.add!"months"(-4);
3112             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
3113         }
3114 
3115         {
3116             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
3117             sysTime.add!"months"(14);
3118             assert(sysTime == SysTime(DateTime(-2000, 3, 2, 7, 7, 7), hnsecs(422202)));
3119             sysTime.add!"months"(-14);
3120             assert(sysTime == SysTime(DateTime(-2001, 1, 2, 7, 7, 7), hnsecs(422202)));
3121         }
3122 
3123         {
3124             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
3125             sysTime.add!"months"(14);
3126             assert(sysTime == SysTime(DateTime(-1999, 3, 3, 7, 7, 7), hnsecs(422202)));
3127             sysTime.add!"months"(-14);
3128             assert(sysTime == SysTime(DateTime(-2000, 1, 3, 7, 7, 7), hnsecs(422202)));
3129         }
3130 
3131         // Test Both
3132         {
3133             auto sysTime = SysTime(Date(1, 1, 1));
3134             sysTime.add!"months"(-1);
3135             assert(sysTime == SysTime(Date(0, 12, 1)));
3136             sysTime.add!"months"(1);
3137             assert(sysTime == SysTime(Date(1, 1, 1)));
3138         }
3139 
3140         {
3141             auto sysTime = SysTime(Date(4, 1, 1));
3142             sysTime.add!"months"(-48);
3143             assert(sysTime == SysTime(Date(0, 1, 1)));
3144             sysTime.add!"months"(48);
3145             assert(sysTime == SysTime(Date(4, 1, 1)));
3146         }
3147 
3148         {
3149             auto sysTime = SysTime(Date(4, 3, 31));
3150             sysTime.add!"months"(-49);
3151             assert(sysTime == SysTime(Date(0, 3, 2)));
3152             sysTime.add!"months"(49);
3153             assert(sysTime == SysTime(Date(4, 4, 2)));
3154         }
3155 
3156         {
3157             auto sysTime = SysTime(Date(4, 3, 31));
3158             sysTime.add!"months"(-85);
3159             assert(sysTime == SysTime(Date(-3, 3, 3)));
3160             sysTime.add!"months"(85);
3161             assert(sysTime == SysTime(Date(4, 4, 3)));
3162         }
3163 
3164         {
3165             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3166             sysTime.add!"months"(-1);
3167             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3168             sysTime.add!"months"(1);
3169             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3170         }
3171 
3172         {
3173             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3174             sysTime.add!"months"(-1);
3175             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3176             sysTime.add!"months"(1);
3177             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3178         }
3179 
3180         {
3181             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
3182             sysTime.add!"months"(1);
3183             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3184             sysTime.add!"months"(-1);
3185             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3186         }
3187 
3188         {
3189             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
3190             sysTime.add!"months"(1);
3191             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3192             sysTime.add!"months"(-1);
3193             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3194         }
3195 
3196         {
3197             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
3198             sysTime.add!"months"(-1);
3199             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17)));
3200             sysTime.add!"months"(1);
3201             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
3202         }
3203 
3204         {
3205             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
3206             sysTime.add!"months"(-85);
3207             assert(sysTime == SysTime(DateTime(-3, 3, 3, 12, 11, 10), msecs(9)));
3208             sysTime.add!"months"(85);
3209             assert(sysTime == SysTime(DateTime(4, 4, 3, 12, 11, 10), msecs(9)));
3210         }
3211 
3212         {
3213             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3214             sysTime.add!"months"(85);
3215             assert(sysTime == SysTime(DateTime(4, 5, 1, 12, 11, 10), msecs(9)));
3216             sysTime.add!"months"(-85);
3217             assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9)));
3218         }
3219 
3220         {
3221             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3222             sysTime.add!"months"(85).add!"months"(-83);
3223             assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), msecs(9)));
3224         }
3225 
3226         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3227         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3228         static assert(!__traits(compiles, cst.add!"months"(4)));
3229         //static assert(!__traits(compiles, ist.add!"months"(4)));
3230     }
3231 
3232     // Test add!"months"() with AllowDayOverflow.no
3233     @safe unittest
3234     {
3235         // Test A.D.
3236         {
3237             auto sysTime = SysTime(Date(1999, 7, 6));
3238             sysTime.add!"months"(3, AllowDayOverflow.no);
3239             assert(sysTime == SysTime(Date(1999, 10, 6)));
3240             sysTime.add!"months"(-4, AllowDayOverflow.no);
3241             assert(sysTime == SysTime(Date(1999, 6, 6)));
3242         }
3243 
3244         {
3245             auto sysTime = SysTime(Date(1999, 7, 6));
3246             sysTime.add!"months"(6, AllowDayOverflow.no);
3247             assert(sysTime == SysTime(Date(2000, 1, 6)));
3248             sysTime.add!"months"(-6, AllowDayOverflow.no);
3249             assert(sysTime == SysTime(Date(1999, 7, 6)));
3250         }
3251 
3252         {
3253             auto sysTime = SysTime(Date(1999, 7, 6));
3254             sysTime.add!"months"(27, AllowDayOverflow.no);
3255             assert(sysTime == SysTime(Date(2001, 10, 6)));
3256             sysTime.add!"months"(-28, AllowDayOverflow.no);
3257             assert(sysTime == SysTime(Date(1999, 6, 6)));
3258         }
3259 
3260         {
3261             auto sysTime = SysTime(Date(1999, 5, 31));
3262             sysTime.add!"months"(1, AllowDayOverflow.no);
3263             assert(sysTime == SysTime(Date(1999, 6, 30)));
3264         }
3265 
3266         {
3267             auto sysTime = SysTime(Date(1999, 5, 31));
3268             sysTime.add!"months"(-1, AllowDayOverflow.no);
3269             assert(sysTime == SysTime(Date(1999, 4, 30)));
3270         }
3271 
3272         {
3273             auto sysTime = SysTime(Date(1999, 2, 28));
3274             sysTime.add!"months"(12, AllowDayOverflow.no);
3275             assert(sysTime == SysTime(Date(2000, 2, 28)));
3276         }
3277 
3278         {
3279             auto sysTime = SysTime(Date(2000, 2, 29));
3280             sysTime.add!"months"(12, AllowDayOverflow.no);
3281             assert(sysTime == SysTime(Date(2001, 2, 28)));
3282         }
3283 
3284         {
3285             auto sysTime = SysTime(Date(1999, 7, 31));
3286             sysTime.add!"months"(1, AllowDayOverflow.no);
3287             assert(sysTime == SysTime(Date(1999, 8, 31)));
3288             sysTime.add!"months"(1, AllowDayOverflow.no);
3289             assert(sysTime == SysTime(Date(1999, 9, 30)));
3290         }
3291 
3292         {
3293             auto sysTime = SysTime(Date(1998, 8, 31));
3294             sysTime.add!"months"(13, AllowDayOverflow.no);
3295             assert(sysTime == SysTime(Date(1999, 9, 30)));
3296             sysTime.add!"months"(-13, AllowDayOverflow.no);
3297             assert(sysTime == SysTime(Date(1998, 8, 30)));
3298         }
3299 
3300         {
3301             auto sysTime = SysTime(Date(1997, 12, 31));
3302             sysTime.add!"months"(13, AllowDayOverflow.no);
3303             assert(sysTime == SysTime(Date(1999, 1, 31)));
3304             sysTime.add!"months"(-13, AllowDayOverflow.no);
3305             assert(sysTime == SysTime(Date(1997, 12, 31)));
3306         }
3307 
3308         {
3309             auto sysTime = SysTime(Date(1997, 12, 31));
3310             sysTime.add!"months"(14, AllowDayOverflow.no);
3311             assert(sysTime == SysTime(Date(1999, 2, 28)));
3312             sysTime.add!"months"(-14, AllowDayOverflow.no);
3313             assert(sysTime == SysTime(Date(1997, 12, 28)));
3314         }
3315 
3316         {
3317             auto sysTime = SysTime(Date(1998, 12, 31));
3318             sysTime.add!"months"(14, AllowDayOverflow.no);
3319             assert(sysTime == SysTime(Date(2000, 2, 29)));
3320             sysTime.add!"months"(-14, AllowDayOverflow.no);
3321             assert(sysTime == SysTime(Date(1998, 12, 29)));
3322         }
3323 
3324         {
3325             auto sysTime = SysTime(Date(1999, 12, 31));
3326             sysTime.add!"months"(14, AllowDayOverflow.no);
3327             assert(sysTime == SysTime(Date(2001, 2, 28)));
3328             sysTime.add!"months"(-14, AllowDayOverflow.no);
3329             assert(sysTime == SysTime(Date(1999, 12, 28)));
3330         }
3331 
3332         {
3333             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
3334             sysTime.add!"months"(3, AllowDayOverflow.no);
3335             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
3336             sysTime.add!"months"(-4, AllowDayOverflow.no);
3337             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
3338         }
3339 
3340         {
3341             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
3342             sysTime.add!"months"(14, AllowDayOverflow.no);
3343             assert(sysTime == SysTime(DateTime(2000, 2, 29, 7, 7, 7), hnsecs(422202)));
3344             sysTime.add!"months"(-14, AllowDayOverflow.no);
3345             assert(sysTime == SysTime(DateTime(1998, 12, 29, 7, 7, 7), hnsecs(422202)));
3346         }
3347 
3348         {
3349             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
3350             sysTime.add!"months"(14, AllowDayOverflow.no);
3351             assert(sysTime == SysTime(DateTime(2001, 2, 28, 7, 7, 7), hnsecs(422202)));
3352             sysTime.add!"months"(-14, AllowDayOverflow.no);
3353             assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202)));
3354         }
3355 
3356         // Test B.C.
3357         {
3358             auto sysTime = SysTime(Date(-1999, 7, 6));
3359             sysTime.add!"months"(3, AllowDayOverflow.no);
3360             assert(sysTime == SysTime(Date(-1999, 10, 6)));
3361             sysTime.add!"months"(-4, AllowDayOverflow.no);
3362             assert(sysTime == SysTime(Date(-1999, 6, 6)));
3363         }
3364 
3365         {
3366             auto sysTime = SysTime(Date(-1999, 7, 6));
3367             sysTime.add!"months"(6, AllowDayOverflow.no);
3368             assert(sysTime == SysTime(Date(-1998, 1, 6)));
3369             sysTime.add!"months"(-6, AllowDayOverflow.no);
3370             assert(sysTime == SysTime(Date(-1999, 7, 6)));
3371         }
3372 
3373         {
3374             auto sysTime = SysTime(Date(-1999, 7, 6));
3375             sysTime.add!"months"(-27, AllowDayOverflow.no);
3376             assert(sysTime == SysTime(Date(-2001, 4, 6)));
3377             sysTime.add!"months"(28, AllowDayOverflow.no);
3378             assert(sysTime == SysTime(Date(-1999, 8, 6)));
3379         }
3380 
3381         {
3382             auto sysTime = SysTime(Date(-1999, 5, 31));
3383             sysTime.add!"months"(1, AllowDayOverflow.no);
3384             assert(sysTime == SysTime(Date(-1999, 6, 30)));
3385         }
3386 
3387         {
3388             auto sysTime = SysTime(Date(-1999, 5, 31));
3389             sysTime.add!"months"(-1, AllowDayOverflow.no);
3390             assert(sysTime == SysTime(Date(-1999, 4, 30)));
3391         }
3392 
3393         {
3394             auto sysTime = SysTime(Date(-1999, 2, 28));
3395             sysTime.add!"months"(-12, AllowDayOverflow.no);
3396             assert(sysTime == SysTime(Date(-2000, 2, 28)));
3397         }
3398 
3399         {
3400             auto sysTime = SysTime(Date(-2000, 2, 29));
3401             sysTime.add!"months"(-12, AllowDayOverflow.no);
3402             assert(sysTime == SysTime(Date(-2001, 2, 28)));
3403         }
3404 
3405         {
3406             auto sysTime = SysTime(Date(-1999, 7, 31));
3407             sysTime.add!"months"(1, AllowDayOverflow.no);
3408             assert(sysTime == SysTime(Date(-1999, 8, 31)));
3409             sysTime.add!"months"(1, AllowDayOverflow.no);
3410             assert(sysTime == SysTime(Date(-1999, 9, 30)));
3411         }
3412 
3413         {
3414             auto sysTime = SysTime(Date(-1998, 8, 31));
3415             sysTime.add!"months"(13, AllowDayOverflow.no);
3416             assert(sysTime == SysTime(Date(-1997, 9, 30)));
3417             sysTime.add!"months"(-13, AllowDayOverflow.no);
3418             assert(sysTime == SysTime(Date(-1998, 8, 30)));
3419         }
3420 
3421         {
3422             auto sysTime = SysTime(Date(-1997, 12, 31));
3423             sysTime.add!"months"(13, AllowDayOverflow.no);
3424             assert(sysTime == SysTime(Date(-1995, 1, 31)));
3425             sysTime.add!"months"(-13, AllowDayOverflow.no);
3426             assert(sysTime == SysTime(Date(-1997, 12, 31)));
3427         }
3428 
3429         {
3430             auto sysTime = SysTime(Date(-1997, 12, 31));
3431             sysTime.add!"months"(14, AllowDayOverflow.no);
3432             assert(sysTime == SysTime(Date(-1995, 2, 28)));
3433             sysTime.add!"months"(-14, AllowDayOverflow.no);
3434             assert(sysTime == SysTime(Date(-1997, 12, 28)));
3435         }
3436 
3437         {
3438             auto sysTime = SysTime(Date(-2002, 12, 31));
3439             sysTime.add!"months"(14, AllowDayOverflow.no);
3440             assert(sysTime == SysTime(Date(-2000, 2, 29)));
3441             sysTime.add!"months"(-14, AllowDayOverflow.no);
3442             assert(sysTime == SysTime(Date(-2002, 12, 29)));
3443         }
3444 
3445         {
3446             auto sysTime = SysTime(Date(-2001, 12, 31));
3447             sysTime.add!"months"(14, AllowDayOverflow.no);
3448             assert(sysTime == SysTime(Date(-1999, 2, 28)));
3449             sysTime.add!"months"(-14, AllowDayOverflow.no);
3450             assert(sysTime == SysTime(Date(-2001, 12, 28)));
3451         }
3452 
3453         {
3454             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
3455             sysTime.add!"months"(3, AllowDayOverflow.no);
3456             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
3457             sysTime.add!"months"(-4, AllowDayOverflow.no);
3458             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
3459         }
3460 
3461         {
3462             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
3463             sysTime.add!"months"(14, AllowDayOverflow.no);
3464             assert(sysTime == SysTime(DateTime(-2000, 2, 29, 7, 7, 7), hnsecs(422202)));
3465             sysTime.add!"months"(-14, AllowDayOverflow.no);
3466             assert(sysTime == SysTime(DateTime(-2002, 12, 29, 7, 7, 7), hnsecs(422202)));
3467         }
3468 
3469         {
3470             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
3471             sysTime.add!"months"(14, AllowDayOverflow.no);
3472             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 7, 7), hnsecs(422202)));
3473             sysTime.add!"months"(-14, AllowDayOverflow.no);
3474             assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202)));
3475         }
3476 
3477         // Test Both
3478         {
3479             auto sysTime = SysTime(Date(1, 1, 1));
3480             sysTime.add!"months"(-1, AllowDayOverflow.no);
3481             assert(sysTime == SysTime(Date(0, 12, 1)));
3482             sysTime.add!"months"(1, AllowDayOverflow.no);
3483             assert(sysTime == SysTime(Date(1, 1, 1)));
3484         }
3485 
3486         {
3487             auto sysTime = SysTime(Date(4, 1, 1));
3488             sysTime.add!"months"(-48, AllowDayOverflow.no);
3489             assert(sysTime == SysTime(Date(0, 1, 1)));
3490             sysTime.add!"months"(48, AllowDayOverflow.no);
3491             assert(sysTime == SysTime(Date(4, 1, 1)));
3492         }
3493 
3494         {
3495             auto sysTime = SysTime(Date(4, 3, 31));
3496             sysTime.add!"months"(-49, AllowDayOverflow.no);
3497             assert(sysTime == SysTime(Date(0, 2, 29)));
3498             sysTime.add!"months"(49, AllowDayOverflow.no);
3499             assert(sysTime == SysTime(Date(4, 3, 29)));
3500         }
3501 
3502         {
3503             auto sysTime = SysTime(Date(4, 3, 31));
3504             sysTime.add!"months"(-85, AllowDayOverflow.no);
3505             assert(sysTime == SysTime(Date(-3, 2, 28)));
3506             sysTime.add!"months"(85, AllowDayOverflow.no);
3507             assert(sysTime == SysTime(Date(4, 3, 28)));
3508         }
3509 
3510         {
3511             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3512             sysTime.add!"months"(-1, AllowDayOverflow.no);
3513             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3514             sysTime.add!"months"(1, AllowDayOverflow.no);
3515             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3516         }
3517 
3518         {
3519             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3520             sysTime.add!"months"(-1, AllowDayOverflow.no);
3521             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3522             sysTime.add!"months"(1, AllowDayOverflow.no);
3523             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3524         }
3525 
3526         {
3527             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
3528             sysTime.add!"months"(1, AllowDayOverflow.no);
3529             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3530             sysTime.add!"months"(-1, AllowDayOverflow.no);
3531             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3532         }
3533 
3534         {
3535             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
3536             sysTime.add!"months"(1, AllowDayOverflow.no);
3537             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3538             sysTime.add!"months"(-1, AllowDayOverflow.no);
3539             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3540         }
3541 
3542         {
3543             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
3544             sysTime.add!"months"(-1, AllowDayOverflow.no);
3545             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17)));
3546             sysTime.add!"months"(1, AllowDayOverflow.no);
3547             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
3548         }
3549 
3550         {
3551             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
3552             sysTime.add!"months"(-85, AllowDayOverflow.no);
3553             assert(sysTime == SysTime(DateTime(-3, 2, 28, 12, 11, 10), msecs(9)));
3554             sysTime.add!"months"(85, AllowDayOverflow.no);
3555             assert(sysTime == SysTime(DateTime(4, 3, 28, 12, 11, 10), msecs(9)));
3556         }
3557 
3558         {
3559             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3560             sysTime.add!"months"(85, AllowDayOverflow.no);
3561             assert(sysTime == SysTime(DateTime(4, 4, 30, 12, 11, 10), msecs(9)));
3562             sysTime.add!"months"(-85, AllowDayOverflow.no);
3563             assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9)));
3564         }
3565 
3566         {
3567             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3568             sysTime.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no);
3569             assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9)));
3570         }
3571     }
3572 
3573 
3574     /++
3575         Adds the given number of years or months to this $(LREF SysTime). A
3576         negative number will subtract.
3577 
3578         The difference between rolling and adding is that rolling does not
3579         affect larger units. Rolling a $(LREF SysTime) 12 months
3580         gets the exact same $(LREF SysTime). However, the days can still be
3581         affected due to the differing number of days in each month.
3582 
3583         Because there are no units larger than years, there is no difference
3584         between adding and rolling years.
3585 
3586         Params:
3587             units         = The type of units to add ("years" or "months").
3588             value         = The number of months or years to add to this
3589                             $(LREF SysTime).
3590             allowOverflow = Whether the days should be allowed to overflow,
3591                             causing the month to increment.
3592       +/
3593     ref SysTime roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow
3594         if (units == "years")
3595     {
3596         return add!"years"(value, allowOverflow);
3597     }
3598 
3599     ///
3600     @safe unittest
3601     {
3602         import std.datetime.date : AllowDayOverflow, DateTime;
3603 
3604         auto st1 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
3605         st1.roll!"months"(1);
3606         assert(st1 == SysTime(DateTime(2010, 2, 1, 12, 33, 33)));
3607 
3608         auto st2 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
3609         st2.roll!"months"(-1);
3610         assert(st2 == SysTime(DateTime(2010, 12, 1, 12, 33, 33)));
3611 
3612         auto st3 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
3613         st3.roll!"months"(1);
3614         assert(st3 == SysTime(DateTime(1999, 3, 1, 12, 33, 33)));
3615 
3616         auto st4 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
3617         st4.roll!"months"(1, AllowDayOverflow.no);
3618         assert(st4 == SysTime(DateTime(1999, 2, 28, 12, 33, 33)));
3619 
3620         auto st5 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
3621         st5.roll!"years"(1);
3622         assert(st5 == SysTime(DateTime(2001, 3, 1, 12, 30, 33)));
3623 
3624         auto st6 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
3625         st6.roll!"years"(1, AllowDayOverflow.no);
3626         assert(st6 == SysTime(DateTime(2001, 2, 28, 12, 30, 33)));
3627     }
3628 
3629     @safe unittest
3630     {
3631         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3632         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3633         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3634         st.roll!"years"(4);
3635         static assert(!__traits(compiles, cst.roll!"years"(4)));
3636         //static assert(!__traits(compiles, ist.roll!"years"(4)));
3637     }
3638 
3639 
3640     // Shares documentation with "years" overload.
3641     ref SysTime roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow
3642         if (units == "months")
3643     {
3644         auto hnsecs = adjTime;
3645         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
3646 
3647         if (hnsecs < 0)
3648         {
3649             hnsecs += convert!("hours", "hnsecs")(24);
3650             --days;
3651         }
3652 
3653         auto date = Date(cast(int) days);
3654         date.roll!"months"(value, allowOverflow);
3655         days = date.dayOfGregorianCal - 1;
3656 
3657         if (days < 0)
3658         {
3659             hnsecs -= convert!("hours", "hnsecs")(24);
3660             ++days;
3661         }
3662 
3663         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
3664         adjTime = newDaysHNSecs + hnsecs;
3665         return this;
3666     }
3667 
3668     // Test roll!"months"() with AllowDayOverflow.yes
3669     @safe unittest
3670     {
3671         // Test A.D.
3672         {
3673             auto sysTime = SysTime(Date(1999, 7, 6));
3674             sysTime.roll!"months"(3);
3675             assert(sysTime == SysTime(Date(1999, 10, 6)));
3676             sysTime.roll!"months"(-4);
3677             assert(sysTime == SysTime(Date(1999, 6, 6)));
3678         }
3679 
3680         {
3681             auto sysTime = SysTime(Date(1999, 7, 6));
3682             sysTime.roll!"months"(6);
3683             assert(sysTime == SysTime(Date(1999, 1, 6)));
3684             sysTime.roll!"months"(-6);
3685             assert(sysTime == SysTime(Date(1999, 7, 6)));
3686         }
3687 
3688         {
3689             auto sysTime = SysTime(Date(1999, 7, 6));
3690             sysTime.roll!"months"(27);
3691             assert(sysTime == SysTime(Date(1999, 10, 6)));
3692             sysTime.roll!"months"(-28);
3693             assert(sysTime == SysTime(Date(1999, 6, 6)));
3694         }
3695 
3696         {
3697             auto sysTime = SysTime(Date(1999, 5, 31));
3698             sysTime.roll!"months"(1);
3699             assert(sysTime == SysTime(Date(1999, 7, 1)));
3700         }
3701 
3702         {
3703             auto sysTime = SysTime(Date(1999, 5, 31));
3704             sysTime.roll!"months"(-1);
3705             assert(sysTime == SysTime(Date(1999, 5, 1)));
3706         }
3707 
3708         {
3709             auto sysTime = SysTime(Date(1999, 2, 28));
3710             sysTime.roll!"months"(12);
3711             assert(sysTime == SysTime(Date(1999, 2, 28)));
3712         }
3713 
3714         {
3715             auto sysTime = SysTime(Date(2000, 2, 29));
3716             sysTime.roll!"months"(12);
3717             assert(sysTime == SysTime(Date(2000, 2, 29)));
3718         }
3719 
3720         {
3721             auto sysTime = SysTime(Date(1999, 7, 31));
3722             sysTime.roll!"months"(1);
3723             assert(sysTime == SysTime(Date(1999, 8, 31)));
3724             sysTime.roll!"months"(1);
3725             assert(sysTime == SysTime(Date(1999, 10, 1)));
3726         }
3727 
3728         {
3729             auto sysTime = SysTime(Date(1998, 8, 31));
3730             sysTime.roll!"months"(13);
3731             assert(sysTime == SysTime(Date(1998, 10, 1)));
3732             sysTime.roll!"months"(-13);
3733             assert(sysTime == SysTime(Date(1998, 9, 1)));
3734         }
3735 
3736         {
3737             auto sysTime = SysTime(Date(1997, 12, 31));
3738             sysTime.roll!"months"(13);
3739             assert(sysTime == SysTime(Date(1997, 1, 31)));
3740             sysTime.roll!"months"(-13);
3741             assert(sysTime == SysTime(Date(1997, 12, 31)));
3742         }
3743 
3744         {
3745             auto sysTime = SysTime(Date(1997, 12, 31));
3746             sysTime.roll!"months"(14);
3747             assert(sysTime == SysTime(Date(1997, 3, 3)));
3748             sysTime.roll!"months"(-14);
3749             assert(sysTime == SysTime(Date(1997, 1, 3)));
3750         }
3751 
3752         {
3753             auto sysTime = SysTime(Date(1998, 12, 31));
3754             sysTime.roll!"months"(14);
3755             assert(sysTime == SysTime(Date(1998, 3, 3)));
3756             sysTime.roll!"months"(-14);
3757             assert(sysTime == SysTime(Date(1998, 1, 3)));
3758         }
3759 
3760         {
3761             auto sysTime = SysTime(Date(1999, 12, 31));
3762             sysTime.roll!"months"(14);
3763             assert(sysTime == SysTime(Date(1999, 3, 3)));
3764             sysTime.roll!"months"(-14);
3765             assert(sysTime == SysTime(Date(1999, 1, 3)));
3766         }
3767 
3768         {
3769             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
3770             sysTime.roll!"months"(3);
3771             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
3772             sysTime.roll!"months"(-4);
3773             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
3774         }
3775 
3776         {
3777             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
3778             sysTime.roll!"months"(14);
3779             assert(sysTime == SysTime(DateTime(1998, 3, 3, 7, 7, 7), hnsecs(422202)));
3780             sysTime.roll!"months"(-14);
3781             assert(sysTime == SysTime(DateTime(1998, 1, 3, 7, 7, 7), hnsecs(422202)));
3782         }
3783 
3784         {
3785             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
3786             sysTime.roll!"months"(14);
3787             assert(sysTime == SysTime(DateTime(1999, 3, 3, 7, 7, 7), hnsecs(422202)));
3788             sysTime.roll!"months"(-14);
3789             assert(sysTime == SysTime(DateTime(1999, 1, 3, 7, 7, 7), hnsecs(422202)));
3790         }
3791 
3792         // Test B.C.
3793         {
3794             auto sysTime = SysTime(Date(-1999, 7, 6));
3795             sysTime.roll!"months"(3);
3796             assert(sysTime == SysTime(Date(-1999, 10, 6)));
3797             sysTime.roll!"months"(-4);
3798             assert(sysTime == SysTime(Date(-1999, 6, 6)));
3799         }
3800 
3801         {
3802             auto sysTime = SysTime(Date(-1999, 7, 6));
3803             sysTime.roll!"months"(6);
3804             assert(sysTime == SysTime(Date(-1999, 1, 6)));
3805             sysTime.roll!"months"(-6);
3806             assert(sysTime == SysTime(Date(-1999, 7, 6)));
3807         }
3808 
3809         {
3810             auto sysTime = SysTime(Date(-1999, 7, 6));
3811             sysTime.roll!"months"(-27);
3812             assert(sysTime == SysTime(Date(-1999, 4, 6)));
3813             sysTime.roll!"months"(28);
3814             assert(sysTime == SysTime(Date(-1999, 8, 6)));
3815         }
3816 
3817         {
3818             auto sysTime = SysTime(Date(-1999, 5, 31));
3819             sysTime.roll!"months"(1);
3820             assert(sysTime == SysTime(Date(-1999, 7, 1)));
3821         }
3822 
3823         {
3824             auto sysTime = SysTime(Date(-1999, 5, 31));
3825             sysTime.roll!"months"(-1);
3826             assert(sysTime == SysTime(Date(-1999, 5, 1)));
3827         }
3828 
3829         {
3830             auto sysTime = SysTime(Date(-1999, 2, 28));
3831             sysTime.roll!"months"(-12);
3832             assert(sysTime == SysTime(Date(-1999, 2, 28)));
3833         }
3834 
3835         {
3836             auto sysTime = SysTime(Date(-2000, 2, 29));
3837             sysTime.roll!"months"(-12);
3838             assert(sysTime == SysTime(Date(-2000, 2, 29)));
3839         }
3840 
3841         {
3842             auto sysTime = SysTime(Date(-1999, 7, 31));
3843             sysTime.roll!"months"(1);
3844             assert(sysTime == SysTime(Date(-1999, 8, 31)));
3845             sysTime.roll!"months"(1);
3846             assert(sysTime == SysTime(Date(-1999, 10, 1)));
3847         }
3848 
3849         {
3850             auto sysTime = SysTime(Date(-1998, 8, 31));
3851             sysTime.roll!"months"(13);
3852             assert(sysTime == SysTime(Date(-1998, 10, 1)));
3853             sysTime.roll!"months"(-13);
3854             assert(sysTime == SysTime(Date(-1998, 9, 1)));
3855         }
3856 
3857         {
3858             auto sysTime = SysTime(Date(-1997, 12, 31));
3859             sysTime.roll!"months"(13);
3860             assert(sysTime == SysTime(Date(-1997, 1, 31)));
3861             sysTime.roll!"months"(-13);
3862             assert(sysTime == SysTime(Date(-1997, 12, 31)));
3863         }
3864 
3865         {
3866             auto sysTime = SysTime(Date(-1997, 12, 31));
3867             sysTime.roll!"months"(14);
3868             assert(sysTime == SysTime(Date(-1997, 3, 3)));
3869             sysTime.roll!"months"(-14);
3870             assert(sysTime == SysTime(Date(-1997, 1, 3)));
3871         }
3872 
3873         {
3874             auto sysTime = SysTime(Date(-2002, 12, 31));
3875             sysTime.roll!"months"(14);
3876             assert(sysTime == SysTime(Date(-2002, 3, 3)));
3877             sysTime.roll!"months"(-14);
3878             assert(sysTime == SysTime(Date(-2002, 1, 3)));
3879         }
3880 
3881         {
3882             auto sysTime = SysTime(Date(-2001, 12, 31));
3883             sysTime.roll!"months"(14);
3884             assert(sysTime == SysTime(Date(-2001, 3, 3)));
3885             sysTime.roll!"months"(-14);
3886             assert(sysTime == SysTime(Date(-2001, 1, 3)));
3887         }
3888 
3889         {
3890             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3891             sysTime.roll!"months"(-1);
3892             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0)));
3893             sysTime.roll!"months"(1);
3894             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3895         }
3896 
3897         {
3898             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3899             sysTime.roll!"months"(-1);
3900             assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3901             sysTime.roll!"months"(1);
3902             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3903         }
3904 
3905         {
3906             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
3907             sysTime.roll!"months"(1);
3908             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
3909             sysTime.roll!"months"(-1);
3910             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3911         }
3912 
3913         {
3914             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
3915             sysTime.roll!"months"(1);
3916             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3917             sysTime.roll!"months"(-1);
3918             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3919         }
3920 
3921         {
3922             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), hnsecs(5007));
3923             sysTime.roll!"months"(3);
3924             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), hnsecs(5007)));
3925             sysTime.roll!"months"(-4);
3926             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), hnsecs(5007)));
3927         }
3928 
3929         {
3930             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
3931             sysTime.roll!"months"(14);
3932             assert(sysTime == SysTime(DateTime(-2002, 3, 3, 7, 7, 7), hnsecs(422202)));
3933             sysTime.roll!"months"(-14);
3934             assert(sysTime == SysTime(DateTime(-2002, 1, 3, 7, 7, 7), hnsecs(422202)));
3935         }
3936 
3937         {
3938             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
3939             sysTime.roll!"months"(14);
3940             assert(sysTime == SysTime(DateTime(-2001, 3, 3, 7, 7, 7), hnsecs(422202)));
3941             sysTime.roll!"months"(-14);
3942             assert(sysTime == SysTime(DateTime(-2001, 1, 3, 7, 7, 7), hnsecs(422202)));
3943         }
3944 
3945         // Test Both
3946         {
3947             auto sysTime = SysTime(Date(1, 1, 1));
3948             sysTime.roll!"months"(-1);
3949             assert(sysTime == SysTime(Date(1, 12, 1)));
3950             sysTime.roll!"months"(1);
3951             assert(sysTime == SysTime(Date(1, 1, 1)));
3952         }
3953 
3954         {
3955             auto sysTime = SysTime(Date(4, 1, 1));
3956             sysTime.roll!"months"(-48);
3957             assert(sysTime == SysTime(Date(4, 1, 1)));
3958             sysTime.roll!"months"(48);
3959             assert(sysTime == SysTime(Date(4, 1, 1)));
3960         }
3961 
3962         {
3963             auto sysTime = SysTime(Date(4, 3, 31));
3964             sysTime.roll!"months"(-49);
3965             assert(sysTime == SysTime(Date(4, 3, 2)));
3966             sysTime.roll!"months"(49);
3967             assert(sysTime == SysTime(Date(4, 4, 2)));
3968         }
3969 
3970         {
3971             auto sysTime = SysTime(Date(4, 3, 31));
3972             sysTime.roll!"months"(-85);
3973             assert(sysTime == SysTime(Date(4, 3, 2)));
3974             sysTime.roll!"months"(85);
3975             assert(sysTime == SysTime(Date(4, 4, 2)));
3976         }
3977 
3978         {
3979             auto sysTime = SysTime(Date(-1, 1, 1));
3980             sysTime.roll!"months"(-1);
3981             assert(sysTime == SysTime(Date(-1, 12, 1)));
3982             sysTime.roll!"months"(1);
3983             assert(sysTime == SysTime(Date(-1, 1, 1)));
3984         }
3985 
3986         {
3987             auto sysTime = SysTime(Date(-4, 1, 1));
3988             sysTime.roll!"months"(-48);
3989             assert(sysTime == SysTime(Date(-4, 1, 1)));
3990             sysTime.roll!"months"(48);
3991             assert(sysTime == SysTime(Date(-4, 1, 1)));
3992         }
3993 
3994         {
3995             auto sysTime = SysTime(Date(-4, 3, 31));
3996             sysTime.roll!"months"(-49);
3997             assert(sysTime == SysTime(Date(-4, 3, 2)));
3998             sysTime.roll!"months"(49);
3999             assert(sysTime == SysTime(Date(-4, 4, 2)));
4000         }
4001 
4002         {
4003             auto sysTime = SysTime(Date(-4, 3, 31));
4004             sysTime.roll!"months"(-85);
4005             assert(sysTime == SysTime(Date(-4, 3, 2)));
4006             sysTime.roll!"months"(85);
4007             assert(sysTime == SysTime(Date(-4, 4, 2)));
4008         }
4009 
4010         {
4011             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
4012             sysTime.roll!"months"(-1);
4013             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17)));
4014             sysTime.roll!"months"(1);
4015             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
4016         }
4017 
4018         {
4019             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
4020             sysTime.roll!"months"(-85);
4021             assert(sysTime == SysTime(DateTime(4, 3, 2, 12, 11, 10), msecs(9)));
4022             sysTime.roll!"months"(85);
4023             assert(sysTime == SysTime(DateTime(4, 4, 2, 12, 11, 10), msecs(9)));
4024         }
4025 
4026         {
4027             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4028             sysTime.roll!"months"(85);
4029             assert(sysTime == SysTime(DateTime(-3, 5, 1, 12, 11, 10), msecs(9)));
4030             sysTime.roll!"months"(-85);
4031             assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9)));
4032         }
4033 
4034         {
4035             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4036             sysTime.roll!"months"(85).roll!"months"(-83);
4037             assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), msecs(9)));
4038         }
4039 
4040         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4041         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4042         static assert(!__traits(compiles, cst.roll!"months"(4)));
4043         //static assert(!__traits(compiles, ist.roll!"months"(4)));
4044     }
4045 
4046     // Test roll!"months"() with AllowDayOverflow.no
4047     @safe unittest
4048     {
4049         // Test A.D.
4050         {
4051             auto sysTime = SysTime(Date(1999, 7, 6));
4052             sysTime.roll!"months"(3, AllowDayOverflow.no);
4053             assert(sysTime == SysTime(Date(1999, 10, 6)));
4054             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4055             assert(sysTime == SysTime(Date(1999, 6, 6)));
4056         }
4057 
4058         {
4059             auto sysTime = SysTime(Date(1999, 7, 6));
4060             sysTime.roll!"months"(6, AllowDayOverflow.no);
4061             assert(sysTime == SysTime(Date(1999, 1, 6)));
4062             sysTime.roll!"months"(-6, AllowDayOverflow.no);
4063             assert(sysTime == SysTime(Date(1999, 7, 6)));
4064         }
4065 
4066         {
4067             auto sysTime = SysTime(Date(1999, 7, 6));
4068             sysTime.roll!"months"(27, AllowDayOverflow.no);
4069             assert(sysTime == SysTime(Date(1999, 10, 6)));
4070             sysTime.roll!"months"(-28, AllowDayOverflow.no);
4071             assert(sysTime == SysTime(Date(1999, 6, 6)));
4072         }
4073 
4074         {
4075             auto sysTime = SysTime(Date(1999, 5, 31));
4076             sysTime.roll!"months"(1, AllowDayOverflow.no);
4077             assert(sysTime == SysTime(Date(1999, 6, 30)));
4078         }
4079 
4080         {
4081             auto sysTime = SysTime(Date(1999, 5, 31));
4082             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4083             assert(sysTime == SysTime(Date(1999, 4, 30)));
4084         }
4085 
4086         {
4087             auto sysTime = SysTime(Date(1999, 2, 28));
4088             sysTime.roll!"months"(12, AllowDayOverflow.no);
4089             assert(sysTime == SysTime(Date(1999, 2, 28)));
4090         }
4091 
4092         {
4093             auto sysTime = SysTime(Date(2000, 2, 29));
4094             sysTime.roll!"months"(12, AllowDayOverflow.no);
4095             assert(sysTime == SysTime(Date(2000, 2, 29)));
4096         }
4097 
4098         {
4099             auto sysTime = SysTime(Date(1999, 7, 31));
4100             sysTime.roll!"months"(1, AllowDayOverflow.no);
4101             assert(sysTime == SysTime(Date(1999, 8, 31)));
4102             sysTime.roll!"months"(1, AllowDayOverflow.no);
4103             assert(sysTime == SysTime(Date(1999, 9, 30)));
4104         }
4105 
4106         {
4107             auto sysTime = SysTime(Date(1998, 8, 31));
4108             sysTime.roll!"months"(13, AllowDayOverflow.no);
4109             assert(sysTime == SysTime(Date(1998, 9, 30)));
4110             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4111             assert(sysTime == SysTime(Date(1998, 8, 30)));
4112         }
4113 
4114         {
4115             auto sysTime = SysTime(Date(1997, 12, 31));
4116             sysTime.roll!"months"(13, AllowDayOverflow.no);
4117             assert(sysTime == SysTime(Date(1997, 1, 31)));
4118             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4119             assert(sysTime == SysTime(Date(1997, 12, 31)));
4120         }
4121 
4122         {
4123             auto sysTime = SysTime(Date(1997, 12, 31));
4124             sysTime.roll!"months"(14, AllowDayOverflow.no);
4125             assert(sysTime == SysTime(Date(1997, 2, 28)));
4126             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4127             assert(sysTime == SysTime(Date(1997, 12, 28)));
4128         }
4129 
4130         {
4131             auto sysTime = SysTime(Date(1998, 12, 31));
4132             sysTime.roll!"months"(14, AllowDayOverflow.no);
4133             assert(sysTime == SysTime(Date(1998, 2, 28)));
4134             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4135             assert(sysTime == SysTime(Date(1998, 12, 28)));
4136         }
4137 
4138         {
4139             auto sysTime = SysTime(Date(1999, 12, 31));
4140             sysTime.roll!"months"(14, AllowDayOverflow.no);
4141             assert(sysTime == SysTime(Date(1999, 2, 28)));
4142             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4143             assert(sysTime == SysTime(Date(1999, 12, 28)));
4144         }
4145 
4146         {
4147             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
4148             sysTime.roll!"months"(3, AllowDayOverflow.no);
4149             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
4150             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4151             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
4152         }
4153 
4154         {
4155             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
4156             sysTime.roll!"months"(14, AllowDayOverflow.no);
4157             assert(sysTime == SysTime(DateTime(1998, 2, 28, 7, 7, 7), hnsecs(422202)));
4158             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4159             assert(sysTime == SysTime(DateTime(1998, 12, 28, 7, 7, 7), hnsecs(422202)));
4160         }
4161 
4162         {
4163             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
4164             sysTime.roll!"months"(14, AllowDayOverflow.no);
4165             assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 7, 7), hnsecs(422202)));
4166             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4167             assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202)));
4168         }
4169 
4170         // Test B.C.
4171         {
4172             auto sysTime = SysTime(Date(-1999, 7, 6));
4173             sysTime.roll!"months"(3, AllowDayOverflow.no);
4174             assert(sysTime == SysTime(Date(-1999, 10, 6)));
4175             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4176             assert(sysTime == SysTime(Date(-1999, 6, 6)));
4177         }
4178 
4179         {
4180             auto sysTime = SysTime(Date(-1999, 7, 6));
4181             sysTime.roll!"months"(6, AllowDayOverflow.no);
4182             assert(sysTime == SysTime(Date(-1999, 1, 6)));
4183             sysTime.roll!"months"(-6, AllowDayOverflow.no);
4184             assert(sysTime == SysTime(Date(-1999, 7, 6)));
4185         }
4186 
4187         {
4188             auto sysTime = SysTime(Date(-1999, 7, 6));
4189             sysTime.roll!"months"(-27, AllowDayOverflow.no);
4190             assert(sysTime == SysTime(Date(-1999, 4, 6)));
4191             sysTime.roll!"months"(28, AllowDayOverflow.no);
4192             assert(sysTime == SysTime(Date(-1999, 8, 6)));
4193         }
4194 
4195         {
4196             auto sysTime = SysTime(Date(-1999, 5, 31));
4197             sysTime.roll!"months"(1, AllowDayOverflow.no);
4198             assert(sysTime == SysTime(Date(-1999, 6, 30)));
4199         }
4200 
4201         {
4202             auto sysTime = SysTime(Date(-1999, 5, 31));
4203             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4204             assert(sysTime == SysTime(Date(-1999, 4, 30)));
4205         }
4206 
4207         {
4208             auto sysTime = SysTime(Date(-1999, 2, 28));
4209             sysTime.roll!"months"(-12, AllowDayOverflow.no);
4210             assert(sysTime == SysTime(Date(-1999, 2, 28)));
4211         }
4212 
4213         {
4214             auto sysTime = SysTime(Date(-2000, 2, 29));
4215             sysTime.roll!"months"(-12, AllowDayOverflow.no);
4216             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4217         }
4218 
4219         {
4220             auto sysTime = SysTime(Date(-1999, 7, 31));
4221             sysTime.roll!"months"(1, AllowDayOverflow.no);
4222             assert(sysTime == SysTime(Date(-1999, 8, 31)));
4223             sysTime.roll!"months"(1, AllowDayOverflow.no);
4224             assert(sysTime == SysTime(Date(-1999, 9, 30)));
4225         }
4226 
4227         {
4228             auto sysTime = SysTime(Date(-1998, 8, 31));
4229             sysTime.roll!"months"(13, AllowDayOverflow.no);
4230             assert(sysTime == SysTime(Date(-1998, 9, 30)));
4231             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4232             assert(sysTime == SysTime(Date(-1998, 8, 30)));
4233         }
4234 
4235         {
4236             auto sysTime = SysTime(Date(-1997, 12, 31));
4237             sysTime.roll!"months"(13, AllowDayOverflow.no);
4238             assert(sysTime == SysTime(Date(-1997, 1, 31)));
4239             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4240             assert(sysTime == SysTime(Date(-1997, 12, 31)));
4241         }
4242 
4243         {
4244             auto sysTime = SysTime(Date(-1997, 12, 31));
4245             sysTime.roll!"months"(14, AllowDayOverflow.no);
4246             assert(sysTime == SysTime(Date(-1997, 2, 28)));
4247             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4248             assert(sysTime == SysTime(Date(-1997, 12, 28)));
4249         }
4250 
4251         {
4252             auto sysTime = SysTime(Date(-2002, 12, 31));
4253             sysTime.roll!"months"(14, AllowDayOverflow.no);
4254             assert(sysTime == SysTime(Date(-2002, 2, 28)));
4255             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4256             assert(sysTime == SysTime(Date(-2002, 12, 28)));
4257         }
4258 
4259         {
4260             auto sysTime = SysTime(Date(-2001, 12, 31));
4261             sysTime.roll!"months"(14, AllowDayOverflow.no);
4262             assert(sysTime == SysTime(Date(-2001, 2, 28)));
4263             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4264             assert(sysTime == SysTime(Date(-2001, 12, 28)));
4265         }
4266 
4267         {
4268             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
4269             sysTime.roll!"months"(3, AllowDayOverflow.no);
4270             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
4271             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4272             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
4273         }
4274 
4275         {
4276             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
4277             sysTime.roll!"months"(14, AllowDayOverflow.no);
4278             assert(sysTime == SysTime(DateTime(-2002, 2, 28, 7, 7, 7), hnsecs(422202)));
4279             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4280             assert(sysTime == SysTime(DateTime(-2002, 12, 28, 7, 7, 7), hnsecs(422202)));
4281         }
4282 
4283         {
4284             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
4285             sysTime.roll!"months"(14, AllowDayOverflow.no);
4286             assert(sysTime == SysTime(DateTime(-2001, 2, 28, 7, 7, 7), hnsecs(422202)));
4287             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4288             assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202)));
4289         }
4290 
4291         // Test Both
4292         {
4293             auto sysTime = SysTime(Date(1, 1, 1));
4294             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4295             assert(sysTime == SysTime(Date(1, 12, 1)));
4296             sysTime.roll!"months"(1, AllowDayOverflow.no);
4297             assert(sysTime == SysTime(Date(1, 1, 1)));
4298         }
4299 
4300         {
4301             auto sysTime = SysTime(Date(4, 1, 1));
4302             sysTime.roll!"months"(-48, AllowDayOverflow.no);
4303             assert(sysTime == SysTime(Date(4, 1, 1)));
4304             sysTime.roll!"months"(48, AllowDayOverflow.no);
4305             assert(sysTime == SysTime(Date(4, 1, 1)));
4306         }
4307 
4308         {
4309             auto sysTime = SysTime(Date(4, 3, 31));
4310             sysTime.roll!"months"(-49, AllowDayOverflow.no);
4311             assert(sysTime == SysTime(Date(4, 2, 29)));
4312             sysTime.roll!"months"(49, AllowDayOverflow.no);
4313             assert(sysTime == SysTime(Date(4, 3, 29)));
4314         }
4315 
4316         {
4317             auto sysTime = SysTime(Date(4, 3, 31));
4318             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4319             assert(sysTime == SysTime(Date(4, 2, 29)));
4320             sysTime.roll!"months"(85, AllowDayOverflow.no);
4321             assert(sysTime == SysTime(Date(4, 3, 29)));
4322         }
4323 
4324         {
4325             auto sysTime = SysTime(Date(-1, 1, 1));
4326             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4327             assert(sysTime == SysTime(Date(-1, 12, 1)));
4328             sysTime.roll!"months"(1, AllowDayOverflow.no);
4329             assert(sysTime == SysTime(Date(-1, 1, 1)));
4330         }
4331 
4332         {
4333             auto sysTime = SysTime(Date(-4, 1, 1));
4334             sysTime.roll!"months"(-48, AllowDayOverflow.no);
4335             assert(sysTime == SysTime(Date(-4, 1, 1)));
4336             sysTime.roll!"months"(48, AllowDayOverflow.no);
4337             assert(sysTime == SysTime(Date(-4, 1, 1)));
4338         }
4339 
4340         {
4341             auto sysTime = SysTime(Date(-4, 3, 31));
4342             sysTime.roll!"months"(-49, AllowDayOverflow.no);
4343             assert(sysTime == SysTime(Date(-4, 2, 29)));
4344             sysTime.roll!"months"(49, AllowDayOverflow.no);
4345             assert(sysTime == SysTime(Date(-4, 3, 29)));
4346         }
4347 
4348         {
4349             auto sysTime = SysTime(Date(-4, 3, 31));
4350             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4351             assert(sysTime == SysTime(Date(-4, 2, 29)));
4352             sysTime.roll!"months"(85, AllowDayOverflow.no);
4353             assert(sysTime == SysTime(Date(-4, 3, 29)));
4354         }
4355 
4356         {
4357             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
4358             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4359             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0)));
4360             sysTime.roll!"months"(1, AllowDayOverflow.no);
4361             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
4362         }
4363 
4364         {
4365             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
4366             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4367             assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4368             sysTime.roll!"months"(1, AllowDayOverflow.no);
4369             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4370         }
4371 
4372         {
4373             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
4374             sysTime.roll!"months"(1, AllowDayOverflow.no);
4375             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
4376             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4377             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
4378         }
4379 
4380         {
4381             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
4382             sysTime.roll!"months"(1, AllowDayOverflow.no);
4383             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4384             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4385             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4386         }
4387 
4388         {
4389             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
4390             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4391             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17)));
4392             sysTime.roll!"months"(1, AllowDayOverflow.no);
4393             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
4394         }
4395 
4396         {
4397             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
4398             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4399             assert(sysTime == SysTime(DateTime(4, 2, 29, 12, 11, 10), msecs(9)));
4400             sysTime.roll!"months"(85, AllowDayOverflow.no);
4401             assert(sysTime == SysTime(DateTime(4, 3, 29, 12, 11, 10), msecs(9)));
4402         }
4403 
4404         {
4405             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4406             sysTime.roll!"months"(85, AllowDayOverflow.no);
4407             assert(sysTime == SysTime(DateTime(-3, 4, 30, 12, 11, 10), msecs(9)));
4408             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4409             assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9)));
4410         }
4411 
4412         {
4413             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4414             sysTime.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no);
4415             assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9)));
4416         }
4417     }
4418 
4419 
4420     /++
4421         Adds the given number of units to this $(LREF SysTime). A negative number
4422         will subtract.
4423 
4424         The difference between rolling and adding is that rolling does not
4425         affect larger units. For instance, rolling a $(LREF SysTime) one
4426         year's worth of days gets the exact same $(LREF SysTime).
4427 
4428         Accepted units are $(D "days"), $(D "minutes"), $(D "hours"),
4429         $(D "minutes"), $(D "seconds"), $(D "msecs"), $(D "usecs"), and
4430         $(D "hnsecs").
4431 
4432         Note that when rolling msecs, usecs or hnsecs, they all add up to a
4433         second. So, for example, rolling 1000 msecs is exactly the same as
4434         rolling 100,000 usecs.
4435 
4436         Params:
4437             units = The units to add.
4438             value = The number of $(D_PARAM units) to add to this
4439                     $(LREF SysTime).
4440       +/
4441     ref SysTime roll(string units)(long value) @safe nothrow
4442         if (units == "days")
4443     {
4444         auto hnsecs = adjTime;
4445         auto gdays = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
4446 
4447         if (hnsecs < 0)
4448         {
4449             hnsecs += convert!("hours", "hnsecs")(24);
4450             --gdays;
4451         }
4452 
4453         auto date = Date(cast(int) gdays);
4454         date.roll!"days"(value);
4455         gdays = date.dayOfGregorianCal - 1;
4456 
4457         if (gdays < 0)
4458         {
4459             hnsecs -= convert!("hours", "hnsecs")(24);
4460             ++gdays;
4461         }
4462 
4463         immutable newDaysHNSecs = convert!("days", "hnsecs")(gdays);
4464         adjTime = newDaysHNSecs + hnsecs;
4465         return  this;
4466     }
4467 
4468     ///
4469     @safe unittest
4470     {
4471         import core.time : msecs, hnsecs;
4472         import std.datetime.date : DateTime;
4473 
4474         auto st1 = SysTime(DateTime(2010, 1, 1, 11, 23, 12));
4475         st1.roll!"days"(1);
4476         assert(st1 == SysTime(DateTime(2010, 1, 2, 11, 23, 12)));
4477         st1.roll!"days"(365);
4478         assert(st1 == SysTime(DateTime(2010, 1, 26, 11, 23, 12)));
4479         st1.roll!"days"(-32);
4480         assert(st1 == SysTime(DateTime(2010, 1, 25, 11, 23, 12)));
4481 
4482         auto st2 = SysTime(DateTime(2010, 7, 4, 12, 0, 0));
4483         st2.roll!"hours"(1);
4484         assert(st2 == SysTime(DateTime(2010, 7, 4, 13, 0, 0)));
4485 
4486         auto st3 = SysTime(DateTime(2010, 2, 12, 12, 0, 0));
4487         st3.roll!"hours"(-1);
4488         assert(st3 == SysTime(DateTime(2010, 2, 12, 11, 0, 0)));
4489 
4490         auto st4 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
4491         st4.roll!"minutes"(1);
4492         assert(st4 == SysTime(DateTime(2009, 12, 31, 0, 1, 0)));
4493 
4494         auto st5 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
4495         st5.roll!"minutes"(-1);
4496         assert(st5 == SysTime(DateTime(2010, 1, 1, 0, 59, 0)));
4497 
4498         auto st6 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
4499         st6.roll!"seconds"(1);
4500         assert(st6 == SysTime(DateTime(2009, 12, 31, 0, 0, 1)));
4501 
4502         auto st7 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
4503         st7.roll!"seconds"(-1);
4504         assert(st7 == SysTime(DateTime(2010, 1, 1, 0, 0, 59)));
4505 
4506         auto dt = DateTime(2010, 1, 1, 0, 0, 0);
4507         auto st8 = SysTime(dt);
4508         st8.roll!"msecs"(1);
4509         assert(st8 == SysTime(dt, msecs(1)));
4510 
4511         auto st9 = SysTime(dt);
4512         st9.roll!"msecs"(-1);
4513         assert(st9 == SysTime(dt, msecs(999)));
4514 
4515         auto st10 = SysTime(dt);
4516         st10.roll!"hnsecs"(1);
4517         assert(st10 == SysTime(dt, hnsecs(1)));
4518 
4519         auto st11 = SysTime(dt);
4520         st11.roll!"hnsecs"(-1);
4521         assert(st11 == SysTime(dt, hnsecs(9_999_999)));
4522     }
4523 
4524     @safe unittest
4525     {
4526         // Test A.D.
4527         {
4528             auto sysTime = SysTime(Date(1999, 2, 28));
4529             sysTime.roll!"days"(1);
4530             assert(sysTime == SysTime(Date(1999, 2, 1)));
4531             sysTime.roll!"days"(-1);
4532             assert(sysTime == SysTime(Date(1999, 2, 28)));
4533         }
4534 
4535         {
4536             auto sysTime = SysTime(Date(2000, 2, 28));
4537             sysTime.roll!"days"(1);
4538             assert(sysTime == SysTime(Date(2000, 2, 29)));
4539             sysTime.roll!"days"(1);
4540             assert(sysTime == SysTime(Date(2000, 2, 1)));
4541             sysTime.roll!"days"(-1);
4542             assert(sysTime == SysTime(Date(2000, 2, 29)));
4543         }
4544 
4545         {
4546             auto sysTime = SysTime(Date(1999, 6, 30));
4547             sysTime.roll!"days"(1);
4548             assert(sysTime == SysTime(Date(1999, 6, 1)));
4549             sysTime.roll!"days"(-1);
4550             assert(sysTime == SysTime(Date(1999, 6, 30)));
4551         }
4552 
4553         {
4554             auto sysTime = SysTime(Date(1999, 7, 31));
4555             sysTime.roll!"days"(1);
4556             assert(sysTime == SysTime(Date(1999, 7, 1)));
4557             sysTime.roll!"days"(-1);
4558             assert(sysTime == SysTime(Date(1999, 7, 31)));
4559         }
4560 
4561         {
4562             auto sysTime = SysTime(Date(1999, 1, 1));
4563             sysTime.roll!"days"(-1);
4564             assert(sysTime == SysTime(Date(1999, 1, 31)));
4565             sysTime.roll!"days"(1);
4566             assert(sysTime == SysTime(Date(1999, 1, 1)));
4567         }
4568 
4569         {
4570             auto sysTime = SysTime(Date(1999, 7, 6));
4571             sysTime.roll!"days"(9);
4572             assert(sysTime == SysTime(Date(1999, 7, 15)));
4573             sysTime.roll!"days"(-11);
4574             assert(sysTime == SysTime(Date(1999, 7, 4)));
4575             sysTime.roll!"days"(30);
4576             assert(sysTime == SysTime(Date(1999, 7, 3)));
4577             sysTime.roll!"days"(-3);
4578             assert(sysTime == SysTime(Date(1999, 7, 31)));
4579         }
4580 
4581         {
4582             auto sysTime = SysTime(Date(1999, 7, 6));
4583             sysTime.roll!"days"(365);
4584             assert(sysTime == SysTime(Date(1999, 7, 30)));
4585             sysTime.roll!"days"(-365);
4586             assert(sysTime == SysTime(Date(1999, 7, 6)));
4587             sysTime.roll!"days"(366);
4588             assert(sysTime == SysTime(Date(1999, 7, 31)));
4589             sysTime.roll!"days"(730);
4590             assert(sysTime == SysTime(Date(1999, 7, 17)));
4591             sysTime.roll!"days"(-1096);
4592             assert(sysTime == SysTime(Date(1999, 7, 6)));
4593         }
4594 
4595         {
4596             auto sysTime = SysTime(Date(1999, 2, 6));
4597             sysTime.roll!"days"(365);
4598             assert(sysTime == SysTime(Date(1999, 2, 7)));
4599             sysTime.roll!"days"(-365);
4600             assert(sysTime == SysTime(Date(1999, 2, 6)));
4601             sysTime.roll!"days"(366);
4602             assert(sysTime == SysTime(Date(1999, 2, 8)));
4603             sysTime.roll!"days"(730);
4604             assert(sysTime == SysTime(Date(1999, 2, 10)));
4605             sysTime.roll!"days"(-1096);
4606             assert(sysTime == SysTime(Date(1999, 2, 6)));
4607         }
4608 
4609         {
4610             auto sysTime = SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578));
4611             sysTime.roll!"days"(1);
4612             assert(sysTime == SysTime(DateTime(1999, 2, 1, 7, 9, 2), usecs(234578)));
4613             sysTime.roll!"days"(-1);
4614             assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578)));
4615         }
4616 
4617         {
4618             auto sysTime = SysTime(DateTime(1999, 7, 6, 7, 9, 2), usecs(234578));
4619             sysTime.roll!"days"(9);
4620             assert(sysTime == SysTime(DateTime(1999, 7, 15, 7, 9, 2), usecs(234578)));
4621             sysTime.roll!"days"(-11);
4622             assert(sysTime == SysTime(DateTime(1999, 7, 4, 7, 9, 2), usecs(234578)));
4623             sysTime.roll!"days"(30);
4624             assert(sysTime == SysTime(DateTime(1999, 7, 3, 7, 9, 2), usecs(234578)));
4625             sysTime.roll!"days"(-3);
4626             assert(sysTime == SysTime(DateTime(1999, 7, 31, 7, 9, 2), usecs(234578)));
4627         }
4628 
4629         // Test B.C.
4630         {
4631             auto sysTime = SysTime(Date(-1999, 2, 28));
4632             sysTime.roll!"days"(1);
4633             assert(sysTime == SysTime(Date(-1999, 2, 1)));
4634             sysTime.roll!"days"(-1);
4635             assert(sysTime == SysTime(Date(-1999, 2, 28)));
4636         }
4637 
4638         {
4639             auto sysTime = SysTime(Date(-2000, 2, 28));
4640             sysTime.roll!"days"(1);
4641             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4642             sysTime.roll!"days"(1);
4643             assert(sysTime == SysTime(Date(-2000, 2, 1)));
4644             sysTime.roll!"days"(-1);
4645             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4646         }
4647 
4648         {
4649             auto sysTime = SysTime(Date(-1999, 6, 30));
4650             sysTime.roll!"days"(1);
4651             assert(sysTime == SysTime(Date(-1999, 6, 1)));
4652             sysTime.roll!"days"(-1);
4653             assert(sysTime == SysTime(Date(-1999, 6, 30)));
4654         }
4655 
4656         {
4657             auto sysTime = SysTime(Date(-1999, 7, 31));
4658             sysTime.roll!"days"(1);
4659             assert(sysTime == SysTime(Date(-1999, 7, 1)));
4660             sysTime.roll!"days"(-1);
4661             assert(sysTime == SysTime(Date(-1999, 7, 31)));
4662         }
4663 
4664         {
4665             auto sysTime = SysTime(Date(-1999, 1, 1));
4666             sysTime.roll!"days"(-1);
4667             assert(sysTime == SysTime(Date(-1999, 1, 31)));
4668             sysTime.roll!"days"(1);
4669             assert(sysTime == SysTime(Date(-1999, 1, 1)));
4670         }
4671 
4672         {
4673             auto sysTime = SysTime(Date(-1999, 7, 6));
4674             sysTime.roll!"days"(9);
4675             assert(sysTime == SysTime(Date(-1999, 7, 15)));
4676             sysTime.roll!"days"(-11);
4677             assert(sysTime == SysTime(Date(-1999, 7, 4)));
4678             sysTime.roll!"days"(30);
4679             assert(sysTime == SysTime(Date(-1999, 7, 3)));
4680             sysTime.roll!"days"(-3);
4681             assert(sysTime == SysTime(Date(-1999, 7, 31)));
4682         }
4683 
4684         {
4685             auto sysTime = SysTime(Date(-1999, 7, 6));
4686             sysTime.roll!"days"(365);
4687             assert(sysTime == SysTime(Date(-1999, 7, 30)));
4688             sysTime.roll!"days"(-365);
4689             assert(sysTime == SysTime(Date(-1999, 7, 6)));
4690             sysTime.roll!"days"(366);
4691             assert(sysTime == SysTime(Date(-1999, 7, 31)));
4692             sysTime.roll!"days"(730);
4693             assert(sysTime == SysTime(Date(-1999, 7, 17)));
4694             sysTime.roll!"days"(-1096);
4695             assert(sysTime == SysTime(Date(-1999, 7, 6)));
4696         }
4697 
4698         {
4699             auto sysTime = SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578));
4700             sysTime.roll!"days"(1);
4701             assert(sysTime == SysTime(DateTime(-1999, 2, 1, 7, 9, 2), usecs(234578)));
4702             sysTime.roll!"days"(-1);
4703             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578)));
4704         }
4705 
4706         {
4707             auto sysTime = SysTime(DateTime(-1999, 7, 6, 7, 9, 2), usecs(234578));
4708             sysTime.roll!"days"(9);
4709             assert(sysTime == SysTime(DateTime(-1999, 7, 15, 7, 9, 2), usecs(234578)));
4710             sysTime.roll!"days"(-11);
4711             assert(sysTime == SysTime(DateTime(-1999, 7, 4, 7, 9, 2), usecs(234578)));
4712             sysTime.roll!"days"(30);
4713             assert(sysTime == SysTime(DateTime(-1999, 7, 3, 7, 9, 2), usecs(234578)));
4714             sysTime.roll!"days"(-3);
4715         }
4716 
4717         // Test Both
4718         {
4719             auto sysTime = SysTime(Date(1, 7, 6));
4720             sysTime.roll!"days"(-365);
4721             assert(sysTime == SysTime(Date(1, 7, 13)));
4722             sysTime.roll!"days"(365);
4723             assert(sysTime == SysTime(Date(1, 7, 6)));
4724             sysTime.roll!"days"(-731);
4725             assert(sysTime == SysTime(Date(1, 7, 19)));
4726             sysTime.roll!"days"(730);
4727             assert(sysTime == SysTime(Date(1, 7, 5)));
4728         }
4729 
4730         {
4731             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
4732             sysTime.roll!"days"(-1);
4733             assert(sysTime == SysTime(DateTime(1, 1, 31, 0, 0, 0)));
4734             sysTime.roll!"days"(1);
4735             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
4736         }
4737 
4738         {
4739             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
4740             sysTime.roll!"days"(-1);
4741             assert(sysTime == SysTime(DateTime(1, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
4742             sysTime.roll!"days"(1);
4743             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4744         }
4745 
4746         {
4747             auto sysTime = SysTime(DateTime(0, 12, 31, 0, 0, 0));
4748             sysTime.roll!"days"(1);
4749             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
4750             sysTime.roll!"days"(-1);
4751             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0)));
4752         }
4753 
4754         {
4755             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
4756             sysTime.roll!"days"(1);
4757             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4758             sysTime.roll!"days"(-1);
4759             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
4760         }
4761 
4762         {
4763             auto sysTime = SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22));
4764             sysTime.roll!"days"(-365);
4765             assert(sysTime == SysTime(DateTime(1, 7, 13, 13, 13, 9), msecs(22)));
4766             sysTime.roll!"days"(365);
4767             assert(sysTime == SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22)));
4768             sysTime.roll!"days"(-731);
4769             assert(sysTime == SysTime(DateTime(1, 7, 19, 13, 13, 9), msecs(22)));
4770             sysTime.roll!"days"(730);
4771             assert(sysTime == SysTime(DateTime(1, 7, 5, 13, 13, 9), msecs(22)));
4772         }
4773 
4774         {
4775             auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22));
4776             sysTime.roll!"days"(-365);
4777             assert(sysTime == SysTime(DateTime(0, 7, 13, 13, 13, 9), msecs(22)));
4778             sysTime.roll!"days"(365);
4779             assert(sysTime == SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22)));
4780             sysTime.roll!"days"(-731);
4781             assert(sysTime == SysTime(DateTime(0, 7, 19, 13, 13, 9), msecs(22)));
4782             sysTime.roll!"days"(730);
4783             assert(sysTime == SysTime(DateTime(0, 7, 5, 13, 13, 9), msecs(22)));
4784         }
4785 
4786         {
4787             auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22));
4788             sysTime.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730);
4789             assert(sysTime == SysTime(DateTime(0, 7, 8, 13, 13, 9), msecs(22)));
4790         }
4791 
4792         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4793         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4794         static assert(!__traits(compiles, cst.roll!"days"(4)));
4795         //static assert(!__traits(compiles, ist.roll!"days"(4)));
4796     }
4797 
4798 
4799     // Shares documentation with "days" version.
4800     ref SysTime roll(string units)(long value) @safe nothrow
4801         if (units == "hours" || units == "minutes" || units == "seconds")
4802     {
4803         try
4804         {
4805             auto hnsecs = adjTime;
4806             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
4807 
4808             if (hnsecs < 0)
4809             {
4810                 hnsecs += convert!("hours", "hnsecs")(24);
4811                 --days;
4812             }
4813 
4814             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
4815             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
4816             immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
4817 
4818             auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
4819                                           cast(int) minute, cast(int) second));
4820             dateTime.roll!units(value);
4821             --days;
4822 
4823             hnsecs += convert!("hours", "hnsecs")(dateTime.hour);
4824             hnsecs += convert!("minutes", "hnsecs")(dateTime.minute);
4825             hnsecs += convert!("seconds", "hnsecs")(dateTime.second);
4826 
4827             if (days < 0)
4828             {
4829                 hnsecs -= convert!("hours", "hnsecs")(24);
4830                 ++days;
4831             }
4832 
4833             immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
4834             adjTime = newDaysHNSecs + hnsecs;
4835             return this;
4836         }
4837         catch (Exception e)
4838             assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw.");
4839     }
4840 
4841     // Test roll!"hours"().
4842     @safe unittest
4843     {
4844         static void testST(SysTime orig, int hours, in SysTime expected, size_t line = __LINE__)
4845         {
4846             orig.roll!"hours"(hours);
4847             if (orig != expected)
4848                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
4849         }
4850 
4851         // Test A.D.
4852         immutable d = msecs(45);
4853         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
4854         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
4855         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
4856         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
4857         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d));
4858         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d));
4859         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d));
4860         testST(beforeAD, 6, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d));
4861         testST(beforeAD, 7, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d));
4862         testST(beforeAD, 8, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
4863         testST(beforeAD, 9, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d));
4864         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
4865         testST(beforeAD, 11, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
4866         testST(beforeAD, 12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
4867         testST(beforeAD, 13, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
4868         testST(beforeAD, 14, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d));
4869         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d));
4870         testST(beforeAD, 16, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
4871         testST(beforeAD, 17, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d));
4872         testST(beforeAD, 18, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d));
4873         testST(beforeAD, 19, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d));
4874         testST(beforeAD, 20, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d));
4875         testST(beforeAD, 21, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d));
4876         testST(beforeAD, 22, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
4877         testST(beforeAD, 23, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
4878         testST(beforeAD, 24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
4879         testST(beforeAD, 25, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
4880         testST(beforeAD, 50, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
4881         testST(beforeAD, 10_000, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
4882 
4883         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
4884         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
4885         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d));
4886         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d));
4887         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d));
4888         testST(beforeAD, -6, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d));
4889         testST(beforeAD, -7, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d));
4890         testST(beforeAD, -8, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
4891         testST(beforeAD, -9, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d));
4892         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d));
4893         testST(beforeAD, -11, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
4894         testST(beforeAD, -12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
4895         testST(beforeAD, -13, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
4896         testST(beforeAD, -14, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
4897         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d));
4898         testST(beforeAD, -16, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
4899         testST(beforeAD, -17, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d));
4900         testST(beforeAD, -18, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d));
4901         testST(beforeAD, -19, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d));
4902         testST(beforeAD, -20, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d));
4903         testST(beforeAD, -21, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d));
4904         testST(beforeAD, -22, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
4905         testST(beforeAD, -23, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
4906         testST(beforeAD, -24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
4907         testST(beforeAD, -25, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
4908         testST(beforeAD, -50, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
4909         testST(beforeAD, -10_000, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
4910 
4911         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
4912         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
4913         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
4914 
4915         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
4916         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
4917         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
4918 
4919         testST(SysTime(DateTime(1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 31, 0, 30, 33), d));
4920         testST(SysTime(DateTime(1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(1999, 8, 1, 23, 30, 33), d));
4921 
4922         testST(SysTime(DateTime(1999, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 12, 31, 0, 30, 33), d));
4923         testST(SysTime(DateTime(2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(2000, 1, 1, 23, 30, 33), d));
4924 
4925         testST(SysTime(DateTime(1999, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(1999, 2, 28, 0, 30, 33), d));
4926         testST(SysTime(DateTime(1999, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(1999, 3, 2, 23, 30, 33), d));
4927 
4928         testST(SysTime(DateTime(2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(2000, 2, 28, 0, 30, 33), d));
4929         testST(SysTime(DateTime(2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(2000, 3, 1, 23, 30, 33), d));
4930 
4931         // Test B.C.
4932         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
4933         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
4934         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
4935         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
4936         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d));
4937         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d));
4938         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d));
4939         testST(beforeBC, 6, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d));
4940         testST(beforeBC, 7, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d));
4941         testST(beforeBC, 8, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
4942         testST(beforeBC, 9, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d));
4943         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
4944         testST(beforeBC, 11, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
4945         testST(beforeBC, 12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
4946         testST(beforeBC, 13, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
4947         testST(beforeBC, 14, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d));
4948         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d));
4949         testST(beforeBC, 16, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
4950         testST(beforeBC, 17, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d));
4951         testST(beforeBC, 18, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d));
4952         testST(beforeBC, 19, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d));
4953         testST(beforeBC, 20, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d));
4954         testST(beforeBC, 21, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d));
4955         testST(beforeBC, 22, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
4956         testST(beforeBC, 23, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
4957         testST(beforeBC, 24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
4958         testST(beforeBC, 25, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
4959         testST(beforeBC, 50, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
4960         testST(beforeBC, 10_000, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
4961 
4962         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
4963         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
4964         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d));
4965         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d));
4966         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d));
4967         testST(beforeBC, -6, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d));
4968         testST(beforeBC, -7, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d));
4969         testST(beforeBC, -8, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
4970         testST(beforeBC, -9, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d));
4971         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d));
4972         testST(beforeBC, -11, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
4973         testST(beforeBC, -12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
4974         testST(beforeBC, -13, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
4975         testST(beforeBC, -14, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
4976         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d));
4977         testST(beforeBC, -16, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
4978         testST(beforeBC, -17, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d));
4979         testST(beforeBC, -18, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d));
4980         testST(beforeBC, -19, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d));
4981         testST(beforeBC, -20, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d));
4982         testST(beforeBC, -21, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d));
4983         testST(beforeBC, -22, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
4984         testST(beforeBC, -23, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
4985         testST(beforeBC, -24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
4986         testST(beforeBC, -25, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
4987         testST(beforeBC, -50, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
4988         testST(beforeBC, -10_000, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
4989 
4990         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
4991         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
4992         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
4993 
4994         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
4995         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
4996         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
4997 
4998         testST(SysTime(DateTime(-1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 31, 0, 30, 33), d));
4999         testST(SysTime(DateTime(-1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 8, 1, 23, 30, 33), d));
5000 
5001         testST(SysTime(DateTime(-2001, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(-2001, 12, 31, 0, 30, 33), d));
5002         testST(SysTime(DateTime(-2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(-2000, 1, 1, 23, 30, 33), d));
5003 
5004         testST(SysTime(DateTime(-2001, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2001, 2, 28, 0, 30, 33), d));
5005         testST(SysTime(DateTime(-2001, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(-2001, 3, 2, 23, 30, 33), d));
5006 
5007         testST(SysTime(DateTime(-2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2000, 2, 28, 0, 30, 33), d));
5008         testST(SysTime(DateTime(-2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(-2000, 3, 1, 23, 30, 33), d));
5009 
5010         // Test Both
5011         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 17_546, SysTime(DateTime(-1, 1, 1, 13, 30, 33), d));
5012         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -17_546, SysTime(DateTime(1, 1, 1, 11, 30, 33), d));
5013 
5014         {
5015             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5016             sysTime.roll!"hours"(-1);
5017             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 0, 0)));
5018             sysTime.roll!"hours"(1);
5019             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5020         }
5021 
5022         {
5023             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999));
5024             sysTime.roll!"hours"(-1);
5025             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
5026             sysTime.roll!"hours"(1);
5027             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999)));
5028         }
5029 
5030         {
5031             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 0, 0));
5032             sysTime.roll!"hours"(1);
5033             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0)));
5034             sysTime.roll!"hours"(-1);
5035             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5036         }
5037 
5038         {
5039             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5040             sysTime.roll!"hours"(1);
5041             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 59, 59), hnsecs(9_999_999)));
5042             sysTime.roll!"hours"(-1);
5043             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5044         }
5045 
5046         {
5047             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5048             sysTime.roll!"hours"(1).roll!"hours"(-67);
5049             assert(sysTime == SysTime(DateTime(0, 12, 31, 5, 59, 59), hnsecs(9_999_999)));
5050         }
5051 
5052         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5053         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5054         static assert(!__traits(compiles, cst.roll!"hours"(4)));
5055         //static assert(!__traits(compiles, ist.roll!"hours"(4)));
5056     }
5057 
5058     // Test roll!"minutes"().
5059     @safe unittest
5060     {
5061         static void testST(SysTime orig, int minutes, in SysTime expected, size_t line = __LINE__)
5062         {
5063             orig.roll!"minutes"(minutes);
5064             if (orig != expected)
5065                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5066         }
5067 
5068         // Test A.D.
5069         immutable d = usecs(7203);
5070         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
5071         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5072         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5073         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 32, 33), d));
5074         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 33, 33), d));
5075         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 34, 33), d));
5076         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 35, 33), d));
5077         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 40, 33), d));
5078         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5079         testST(beforeAD, 29, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5080         testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5081         testST(beforeAD, 45, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5082         testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5083         testST(beforeAD, 75, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5084         testST(beforeAD, 90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5085         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 10, 33), d));
5086 
5087         testST(beforeAD, 689, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5088         testST(beforeAD, 690, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5089         testST(beforeAD, 691, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5090         testST(beforeAD, 960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5091         testST(beforeAD, 1439, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5092         testST(beforeAD, 1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5093         testST(beforeAD, 1441, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5094         testST(beforeAD, 2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5095 
5096         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5097         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 28, 33), d));
5098         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 27, 33), d));
5099         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 26, 33), d));
5100         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 25, 33), d));
5101         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 20, 33), d));
5102         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5103         testST(beforeAD, -29, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5104         testST(beforeAD, -30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5105         testST(beforeAD, -45, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5106         testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5107         testST(beforeAD, -75, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5108         testST(beforeAD, -90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5109         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 50, 33), d));
5110 
5111         testST(beforeAD, -749, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5112         testST(beforeAD, -750, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5113         testST(beforeAD, -751, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5114         testST(beforeAD, -960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5115         testST(beforeAD, -1439, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5116         testST(beforeAD, -1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5117         testST(beforeAD, -1441, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5118         testST(beforeAD, -2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5119 
5120         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5121         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5122         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5123 
5124         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(1999, 7, 6, 11, 0, 33), d));
5125         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(1999, 7, 6, 11, 59, 33), d));
5126         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(1999, 7, 6, 11, 58, 33), d));
5127 
5128         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 1, 33), d));
5129         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 33), d));
5130         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 0, 59, 33), d));
5131 
5132         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(1999, 7, 5, 23, 0, 33), d));
5133         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 33), d));
5134         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(1999, 7, 5, 23, 58, 33), d));
5135 
5136         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(1998, 12, 31, 23, 0, 33), d));
5137         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 33), d));
5138         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(1998, 12, 31, 23, 58, 33), d));
5139 
5140         // Test B.C.
5141         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5142         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5143         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5144         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 32, 33), d));
5145         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 33, 33), d));
5146         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 34, 33), d));
5147         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 35, 33), d));
5148         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 40, 33), d));
5149         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5150         testST(beforeBC, 29, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5151         testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5152         testST(beforeBC, 45, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5153         testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5154         testST(beforeBC, 75, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5155         testST(beforeBC, 90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5156         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 10, 33), d));
5157 
5158         testST(beforeBC, 689, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5159         testST(beforeBC, 690, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5160         testST(beforeBC, 691, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5161         testST(beforeBC, 960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5162         testST(beforeBC, 1439, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5163         testST(beforeBC, 1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5164         testST(beforeBC, 1441, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5165         testST(beforeBC, 2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5166 
5167         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5168         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 28, 33), d));
5169         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 27, 33), d));
5170         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 26, 33), d));
5171         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 25, 33), d));
5172         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 20, 33), d));
5173         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5174         testST(beforeBC, -29, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5175         testST(beforeBC, -30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5176         testST(beforeBC, -45, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5177         testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5178         testST(beforeBC, -75, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5179         testST(beforeBC, -90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5180         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 50, 33), d));
5181 
5182         testST(beforeBC, -749, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5183         testST(beforeBC, -750, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5184         testST(beforeBC, -751, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5185         testST(beforeBC, -960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5186         testST(beforeBC, -1439, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5187         testST(beforeBC, -1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5188         testST(beforeBC, -1441, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5189         testST(beforeBC, -2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5190 
5191         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5192         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5193         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5194 
5195         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 11, 0, 33), d));
5196         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d));
5197         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 11, 58, 33), d));
5198 
5199         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 1, 33), d));
5200         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d));
5201         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 59, 33), d));
5202 
5203         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 0, 33), d));
5204         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d));
5205         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 58, 33), d));
5206 
5207         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 0, 33), d));
5208         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d));
5209         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 58, 33), d));
5210 
5211         // Test Both
5212         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(1, 1, 1, 0, 59, 0)));
5213         testST(SysTime(DateTime(0, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5214 
5215         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(0, 1, 1, 0, 59, 0)));
5216         testST(SysTime(DateTime(-1, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(-1, 12, 31, 23, 0, 0)));
5217 
5218         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 1_052_760, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d));
5219         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -1_052_760, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5220 
5221         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 1_052_782, SysTime(DateTime(-1, 1, 1, 11, 52, 33), d));
5222         testST(SysTime(DateTime(1, 1, 1, 13, 52, 33), d), -1_052_782, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5223 
5224         {
5225             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5226             sysTime.roll!"minutes"(-1);
5227             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 0)));
5228             sysTime.roll!"minutes"(1);
5229             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5230         }
5231 
5232         {
5233             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999));
5234             sysTime.roll!"minutes"(-1);
5235             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999)));
5236             sysTime.roll!"minutes"(1);
5237             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999)));
5238         }
5239 
5240         {
5241             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 0));
5242             sysTime.roll!"minutes"(1);
5243             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5244             sysTime.roll!"minutes"(-1);
5245             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0)));
5246         }
5247 
5248         {
5249             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5250             sysTime.roll!"minutes"(1);
5251             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 59), hnsecs(9_999_999)));
5252             sysTime.roll!"minutes"(-1);
5253             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5254         }
5255 
5256         {
5257             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5258             sysTime.roll!"minutes"(1).roll!"minutes"(-79);
5259             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 41, 59), hnsecs(9_999_999)));
5260         }
5261 
5262         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5263         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5264         static assert(!__traits(compiles, cst.roll!"minutes"(4)));
5265         //static assert(!__traits(compiles, ist.roll!"minutes"(4)));
5266     }
5267 
5268     // Test roll!"seconds"().
5269     @safe unittest
5270     {
5271         static void testST(SysTime orig, int seconds, in SysTime expected, size_t line = __LINE__)
5272         {
5273             orig.roll!"seconds"(seconds);
5274             if (orig != expected)
5275                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5276         }
5277 
5278         // Test A.D.
5279         immutable d = msecs(274);
5280         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
5281         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5282         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5283         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 35), d));
5284         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 30, 36), d));
5285         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 30, 37), d));
5286         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 30, 38), d));
5287         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 43), d));
5288         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 30, 48), d));
5289         testST(beforeAD, 26, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5290         testST(beforeAD, 27, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5291         testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 30, 3), d));
5292         testST(beforeAD, 59, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5293         testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5294         testST(beforeAD, 61, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5295 
5296         testST(beforeAD, 1766, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5297         testST(beforeAD, 1767, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5298         testST(beforeAD, 1768, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d));
5299         testST(beforeAD, 2007, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5300         testST(beforeAD, 3599, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5301         testST(beforeAD, 3600, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5302         testST(beforeAD, 3601, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5303         testST(beforeAD, 7200, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5304 
5305         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5306         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 31), d));
5307         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 30, 30), d));
5308         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 30, 29), d));
5309         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 30, 28), d));
5310         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 23), d));
5311         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 30, 18), d));
5312         testST(beforeAD, -33, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5313         testST(beforeAD, -34, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5314         testST(beforeAD, -35, SysTime(DateTime(1999, 7, 6, 12, 30, 58), d));
5315         testST(beforeAD, -59, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5316         testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5317         testST(beforeAD, -61, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5318 
5319         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d));
5320         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5321         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5322 
5323         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 0, 1), d));
5324         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 0), d));
5325         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 0, 59), d));
5326 
5327         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 0, 0, 1), d));
5328         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 0), d));
5329         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 0, 0, 59), d));
5330 
5331         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(1999, 7, 5, 23, 59, 0), d));
5332         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 59), d));
5333         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(1999, 7, 5, 23, 59, 58), d));
5334 
5335         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(1998, 12, 31, 23, 59, 0), d));
5336         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 59), d));
5337         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(1998, 12, 31, 23, 59, 58), d));
5338 
5339         // Test B.C.
5340         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5341         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5342         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5343         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 35), d));
5344         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 30, 36), d));
5345         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 30, 37), d));
5346         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 30, 38), d));
5347         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 43), d));
5348         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 30, 48), d));
5349         testST(beforeBC, 26, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5350         testST(beforeBC, 27, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5351         testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 30, 3), d));
5352         testST(beforeBC, 59, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5353         testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5354         testST(beforeBC, 61, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5355 
5356         testST(beforeBC, 1766, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5357         testST(beforeBC, 1767, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5358         testST(beforeBC, 1768, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d));
5359         testST(beforeBC, 2007, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5360         testST(beforeBC, 3599, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5361         testST(beforeBC, 3600, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5362         testST(beforeBC, 3601, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5363         testST(beforeBC, 7200, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5364 
5365         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5366         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 31), d));
5367         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 30, 30), d));
5368         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 30, 29), d));
5369         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 30, 28), d));
5370         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 23), d));
5371         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 30, 18), d));
5372         testST(beforeBC, -33, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5373         testST(beforeBC, -34, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5374         testST(beforeBC, -35, SysTime(DateTime(-1999, 7, 6, 12, 30, 58), d));
5375         testST(beforeBC, -59, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5376         testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5377         testST(beforeBC, -61, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5378 
5379         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d));
5380         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5381         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5382 
5383         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 0, 1), d));
5384         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d));
5385         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 0, 59), d));
5386 
5387         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 0, 1), d));
5388         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d));
5389         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 0, 59), d));
5390 
5391         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 59, 0), d));
5392         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d));
5393         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 59, 58), d));
5394 
5395         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 59, 0), d));
5396         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d));
5397         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 59, 58), d));
5398 
5399         // Test Both
5400         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(1, 1, 1, 0, 0, 59), d));
5401         testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(0, 12, 31, 23, 59, 0), d));
5402 
5403         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(0, 1, 1, 0, 0, 59), d));
5404         testST(SysTime(DateTime(-1, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-1, 12, 31, 23, 59, 0), d));
5405 
5406         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_600L, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d));
5407         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -63_165_600L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5408 
5409         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_617L, SysTime(DateTime(-1, 1, 1, 11, 30, 50), d));
5410         testST(SysTime(DateTime(1, 1, 1, 13, 30, 50), d), -63_165_617L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5411 
5412         {
5413             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5414             sysTime.roll!"seconds"(-1);
5415             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59)));
5416             sysTime.roll!"seconds"(1);
5417             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5418         }
5419 
5420         {
5421             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999));
5422             sysTime.roll!"seconds"(-1);
5423             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999)));
5424             sysTime.roll!"seconds"(1);
5425             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
5426         }
5427 
5428         {
5429             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59));
5430             sysTime.roll!"seconds"(1);
5431             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0)));
5432             sysTime.roll!"seconds"(-1);
5433             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59)));
5434         }
5435 
5436         {
5437             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5438             sysTime.roll!"seconds"(1);
5439             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0), hnsecs(9_999_999)));
5440             sysTime.roll!"seconds"(-1);
5441             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5442         }
5443 
5444         {
5445             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5446             sysTime.roll!"seconds"(1).roll!"seconds"(-102);
5447             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 18), hnsecs(9_999_999)));
5448         }
5449 
5450         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5451         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5452         static assert(!__traits(compiles, cst.roll!"seconds"(4)));
5453         //static assert(!__traits(compiles, ist.roll!"seconds"(4)));
5454     }
5455 
5456 
5457     // Shares documentation with "days" version.
5458     ref SysTime roll(string units)(long value) @safe nothrow
5459         if (units == "msecs" || units == "usecs" || units == "hnsecs")
5460     {
5461         auto hnsecs = adjTime;
5462         immutable days = splitUnitsFromHNSecs!"days"(hnsecs);
5463         immutable negative = hnsecs < 0;
5464 
5465         if (negative)
5466             hnsecs += convert!("hours", "hnsecs")(24);
5467 
5468         immutable seconds = splitUnitsFromHNSecs!"seconds"(hnsecs);
5469         hnsecs += convert!(units, "hnsecs")(value);
5470         hnsecs %= convert!("seconds", "hnsecs")(1);
5471 
5472         if (hnsecs < 0)
5473             hnsecs += convert!("seconds", "hnsecs")(1);
5474         hnsecs += convert!("seconds", "hnsecs")(seconds);
5475 
5476         if (negative)
5477             hnsecs -= convert!("hours", "hnsecs")(24);
5478 
5479         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
5480         adjTime = newDaysHNSecs + hnsecs;
5481         return this;
5482     }
5483 
5484 
5485     // Test roll!"msecs"().
5486     @safe unittest
5487     {
5488         static void testST(SysTime orig, int milliseconds, in SysTime expected, size_t line = __LINE__)
5489         {
5490             orig.roll!"msecs"(milliseconds);
5491             if (orig != expected)
5492                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5493         }
5494 
5495         // Test A.D.
5496         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274));
5497         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5498         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275)));
5499         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(276)));
5500         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(284)));
5501         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(374)));
5502         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5503         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5504         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5505         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275)));
5506         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5507         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5508         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5509         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(1)));
5510         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5511         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5512 
5513         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273)));
5514         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(272)));
5515         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(264)));
5516         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(174)));
5517         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5518         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5519         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5520         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273)));
5521         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5522         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5523         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5524         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5525         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5526 
5527         // Test B.C.
5528         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274));
5529         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5530         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275)));
5531         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(276)));
5532         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(284)));
5533         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(374)));
5534         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5535         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5536         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5537         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275)));
5538         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5539         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5540         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5541         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(1)));
5542         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5543         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5544 
5545         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273)));
5546         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(272)));
5547         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(264)));
5548         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(174)));
5549         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5550         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5551         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5552         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273)));
5553         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5554         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5555         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5556         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5557         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5558 
5559         // Test Both
5560         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5561         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(1)));
5562         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5563         testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(999)));
5564         testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(998)));
5565         testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5566         testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5567         testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(445)));
5568 
5569         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5570         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_989_999)));
5571         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5572         testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999)));
5573         testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999)));
5574         testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5575         testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5576         testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(5_549_999)));
5577 
5578         {
5579             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5580             st.roll!"msecs"(1202).roll!"msecs"(-703);
5581             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(4_989_999)));
5582         }
5583 
5584         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5585         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5586         static assert(!__traits(compiles, cst.addMSecs(4)));
5587         //static assert(!__traits(compiles, ist.addMSecs(4)));
5588     }
5589 
5590     // Test roll!"usecs"().
5591     @safe unittest
5592     {
5593         static void testST(SysTime orig, long microseconds, in SysTime expected, size_t line = __LINE__)
5594         {
5595             orig.roll!"usecs"(microseconds);
5596             if (orig != expected)
5597                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5598         }
5599 
5600         // Test A.D.
5601         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274));
5602         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5603         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(275)));
5604         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(276)));
5605         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(284)));
5606         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(374)));
5607         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999)));
5608         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1000)));
5609         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1274)));
5610         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1275)));
5611         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(2274)));
5612         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(26_999)));
5613         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_000)));
5614         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_001)));
5615         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(766_999)));
5616         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(767_000)));
5617         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5618         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5619         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5620 
5621         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(273)));
5622         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(272)));
5623         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(264)));
5624         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(174)));
5625         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5626         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_999)));
5627         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_274)));
5628         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_273)));
5629         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(998_274)));
5630         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(967_000)));
5631         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(966_999)));
5632         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(167_000)));
5633         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(166_999)));
5634         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5635         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5636         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
5637 
5638         // Test B.C.
5639         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274));
5640         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
5641         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(275)));
5642         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(276)));
5643         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(284)));
5644         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(374)));
5645         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999)));
5646         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1000)));
5647         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1274)));
5648         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1275)));
5649         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(2274)));
5650         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(26_999)));
5651         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_000)));
5652         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_001)));
5653         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(766_999)));
5654         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(767_000)));
5655         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
5656         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
5657         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
5658 
5659         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(273)));
5660         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(272)));
5661         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(264)));
5662         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(174)));
5663         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5664         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_999)));
5665         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_274)));
5666         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_273)));
5667         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(998_274)));
5668         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(967_000)));
5669         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(966_999)));
5670         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(167_000)));
5671         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(166_999)));
5672         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
5673         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
5674         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
5675 
5676         // Test Both
5677         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5678         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(1)));
5679         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5680         testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_999)));
5681         testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_998)));
5682         testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_000)));
5683         testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(998_000)));
5684         testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(997_445)));
5685         testST(beforeBoth1, -1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5686         testST(beforeBoth1, -2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5687         testST(beforeBoth1, -2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(666_667)));
5688 
5689         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5690         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_989)));
5691         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5692         testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9)));
5693         testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19)));
5694         testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999)));
5695         testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999)));
5696         testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(25_549)));
5697         testST(beforeBoth2, 1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5698         testST(beforeBoth2, 2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5699         testST(beforeBoth2, 2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(3_333_329)));
5700 
5701         {
5702             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5703             st.roll!"usecs"(9_020_027);
5704             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(200_269)));
5705         }
5706 
5707         {
5708             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5709             st.roll!"usecs"(9_020_027).roll!"usecs"(-70_034);
5710             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_499_929)));
5711         }
5712 
5713         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5714         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5715         static assert(!__traits(compiles, cst.roll!"usecs"(4)));
5716         //static assert(!__traits(compiles, ist.roll!"usecs"(4)));
5717     }
5718 
5719     // Test roll!"hnsecs"().
5720     @safe unittest
5721     {
5722         static void testST(SysTime orig, long hnsecs, in SysTime expected, size_t line = __LINE__)
5723         {
5724             orig.roll!"hnsecs"(hnsecs);
5725             if (orig != expected)
5726                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5727         }
5728 
5729         // Test A.D.
5730         auto dtAD = DateTime(1999, 7, 6, 12, 30, 33);
5731         auto beforeAD = SysTime(dtAD, hnsecs(274));
5732         testST(beforeAD, 0, SysTime(dtAD, hnsecs(274)));
5733         testST(beforeAD, 1, SysTime(dtAD, hnsecs(275)));
5734         testST(beforeAD, 2, SysTime(dtAD, hnsecs(276)));
5735         testST(beforeAD, 10, SysTime(dtAD, hnsecs(284)));
5736         testST(beforeAD, 100, SysTime(dtAD, hnsecs(374)));
5737         testST(beforeAD, 725, SysTime(dtAD, hnsecs(999)));
5738         testST(beforeAD, 726, SysTime(dtAD, hnsecs(1000)));
5739         testST(beforeAD, 1000, SysTime(dtAD, hnsecs(1274)));
5740         testST(beforeAD, 1001, SysTime(dtAD, hnsecs(1275)));
5741         testST(beforeAD, 2000, SysTime(dtAD, hnsecs(2274)));
5742         testST(beforeAD, 26_725, SysTime(dtAD, hnsecs(26_999)));
5743         testST(beforeAD, 26_726, SysTime(dtAD, hnsecs(27_000)));
5744         testST(beforeAD, 26_727, SysTime(dtAD, hnsecs(27_001)));
5745         testST(beforeAD, 1_766_725, SysTime(dtAD, hnsecs(1_766_999)));
5746         testST(beforeAD, 1_766_726, SysTime(dtAD, hnsecs(1_767_000)));
5747         testST(beforeAD, 1_000_000, SysTime(dtAD, hnsecs(1_000_274)));
5748         testST(beforeAD, 60_000_000L, SysTime(dtAD, hnsecs(274)));
5749         testST(beforeAD, 3_600_000_000L, SysTime(dtAD, hnsecs(274)));
5750         testST(beforeAD, 600_000_000L, SysTime(dtAD, hnsecs(274)));
5751         testST(beforeAD, 36_000_000_000L, SysTime(dtAD, hnsecs(274)));
5752 
5753         testST(beforeAD, -1, SysTime(dtAD, hnsecs(273)));
5754         testST(beforeAD, -2, SysTime(dtAD, hnsecs(272)));
5755         testST(beforeAD, -10, SysTime(dtAD, hnsecs(264)));
5756         testST(beforeAD, -100, SysTime(dtAD, hnsecs(174)));
5757         testST(beforeAD, -274, SysTime(dtAD));
5758         testST(beforeAD, -275, SysTime(dtAD, hnsecs(9_999_999)));
5759         testST(beforeAD, -1000, SysTime(dtAD, hnsecs(9_999_274)));
5760         testST(beforeAD, -1001, SysTime(dtAD, hnsecs(9_999_273)));
5761         testST(beforeAD, -2000, SysTime(dtAD, hnsecs(9_998_274)));
5762         testST(beforeAD, -33_274, SysTime(dtAD, hnsecs(9_967_000)));
5763         testST(beforeAD, -33_275, SysTime(dtAD, hnsecs(9_966_999)));
5764         testST(beforeAD, -1_833_274, SysTime(dtAD, hnsecs(8_167_000)));
5765         testST(beforeAD, -1_833_275, SysTime(dtAD, hnsecs(8_166_999)));
5766         testST(beforeAD, -1_000_000, SysTime(dtAD, hnsecs(9_000_274)));
5767         testST(beforeAD, -60_000_000L, SysTime(dtAD, hnsecs(274)));
5768         testST(beforeAD, -3_600_000_000L, SysTime(dtAD, hnsecs(274)));
5769         testST(beforeAD, -600_000_000L, SysTime(dtAD, hnsecs(274)));
5770         testST(beforeAD, -36_000_000_000L, SysTime(dtAD, hnsecs(274)));
5771 
5772         // Test B.C.
5773         auto dtBC = DateTime(-1999, 7, 6, 12, 30, 33);
5774         auto beforeBC = SysTime(dtBC, hnsecs(274));
5775         testST(beforeBC, 0, SysTime(dtBC, hnsecs(274)));
5776         testST(beforeBC, 1, SysTime(dtBC, hnsecs(275)));
5777         testST(beforeBC, 2, SysTime(dtBC, hnsecs(276)));
5778         testST(beforeBC, 10, SysTime(dtBC, hnsecs(284)));
5779         testST(beforeBC, 100, SysTime(dtBC, hnsecs(374)));
5780         testST(beforeBC, 725, SysTime(dtBC, hnsecs(999)));
5781         testST(beforeBC, 726, SysTime(dtBC, hnsecs(1000)));
5782         testST(beforeBC, 1000, SysTime(dtBC, hnsecs(1274)));
5783         testST(beforeBC, 1001, SysTime(dtBC, hnsecs(1275)));
5784         testST(beforeBC, 2000, SysTime(dtBC, hnsecs(2274)));
5785         testST(beforeBC, 26_725, SysTime(dtBC, hnsecs(26_999)));
5786         testST(beforeBC, 26_726, SysTime(dtBC, hnsecs(27_000)));
5787         testST(beforeBC, 26_727, SysTime(dtBC, hnsecs(27_001)));
5788         testST(beforeBC, 1_766_725, SysTime(dtBC, hnsecs(1_766_999)));
5789         testST(beforeBC, 1_766_726, SysTime(dtBC, hnsecs(1_767_000)));
5790         testST(beforeBC, 1_000_000, SysTime(dtBC, hnsecs(1_000_274)));
5791         testST(beforeBC, 60_000_000L, SysTime(dtBC, hnsecs(274)));
5792         testST(beforeBC, 3_600_000_000L, SysTime(dtBC, hnsecs(274)));
5793         testST(beforeBC, 600_000_000L, SysTime(dtBC, hnsecs(274)));
5794         testST(beforeBC, 36_000_000_000L, SysTime(dtBC, hnsecs(274)));
5795 
5796         testST(beforeBC, -1, SysTime(dtBC, hnsecs(273)));
5797         testST(beforeBC, -2, SysTime(dtBC, hnsecs(272)));
5798         testST(beforeBC, -10, SysTime(dtBC, hnsecs(264)));
5799         testST(beforeBC, -100, SysTime(dtBC, hnsecs(174)));
5800         testST(beforeBC, -274, SysTime(dtBC));
5801         testST(beforeBC, -275, SysTime(dtBC, hnsecs(9_999_999)));
5802         testST(beforeBC, -1000, SysTime(dtBC, hnsecs(9_999_274)));
5803         testST(beforeBC, -1001, SysTime(dtBC, hnsecs(9_999_273)));
5804         testST(beforeBC, -2000, SysTime(dtBC, hnsecs(9_998_274)));
5805         testST(beforeBC, -33_274, SysTime(dtBC, hnsecs(9_967_000)));
5806         testST(beforeBC, -33_275, SysTime(dtBC, hnsecs(9_966_999)));
5807         testST(beforeBC, -1_833_274, SysTime(dtBC, hnsecs(8_167_000)));
5808         testST(beforeBC, -1_833_275, SysTime(dtBC, hnsecs(8_166_999)));
5809         testST(beforeBC, -1_000_000, SysTime(dtBC, hnsecs(9_000_274)));
5810         testST(beforeBC, -60_000_000L, SysTime(dtBC, hnsecs(274)));
5811         testST(beforeBC, -3_600_000_000L, SysTime(dtBC, hnsecs(274)));
5812         testST(beforeBC, -600_000_000L, SysTime(dtBC, hnsecs(274)));
5813         testST(beforeBC, -36_000_000_000L, SysTime(dtBC, hnsecs(274)));
5814 
5815         // Test Both
5816         auto dtBoth1 = DateTime(1, 1, 1, 0, 0, 0);
5817         auto beforeBoth1 = SysTime(dtBoth1);
5818         testST(beforeBoth1, 1, SysTime(dtBoth1, hnsecs(1)));
5819         testST(beforeBoth1, 0, SysTime(dtBoth1));
5820         testST(beforeBoth1, -1, SysTime(dtBoth1, hnsecs(9_999_999)));
5821         testST(beforeBoth1, -2, SysTime(dtBoth1, hnsecs(9_999_998)));
5822         testST(beforeBoth1, -1000, SysTime(dtBoth1, hnsecs(9_999_000)));
5823         testST(beforeBoth1, -2000, SysTime(dtBoth1, hnsecs(9_998_000)));
5824         testST(beforeBoth1, -2555, SysTime(dtBoth1, hnsecs(9_997_445)));
5825         testST(beforeBoth1, -1_000_000, SysTime(dtBoth1, hnsecs(9_000_000)));
5826         testST(beforeBoth1, -2_000_000, SysTime(dtBoth1, hnsecs(8_000_000)));
5827         testST(beforeBoth1, -2_333_333, SysTime(dtBoth1, hnsecs(7_666_667)));
5828         testST(beforeBoth1, -10_000_000, SysTime(dtBoth1));
5829         testST(beforeBoth1, -20_000_000, SysTime(dtBoth1));
5830         testST(beforeBoth1, -20_888_888, SysTime(dtBoth1, hnsecs(9_111_112)));
5831 
5832         auto dtBoth2 = DateTime(0, 12, 31, 23, 59, 59);
5833         auto beforeBoth2 = SysTime(dtBoth2, hnsecs(9_999_999));
5834         testST(beforeBoth2, -1, SysTime(dtBoth2, hnsecs(9_999_998)));
5835         testST(beforeBoth2, 0, SysTime(dtBoth2, hnsecs(9_999_999)));
5836         testST(beforeBoth2, 1, SysTime(dtBoth2));
5837         testST(beforeBoth2, 2, SysTime(dtBoth2, hnsecs(1)));
5838         testST(beforeBoth2, 1000, SysTime(dtBoth2, hnsecs(999)));
5839         testST(beforeBoth2, 2000, SysTime(dtBoth2, hnsecs(1999)));
5840         testST(beforeBoth2, 2555, SysTime(dtBoth2, hnsecs(2554)));
5841         testST(beforeBoth2, 1_000_000, SysTime(dtBoth2, hnsecs(999_999)));
5842         testST(beforeBoth2, 2_000_000, SysTime(dtBoth2, hnsecs(1_999_999)));
5843         testST(beforeBoth2, 2_333_333, SysTime(dtBoth2, hnsecs(2_333_332)));
5844         testST(beforeBoth2, 10_000_000, SysTime(dtBoth2, hnsecs(9_999_999)));
5845         testST(beforeBoth2, 20_000_000, SysTime(dtBoth2, hnsecs(9_999_999)));
5846         testST(beforeBoth2, 20_888_888, SysTime(dtBoth2, hnsecs(888_887)));
5847 
5848         {
5849             auto st = SysTime(dtBoth2, hnsecs(9_999_999));
5850             st.roll!"hnsecs"(70_777_222).roll!"hnsecs"(-222_555_292);
5851             assert(st == SysTime(dtBoth2, hnsecs(8_221_929)));
5852         }
5853 
5854         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5855         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5856         static assert(!__traits(compiles, cst.roll!"hnsecs"(4)));
5857         //static assert(!__traits(compiles, ist.roll!"hnsecs"(4)));
5858     }
5859 
5860 
5861     /++
5862         Gives the result of adding or subtracting a $(REF Duration, core,time)
5863         from this $(LREF SysTime).
5864 
5865         The legal types of arithmetic for $(LREF SysTime) using this operator
5866         are
5867 
5868         $(BOOKTABLE,
5869         $(TR $(TD SysTime) $(TD +) $(TD Duration) $(TD -->) $(TD SysTime))
5870         $(TR $(TD SysTime) $(TD -) $(TD Duration) $(TD -->) $(TD SysTime))
5871         )
5872 
5873         Params:
5874             duration = The $(REF Duration, core,time) to add to or subtract from
5875                        this $(LREF SysTime).
5876       +/
5877     SysTime opBinary(string op)(Duration duration) @safe const pure nothrow
5878         if (op == "+" || op == "-")
5879     {
5880         SysTime retval = SysTime(this._stdTime, this._timezone);
5881         immutable hnsecs = duration.total!"hnsecs";
5882         mixin("retval._stdTime " ~ op ~ "= hnsecs;");
5883         return retval;
5884     }
5885 
5886     ///
5887     @safe unittest
5888     {
5889         import core.time : hours, seconds;
5890         import std.datetime.date : DateTime;
5891 
5892         assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + seconds(1) ==
5893                SysTime(DateTime(2016, 1, 1, 0, 0, 0)));
5894 
5895         assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + hours(1) ==
5896                SysTime(DateTime(2016, 1, 1, 0, 59, 59)));
5897 
5898         assert(SysTime(DateTime(2016, 1, 1, 0, 0, 0)) - seconds(1) ==
5899                SysTime(DateTime(2015, 12, 31, 23, 59, 59)));
5900 
5901         assert(SysTime(DateTime(2016, 1, 1, 0, 59, 59)) - hours(1) ==
5902                SysTime(DateTime(2015, 12, 31, 23, 59, 59)));
5903     }
5904 
5905     @safe unittest
5906     {
5907         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_678));
5908 
5909         assert(st + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
5910         assert(st + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
5911         assert(st + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
5912         assert(st + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
5913         assert(st + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
5914         assert(st + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
5915         assert(st + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
5916         assert(st + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
5917         assert(st + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
5918         assert(st + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
5919         assert(st + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
5920         assert(st + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
5921         assert(st + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
5922         assert(st + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
5923         assert(st + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
5924         assert(st + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671)));
5925 
5926         assert(st - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
5927         assert(st - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
5928         assert(st - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
5929         assert(st - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
5930         assert(st - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
5931         assert(st - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
5932         assert(st - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
5933         assert(st - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
5934         assert(st - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
5935         assert(st - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
5936         assert(st - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
5937         assert(st - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
5938         assert(st - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
5939         assert(st - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
5940         assert(st - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
5941         assert(st - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671)));
5942 
5943         static void testST(in SysTime orig, long hnsecs, in SysTime expected, size_t line = __LINE__)
5944         {
5945             auto result = orig + dur!"hnsecs"(hnsecs);
5946             if (result != expected)
5947                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", result, expected), __FILE__, line);
5948         }
5949 
5950         // Test A.D.
5951         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
5952         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
5953         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
5954         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
5955         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
5956         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
5957         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
5958         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
5959         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
5960         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
5961         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
5962         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
5963         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
5964         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
5965         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
5966         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
5967         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
5968         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
5969         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
5970         testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
5971         testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
5972 
5973         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
5974         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
5975         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
5976         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
5977         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5978         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
5979         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
5980         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
5981         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
5982         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
5983         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
5984         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
5985         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
5986         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
5987         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
5988         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
5989         testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
5990         testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
5991 
5992         // Test B.C.
5993         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
5994         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
5995         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
5996         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
5997         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
5998         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
5999         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
6000         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6001         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6002         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6003         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6004         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6005         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6006         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6007         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6008         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6009         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6010         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
6011         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
6012         testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
6013         testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
6014 
6015         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
6016         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
6017         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
6018         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
6019         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6020         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6021         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6022         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6023         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6024         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6025         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6026         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6027         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6028         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6029         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
6030         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
6031         testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
6032         testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
6033 
6034         // Test Both
6035         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6036         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6037         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6038         testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6039         testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6040         testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
6041         testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
6042         testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
6043         testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
6044         testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
6045         testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
6046         testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6047         testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
6048         testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
6049 
6050         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6051         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6052         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6053         testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6054         testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6055         testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
6056         testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
6057         testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
6058         testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
6059         testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
6060         testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
6061         testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6062         testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
6063         testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887)));
6064 
6065         auto duration = dur!"seconds"(12);
6066         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6067         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6068         assert(cst + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45)));
6069         //assert(ist + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45)));
6070         assert(cst - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21)));
6071         //assert(ist - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21)));
6072     }
6073 
6074 
6075     /++
6076         Gives the result of adding or subtracting a $(REF Duration, core,time) from
6077         this $(LREF SysTime), as well as assigning the result to this
6078         $(LREF SysTime).
6079 
6080         The legal types of arithmetic for $(LREF SysTime) using this operator are
6081 
6082         $(BOOKTABLE,
6083         $(TR $(TD SysTime) $(TD +) $(TD Duration) $(TD -->) $(TD SysTime))
6084         $(TR $(TD SysTime) $(TD -) $(TD Duration) $(TD -->) $(TD SysTime))
6085         )
6086 
6087         Params:
6088             duration = The $(REF Duration, core,time) to add to or subtract from
6089                        this $(LREF SysTime).
6090       +/
6091     ref SysTime opOpAssign(string op)(Duration duration) @safe pure nothrow
6092         if (op == "+" || op == "-")
6093     {
6094         immutable hnsecs = duration.total!"hnsecs";
6095         mixin("_stdTime " ~ op ~ "= hnsecs;");
6096         return this;
6097     }
6098 
6099     @safe unittest
6100     {
6101         auto before = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6102         assert(before + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
6103         assert(before + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
6104         assert(before + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
6105         assert(before + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
6106 
6107         assert(before + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
6108         assert(before + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
6109         assert(before + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
6110         assert(before + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
6111         assert(before + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
6112         assert(before + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
6113         assert(before + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
6114         assert(before + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
6115         assert(before + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
6116         assert(before + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
6117         assert(before + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
6118         assert(before + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
6119 
6120         assert(before - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
6121         assert(before - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
6122         assert(before - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
6123         assert(before - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
6124 
6125         assert(before - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
6126         assert(before - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
6127         assert(before - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
6128         assert(before - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
6129         assert(before - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
6130         assert(before - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
6131         assert(before - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
6132         assert(before - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
6133         assert(before - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
6134         assert(before - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
6135         assert(before - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
6136         assert(before - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
6137 
6138         static void testST(SysTime orig, long hnsecs, in SysTime expected, size_t line = __LINE__)
6139         {
6140             auto r = orig += dur!"hnsecs"(hnsecs);
6141             if (orig != expected)
6142                 throw new AssertError(format("Failed 1. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
6143             if (r != expected)
6144                 throw new AssertError(format("Failed 2. actual [%s] != expected [%s]", r, expected), __FILE__, line);
6145         }
6146 
6147         // Test A.D.
6148         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
6149         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
6150         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
6151         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
6152         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
6153         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
6154         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
6155         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6156         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6157         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6158         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6159         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6160         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6161         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6162         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6163         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6164         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6165         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
6166         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
6167         testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
6168         testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
6169 
6170         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
6171         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
6172         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
6173         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
6174         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
6175         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6176         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6177         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6178         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6179         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6180         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6181         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6182         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6183         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6184         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
6185         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
6186         testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
6187         testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
6188 
6189         // Test B.C.
6190         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
6191         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
6192         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
6193         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
6194         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
6195         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
6196         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
6197         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6198         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6199         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6200         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6201         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6202         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6203         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6204         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6205         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6206         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6207         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
6208         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
6209         testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
6210         testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
6211 
6212         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
6213         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
6214         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
6215         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
6216         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6217         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6218         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6219         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6220         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6221         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6222         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6223         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6224         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6225         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6226         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
6227         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
6228         testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
6229         testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
6230 
6231         // Test Both
6232         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6233         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6234         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6235         testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6236         testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6237         testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
6238         testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
6239         testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
6240         testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
6241         testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
6242         testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
6243         testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6244         testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
6245         testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
6246 
6247         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6248         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6249         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6250         testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6251         testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6252         testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
6253         testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
6254         testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
6255         testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
6256         testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
6257         testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
6258         testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6259         testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
6260         testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887)));
6261 
6262         {
6263             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6264             (st += dur!"hnsecs"(52)) += dur!"seconds"(-907);
6265             assert(st == SysTime(DateTime(0, 12, 31, 23, 44, 53), hnsecs(51)));
6266         }
6267 
6268         auto duration = dur!"seconds"(12);
6269         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6270         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6271         static assert(!__traits(compiles, cst += duration));
6272         //static assert(!__traits(compiles, ist += duration));
6273         static assert(!__traits(compiles, cst -= duration));
6274         //static assert(!__traits(compiles, ist -= duration));
6275     }
6276 
6277 
6278     /++
6279         Gives the difference between two $(LREF SysTime)s.
6280 
6281         The legal types of arithmetic for $(LREF SysTime) using this operator
6282         are
6283 
6284         $(BOOKTABLE,
6285         $(TR $(TD SysTime) $(TD -) $(TD SysTime) $(TD -->) $(TD duration))
6286         )
6287       +/
6288     Duration opBinary(string op)(in SysTime rhs) @safe const pure nothrow
6289         if (op == "-")
6290     {
6291         return dur!"hnsecs"(_stdTime - rhs._stdTime);
6292     }
6293 
6294     @safe unittest
6295     {
6296         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1998, 7, 6, 12, 30, 33)) ==
6297                dur!"seconds"(31_536_000));
6298         assert(SysTime(DateTime(1998, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6299                dur!"seconds"(-31_536_000));
6300 
6301         assert(SysTime(DateTime(1999, 8, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6302                dur!"seconds"(26_78_400));
6303         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 8, 6, 12, 30, 33)) ==
6304                dur!"seconds"(-26_78_400));
6305 
6306         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 5, 12, 30, 33)) ==
6307                dur!"seconds"(86_400));
6308         assert(SysTime(DateTime(1999, 7, 5, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6309                dur!"seconds"(-86_400));
6310 
6311         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 11, 30, 33)) ==
6312                dur!"seconds"(3600));
6313         assert(SysTime(DateTime(1999, 7, 6, 11, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6314                dur!"seconds"(-3600));
6315 
6316         assert(SysTime(DateTime(1999, 7, 6, 12, 31, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6317                dur!"seconds"(60));
6318         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 31, 33)) ==
6319                dur!"seconds"(-60));
6320 
6321         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 34)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6322                dur!"seconds"(1));
6323         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 34)) ==
6324                dur!"seconds"(-1));
6325 
6326         {
6327             auto dt = DateTime(1999, 7, 6, 12, 30, 33);
6328             assert(SysTime(dt, msecs(532)) - SysTime(dt) == msecs(532));
6329             assert(SysTime(dt) - SysTime(dt, msecs(532)) == msecs(-532));
6330 
6331             assert(SysTime(dt, usecs(333_347)) - SysTime(dt) == usecs(333_347));
6332             assert(SysTime(dt) - SysTime(dt, usecs(333_347)) == usecs(-333_347));
6333 
6334             assert(SysTime(dt, hnsecs(1_234_567)) - SysTime(dt) == hnsecs(1_234_567));
6335             assert(SysTime(dt) - SysTime(dt, hnsecs(1_234_567)) == hnsecs(-1_234_567));
6336         }
6337 
6338         assert(SysTime(DateTime(1, 1, 1, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(45033));
6339         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(1, 1, 1, 12, 30, 33)) == dur!"seconds"(-45033));
6340         assert(SysTime(DateTime(0, 12, 31, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(-41367));
6341         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 12, 30, 33)) == dur!"seconds"(41367));
6342 
6343         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) ==
6344                dur!"hnsecs"(1));
6345         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) ==
6346                dur!"hnsecs"(-1));
6347 
6348         version (Posix)
6349             immutable tz = PosixTimeZone.getTimeZone("America/Los_Angeles");
6350         else version (Windows)
6351             immutable tz = WindowsTimeZone.getTimeZone("Pacific Standard Time");
6352 
6353         {
6354             auto dt = DateTime(2011, 1, 13, 8, 17, 2);
6355             auto d = msecs(296);
6356             assert(SysTime(dt, d, tz) - SysTime(dt, d, tz) == Duration.zero);
6357             assert(SysTime(dt, d, tz) - SysTime(dt, d, UTC()) == hours(8));
6358             assert(SysTime(dt, d, UTC()) - SysTime(dt, d, tz) == hours(-8));
6359         }
6360 
6361         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6362         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6363         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6364         assert(st - st == Duration.zero);
6365         assert(cst - st == Duration.zero);
6366         //assert(ist - st == Duration.zero);
6367 
6368         assert(st - cst == Duration.zero);
6369         assert(cst - cst == Duration.zero);
6370         //assert(ist - cst == Duration.zero);
6371 
6372         //assert(st - ist == Duration.zero);
6373         //assert(cst - ist == Duration.zero);
6374         //assert(ist - ist == Duration.zero);
6375     }
6376 
6377 
6378     /++
6379         Returns the difference between the two $(LREF SysTime)s in months.
6380 
6381         To get the difference in years, subtract the year property
6382         of two $(LREF SysTime)s. To get the difference in days or weeks,
6383         subtract the $(LREF SysTime)s themselves and use the
6384         $(REF Duration, core,time) that results. Because converting between
6385         months and smaller units requires a specific date (which
6386         $(REF Duration, core,time)s don't have), getting the difference in
6387         months requires some math using both the year and month properties, so
6388         this is a convenience function for getting the difference in months.
6389 
6390         Note that the number of days in the months or how far into the month
6391         either date is is irrelevant. It is the difference in the month property
6392         combined with the difference in years * 12. So, for instance,
6393         December 31st and January 1st are one month apart just as December 1st
6394         and January 31st are one month apart.
6395 
6396         Params:
6397             rhs = The $(LREF SysTime) to subtract from this one.
6398       +/
6399     int diffMonths(in SysTime rhs) @safe const nothrow
6400     {
6401         return (cast(Date) this).diffMonths(cast(Date) rhs);
6402     }
6403 
6404     ///
6405     @safe unittest
6406     {
6407         import std.datetime.date : Date;
6408 
6409         assert(SysTime(Date(1999, 2, 1)).diffMonths(
6410                    SysTime(Date(1999, 1, 31))) == 1);
6411 
6412         assert(SysTime(Date(1999, 1, 31)).diffMonths(
6413                    SysTime(Date(1999, 2, 1))) == -1);
6414 
6415         assert(SysTime(Date(1999, 3, 1)).diffMonths(
6416                    SysTime(Date(1999, 1, 1))) == 2);
6417 
6418         assert(SysTime(Date(1999, 1, 1)).diffMonths(
6419                    SysTime(Date(1999, 3, 31))) == -2);
6420     }
6421 
6422     @safe unittest
6423     {
6424         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6425         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6426         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6427         assert(st.diffMonths(st) == 0);
6428         assert(cst.diffMonths(st) == 0);
6429         //assert(ist.diffMonths(st) == 0);
6430 
6431         assert(st.diffMonths(cst) == 0);
6432         assert(cst.diffMonths(cst) == 0);
6433         //assert(ist.diffMonths(cst) == 0);
6434 
6435         //assert(st.diffMonths(ist) == 0);
6436         //assert(cst.diffMonths(ist) == 0);
6437         //assert(ist.diffMonths(ist) == 0);
6438     }
6439 
6440 
6441     /++
6442         Whether this $(LREF SysTime) is in a leap year.
6443      +/
6444     @property bool isLeapYear() @safe const nothrow
6445     {
6446         return (cast(Date) this).isLeapYear;
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         assert(!st.isLeapYear);
6455         assert(!cst.isLeapYear);
6456         //assert(!ist.isLeapYear);
6457     }
6458 
6459 
6460     /++
6461         Day of the week this $(LREF SysTime) is on.
6462       +/
6463     @property DayOfWeek dayOfWeek() @safe const nothrow
6464     {
6465         return getDayOfWeek(dayOfGregorianCal);
6466     }
6467 
6468     @safe unittest
6469     {
6470         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6471         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6472         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6473         assert(st.dayOfWeek == DayOfWeek.tue);
6474         assert(cst.dayOfWeek == DayOfWeek.tue);
6475         //assert(ist.dayOfWeek == DayOfWeek.tue);
6476     }
6477 
6478 
6479     /++
6480         Day of the year this $(LREF SysTime) is on.
6481       +/
6482     @property ushort dayOfYear() @safe const nothrow
6483     {
6484         return (cast(Date) this).dayOfYear;
6485     }
6486 
6487     ///
6488     @safe unittest
6489     {
6490         import std.datetime.date : DateTime;
6491 
6492         assert(SysTime(DateTime(1999, 1, 1, 12, 22, 7)).dayOfYear == 1);
6493         assert(SysTime(DateTime(1999, 12, 31, 7, 2, 59)).dayOfYear == 365);
6494         assert(SysTime(DateTime(2000, 12, 31, 21, 20, 0)).dayOfYear == 366);
6495     }
6496 
6497     @safe unittest
6498     {
6499         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6500         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6501         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6502         assert(st.dayOfYear == 187);
6503         assert(cst.dayOfYear == 187);
6504         //assert(ist.dayOfYear == 187);
6505     }
6506 
6507 
6508     /++
6509         Day of the year.
6510 
6511         Params:
6512             day = The day of the year to set which day of the year this
6513                   $(LREF SysTime) is on.
6514       +/
6515     @property void dayOfYear(int day) @safe
6516     {
6517         immutable hnsecs = adjTime;
6518         immutable days = convert!("hnsecs", "days")(hnsecs);
6519         immutable theRest = hnsecs - convert!("days", "hnsecs")(days);
6520 
6521         auto date = Date(cast(int) days);
6522         date.dayOfYear = day;
6523 
6524         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
6525 
6526         adjTime = newDaysHNSecs + theRest;
6527     }
6528 
6529     @safe unittest
6530     {
6531         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6532         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6533         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6534         st.dayOfYear = 12;
6535         assert(st.dayOfYear == 12);
6536         static assert(!__traits(compiles, cst.dayOfYear = 12));
6537         //static assert(!__traits(compiles, ist.dayOfYear = 12));
6538     }
6539 
6540 
6541     /++
6542         The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on.
6543      +/
6544     @property int dayOfGregorianCal() @safe const nothrow
6545     {
6546         immutable adjustedTime = adjTime;
6547 
6548         // We have to add one because 0 would be midnight, January 1st, 1 A.D.,
6549         // which would be the 1st day of the Gregorian Calendar, not the 0th. So,
6550         // simply casting to days is one day off.
6551         if (adjustedTime > 0)
6552             return cast(int) getUnitsFromHNSecs!"days"(adjustedTime) + 1;
6553 
6554         long hnsecs = adjustedTime;
6555         immutable days = cast(int) splitUnitsFromHNSecs!"days"(hnsecs);
6556 
6557         return hnsecs == 0 ? days + 1 : days;
6558     }
6559 
6560     ///
6561     @safe unittest
6562     {
6563         import std.datetime.date : DateTime;
6564 
6565         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
6566         assert(SysTime(DateTime(1, 12, 31, 23, 59, 59)).dayOfGregorianCal == 365);
6567         assert(SysTime(DateTime(2, 1, 1, 2, 2, 2)).dayOfGregorianCal == 366);
6568 
6569         assert(SysTime(DateTime(0, 12, 31, 7, 7, 7)).dayOfGregorianCal == 0);
6570         assert(SysTime(DateTime(0, 1, 1, 19, 30, 0)).dayOfGregorianCal == -365);
6571         assert(SysTime(DateTime(-1, 12, 31, 4, 7, 0)).dayOfGregorianCal == -366);
6572 
6573         assert(SysTime(DateTime(2000, 1, 1, 9, 30, 20)).dayOfGregorianCal == 730_120);
6574         assert(SysTime(DateTime(2010, 12, 31, 15, 45, 50)).dayOfGregorianCal == 734_137);
6575     }
6576 
6577     @safe unittest
6578     {
6579         // Test A.D.
6580         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
6581         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 1);
6582         assert(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 1);
6583 
6584         assert(SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1);
6585         assert(SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)).dayOfGregorianCal == 2);
6586         assert(SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 32);
6587         assert(SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 366);
6588         assert(SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 731);
6589         assert(SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1096);
6590         assert(SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1462);
6591         assert(SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 17_898);
6592         assert(SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 35_065);
6593         assert(SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_160);
6594         assert(SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_525);
6595         assert(SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 37_986);
6596         assert(SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 72_684);
6597         assert(SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 73_049);
6598         assert(SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_208);
6599         assert(SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_573);
6600         assert(SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 145_732);
6601         assert(SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 146_098);
6602         assert(SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_257);
6603         assert(SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_622);
6604         assert(SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 364_878);
6605         assert(SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 365_243);
6606         assert(SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_023);
6607         assert(SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_389);
6608         assert(SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_596);
6609         assert(SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_961);
6610         assert(SysTime(DateTime(1945, 11, 12, 12, 2, 9), msecs(212)).dayOfGregorianCal == 710_347);
6611         assert(SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 729_755);
6612         assert(SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_120);
6613         assert(SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_486);
6614 
6615         assert(SysTime(DateTime(2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_773);
6616         assert(SysTime(DateTime(2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_803);
6617         assert(SysTime(DateTime(2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_804);
6618         assert(SysTime(DateTime(2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_831);
6619         assert(SysTime(DateTime(2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_832);
6620         assert(SysTime(DateTime(2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_862);
6621         assert(SysTime(DateTime(2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_863);
6622         assert(SysTime(DateTime(2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_892);
6623         assert(SysTime(DateTime(2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_893);
6624         assert(SysTime(DateTime(2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_923);
6625         assert(SysTime(DateTime(2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_924);
6626         assert(SysTime(DateTime(2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_953);
6627         assert(SysTime(DateTime(2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_954);
6628         assert(SysTime(DateTime(2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_984);
6629         assert(SysTime(DateTime(2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_985);
6630         assert(SysTime(DateTime(2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_015);
6631         assert(SysTime(DateTime(2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_016);
6632         assert(SysTime(DateTime(2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_045);
6633         assert(SysTime(DateTime(2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_046);
6634         assert(SysTime(DateTime(2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_076);
6635         assert(SysTime(DateTime(2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_077);
6636         assert(SysTime(DateTime(2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_106);
6637         assert(SysTime(DateTime(2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_107);
6638         assert(SysTime(DateTime(2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_137);
6639 
6640         assert(SysTime(DateTime(2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == 734_534);
6641         assert(SysTime(DateTime(2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == 734_561);
6642         assert(SysTime(DateTime(2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == 734_562);
6643         assert(SysTime(DateTime(2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == 734_563);
6644 
6645         // Test B.C.
6646         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 0);
6647         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == 0);
6648         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59)).dayOfGregorianCal == 0);
6649         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 0);
6650         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).dayOfGregorianCal == 0);
6651 
6652         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == -366);
6653         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == -366);
6654         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59)).dayOfGregorianCal == -366);
6655         assert(SysTime(DateTime(-1, 12, 31, 0, 0, 0)).dayOfGregorianCal == -366);
6656 
6657         assert(SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == 0);
6658         assert(SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1);
6659         assert(SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -30);
6660         assert(SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -31);
6661 
6662         assert(SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -366);
6663         assert(SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -367);
6664         assert(SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730);
6665         assert(SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731);
6666         assert(SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1095);
6667         assert(SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1096);
6668         assert(SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1460);
6669         assert(SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1461);
6670         assert(SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1826);
6671         assert(SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1827);
6672         assert(SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -2191);
6673         assert(SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -3652);
6674 
6675         assert(SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_262);
6676         assert(SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_627);
6677         assert(SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -35_794);
6678         assert(SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_160);
6679         assert(SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_524);
6680         assert(SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_889);
6681         assert(SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -37_254);
6682         assert(SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -38_715);
6683         assert(SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_413);
6684         assert(SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_778);
6685         assert(SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -109_937);
6686         assert(SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -110_302);
6687         assert(SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_097);
6688         assert(SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_462);
6689         assert(SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_827);
6690         assert(SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_621);
6691         assert(SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_986);
6692         assert(SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -183_351);
6693         assert(SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_607);
6694         assert(SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_972);
6695         assert(SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_387);
6696         assert(SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_388);
6697         assert(SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_753);
6698         assert(SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -585_118);
6699         assert(SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_325);
6700         assert(SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_690);
6701         assert(SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_484);
6702         assert(SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_485);
6703         assert(SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_850);
6704         assert(SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731_215);
6705 
6706         assert(SysTime(DateTime(-2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_502);
6707         assert(SysTime(DateTime(-2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_472);
6708         assert(SysTime(DateTime(-2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_471);
6709         assert(SysTime(DateTime(-2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_444);
6710         assert(SysTime(DateTime(-2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_443);
6711         assert(SysTime(DateTime(-2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_413);
6712         assert(SysTime(DateTime(-2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_412);
6713         assert(SysTime(DateTime(-2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_383);
6714         assert(SysTime(DateTime(-2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_382);
6715         assert(SysTime(DateTime(-2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_352);
6716         assert(SysTime(DateTime(-2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_351);
6717         assert(SysTime(DateTime(-2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_322);
6718         assert(SysTime(DateTime(-2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_321);
6719         assert(SysTime(DateTime(-2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_291);
6720         assert(SysTime(DateTime(-2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_290);
6721         assert(SysTime(DateTime(-2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_260);
6722         assert(SysTime(DateTime(-2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_259);
6723         assert(SysTime(DateTime(-2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_230);
6724         assert(SysTime(DateTime(-2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_229);
6725         assert(SysTime(DateTime(-2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_199);
6726         assert(SysTime(DateTime(-2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_198);
6727         assert(SysTime(DateTime(-2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_169);
6728         assert(SysTime(DateTime(-2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_168);
6729         assert(SysTime(DateTime(-2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_138);
6730 
6731         assert(SysTime(DateTime(-2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == -735_202);
6732         assert(SysTime(DateTime(-2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == -735_175);
6733         assert(SysTime(DateTime(-2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == -735_174);
6734         assert(SysTime(DateTime(-2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == -735_173);
6735 
6736         // Start of Hebrew Calendar
6737         assert(SysTime(DateTime(-3760, 9, 7, 0, 0, 0)).dayOfGregorianCal == -1_373_427);
6738 
6739         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6740         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6741         assert(cst.dayOfGregorianCal == 729_941);
6742         //assert(ist.dayOfGregorianCal == 729_941);
6743     }
6744 
6745 
6746     // Test that the logic for the day of the Gregorian Calendar is consistent
6747     // between Date and SysTime.
6748     @safe unittest
6749     {
6750         void test(Date date, SysTime st, size_t line = __LINE__)
6751         {
6752             if (date.dayOfGregorianCal != st.dayOfGregorianCal)
6753             {
6754                 throw new AssertError(format("Date [%s] SysTime [%s]", date.dayOfGregorianCal, st.dayOfGregorianCal),
6755                                       __FILE__, line);
6756             }
6757         }
6758 
6759         // Test A.D.
6760         test(Date(1, 1, 1), SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6761         test(Date(1, 1, 2), SysTime(DateTime(1, 1, 2, 0, 0, 0), hnsecs(500)));
6762         test(Date(1, 2, 1), SysTime(DateTime(1, 2, 1, 0, 0, 0), hnsecs(50_000)));
6763         test(Date(2, 1, 1), SysTime(DateTime(2, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6764         test(Date(3, 1, 1), SysTime(DateTime(3, 1, 1, 12, 13, 14)));
6765         test(Date(4, 1, 1), SysTime(DateTime(4, 1, 1, 12, 13, 14), hnsecs(500)));
6766         test(Date(5, 1, 1), SysTime(DateTime(5, 1, 1, 12, 13, 14), hnsecs(50_000)));
6767         test(Date(50, 1, 1), SysTime(DateTime(50, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
6768         test(Date(97, 1, 1), SysTime(DateTime(97, 1, 1, 23, 59, 59)));
6769         test(Date(100, 1, 1), SysTime(DateTime(100, 1, 1, 23, 59, 59), hnsecs(500)));
6770         test(Date(101, 1, 1), SysTime(DateTime(101, 1, 1, 23, 59, 59), hnsecs(50_000)));
6771         test(Date(105, 1, 1), SysTime(DateTime(105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
6772         test(Date(200, 1, 1), SysTime(DateTime(200, 1, 1, 0, 0, 0)));
6773         test(Date(201, 1, 1), SysTime(DateTime(201, 1, 1, 0, 0, 0), hnsecs(500)));
6774         test(Date(300, 1, 1), SysTime(DateTime(300, 1, 1, 0, 0, 0), hnsecs(50_000)));
6775         test(Date(301, 1, 1), SysTime(DateTime(301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6776         test(Date(400, 1, 1), SysTime(DateTime(400, 1, 1, 12, 13, 14)));
6777         test(Date(401, 1, 1), SysTime(DateTime(401, 1, 1, 12, 13, 14), hnsecs(500)));
6778         test(Date(500, 1, 1), SysTime(DateTime(500, 1, 1, 12, 13, 14), hnsecs(50_000)));
6779         test(Date(501, 1, 1), SysTime(DateTime(501, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
6780         test(Date(1000, 1, 1), SysTime(DateTime(1000, 1, 1, 23, 59, 59)));
6781         test(Date(1001, 1, 1), SysTime(DateTime(1001, 1, 1, 23, 59, 59), hnsecs(500)));
6782         test(Date(1600, 1, 1), SysTime(DateTime(1600, 1, 1, 23, 59, 59), hnsecs(50_000)));
6783         test(Date(1601, 1, 1), SysTime(DateTime(1601, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
6784         test(Date(1900, 1, 1), SysTime(DateTime(1900, 1, 1, 0, 0, 0)));
6785         test(Date(1901, 1, 1), SysTime(DateTime(1901, 1, 1, 0, 0, 0), hnsecs(500)));
6786         test(Date(1945, 11, 12), SysTime(DateTime(1945, 11, 12, 0, 0, 0), hnsecs(50_000)));
6787         test(Date(1999, 1, 1), SysTime(DateTime(1999, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6788         test(Date(1999, 7, 6), SysTime(DateTime(1999, 7, 6, 12, 13, 14)));
6789         test(Date(2000, 1, 1), SysTime(DateTime(2000, 1, 1, 12, 13, 14), hnsecs(500)));
6790         test(Date(2001, 1, 1), SysTime(DateTime(2001, 1, 1, 12, 13, 14), hnsecs(50_000)));
6791 
6792         test(Date(2010, 1, 1), SysTime(DateTime(2010, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
6793         test(Date(2010, 1, 31), SysTime(DateTime(2010, 1, 31, 23, 0, 0)));
6794         test(Date(2010, 2, 1), SysTime(DateTime(2010, 2, 1, 23, 59, 59), hnsecs(500)));
6795         test(Date(2010, 2, 28), SysTime(DateTime(2010, 2, 28, 23, 59, 59), hnsecs(50_000)));
6796         test(Date(2010, 3, 1), SysTime(DateTime(2010, 3, 1, 23, 59, 59), hnsecs(9_999_999)));
6797         test(Date(2010, 3, 31), SysTime(DateTime(2010, 3, 31, 0, 0, 0)));
6798         test(Date(2010, 4, 1), SysTime(DateTime(2010, 4, 1, 0, 0, 0), hnsecs(500)));
6799         test(Date(2010, 4, 30), SysTime(DateTime(2010, 4, 30, 0, 0, 0), hnsecs(50_000)));
6800         test(Date(2010, 5, 1), SysTime(DateTime(2010, 5, 1, 0, 0, 0), hnsecs(9_999_999)));
6801         test(Date(2010, 5, 31), SysTime(DateTime(2010, 5, 31, 12, 13, 14)));
6802         test(Date(2010, 6, 1), SysTime(DateTime(2010, 6, 1, 12, 13, 14), hnsecs(500)));
6803         test(Date(2010, 6, 30), SysTime(DateTime(2010, 6, 30, 12, 13, 14), hnsecs(50_000)));
6804         test(Date(2010, 7, 1), SysTime(DateTime(2010, 7, 1, 12, 13, 14), hnsecs(9_999_999)));
6805         test(Date(2010, 7, 31), SysTime(DateTime(2010, 7, 31, 23, 59, 59)));
6806         test(Date(2010, 8, 1), SysTime(DateTime(2010, 8, 1, 23, 59, 59), hnsecs(500)));
6807         test(Date(2010, 8, 31), SysTime(DateTime(2010, 8, 31, 23, 59, 59), hnsecs(50_000)));
6808         test(Date(2010, 9, 1), SysTime(DateTime(2010, 9, 1, 23, 59, 59), hnsecs(9_999_999)));
6809         test(Date(2010, 9, 30), SysTime(DateTime(2010, 9, 30, 12, 0, 0)));
6810         test(Date(2010, 10, 1), SysTime(DateTime(2010, 10, 1, 0, 12, 0), hnsecs(500)));
6811         test(Date(2010, 10, 31), SysTime(DateTime(2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
6812         test(Date(2010, 11, 1), SysTime(DateTime(2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
6813         test(Date(2010, 11, 30), SysTime(DateTime(2010, 11, 30, 0, 59, 0)));
6814         test(Date(2010, 12, 1), SysTime(DateTime(2010, 12, 1, 0, 0, 59), hnsecs(500)));
6815         test(Date(2010, 12, 31), SysTime(DateTime(2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
6816 
6817         test(Date(2012, 2, 1), SysTime(DateTime(2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
6818         test(Date(2012, 2, 28), SysTime(DateTime(2012, 2, 28, 23, 59, 0)));
6819         test(Date(2012, 2, 29), SysTime(DateTime(2012, 2, 29, 7, 7, 7), hnsecs(7)));
6820         test(Date(2012, 3, 1), SysTime(DateTime(2012, 3, 1, 7, 7, 7), hnsecs(7)));
6821 
6822         // Test B.C.
6823         test(Date(0, 12, 31), SysTime(DateTime(0, 12, 31, 0, 0, 0)));
6824         test(Date(0, 12, 30), SysTime(DateTime(0, 12, 30, 0, 0, 0), hnsecs(500)));
6825         test(Date(0, 12, 1), SysTime(DateTime(0, 12, 1, 0, 0, 0), hnsecs(50_000)));
6826         test(Date(0, 11, 30), SysTime(DateTime(0, 11, 30, 0, 0, 0), hnsecs(9_999_999)));
6827 
6828         test(Date(-1, 12, 31), SysTime(DateTime(-1, 12, 31, 12, 13, 14)));
6829         test(Date(-1, 12, 30), SysTime(DateTime(-1, 12, 30, 12, 13, 14), hnsecs(500)));
6830         test(Date(-1, 1, 1), SysTime(DateTime(-1, 1, 1, 12, 13, 14), hnsecs(50_000)));
6831         test(Date(-2, 12, 31), SysTime(DateTime(-2, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
6832         test(Date(-2, 1, 1), SysTime(DateTime(-2, 1, 1, 23, 59, 59)));
6833         test(Date(-3, 12, 31), SysTime(DateTime(-3, 12, 31, 23, 59, 59), hnsecs(500)));
6834         test(Date(-3, 1, 1), SysTime(DateTime(-3, 1, 1, 23, 59, 59), hnsecs(50_000)));
6835         test(Date(-4, 12, 31), SysTime(DateTime(-4, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6836         test(Date(-4, 1, 1), SysTime(DateTime(-4, 1, 1, 0, 0, 0)));
6837         test(Date(-5, 12, 31), SysTime(DateTime(-5, 12, 31, 0, 0, 0), hnsecs(500)));
6838         test(Date(-5, 1, 1), SysTime(DateTime(-5, 1, 1, 0, 0, 0), hnsecs(50_000)));
6839         test(Date(-9, 1, 1), SysTime(DateTime(-9, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6840 
6841         test(Date(-49, 1, 1), SysTime(DateTime(-49, 1, 1, 12, 13, 14)));
6842         test(Date(-50, 1, 1), SysTime(DateTime(-50, 1, 1, 12, 13, 14), hnsecs(500)));
6843         test(Date(-97, 1, 1), SysTime(DateTime(-97, 1, 1, 12, 13, 14), hnsecs(50_000)));
6844         test(Date(-99, 12, 31), SysTime(DateTime(-99, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
6845         test(Date(-99, 1, 1), SysTime(DateTime(-99, 1, 1, 23, 59, 59)));
6846         test(Date(-100, 1, 1), SysTime(DateTime(-100, 1, 1, 23, 59, 59), hnsecs(500)));
6847         test(Date(-101, 1, 1), SysTime(DateTime(-101, 1, 1, 23, 59, 59), hnsecs(50_000)));
6848         test(Date(-105, 1, 1), SysTime(DateTime(-105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
6849         test(Date(-200, 1, 1), SysTime(DateTime(-200, 1, 1, 0, 0, 0)));
6850         test(Date(-201, 1, 1), SysTime(DateTime(-201, 1, 1, 0, 0, 0), hnsecs(500)));
6851         test(Date(-300, 1, 1), SysTime(DateTime(-300, 1, 1, 0, 0, 0), hnsecs(50_000)));
6852         test(Date(-301, 1, 1), SysTime(DateTime(-301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6853         test(Date(-400, 12, 31), SysTime(DateTime(-400, 12, 31, 12, 13, 14)));
6854         test(Date(-400, 1, 1), SysTime(DateTime(-400, 1, 1, 12, 13, 14), hnsecs(500)));
6855         test(Date(-401, 1, 1), SysTime(DateTime(-401, 1, 1, 12, 13, 14), hnsecs(50_000)));
6856         test(Date(-499, 1, 1), SysTime(DateTime(-499, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
6857         test(Date(-500, 1, 1), SysTime(DateTime(-500, 1, 1, 23, 59, 59)));
6858         test(Date(-501, 1, 1), SysTime(DateTime(-501, 1, 1, 23, 59, 59), hnsecs(500)));
6859         test(Date(-1000, 1, 1), SysTime(DateTime(-1000, 1, 1, 23, 59, 59), hnsecs(50_000)));
6860         test(Date(-1001, 1, 1), SysTime(DateTime(-1001, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
6861         test(Date(-1599, 1, 1), SysTime(DateTime(-1599, 1, 1, 0, 0, 0)));
6862         test(Date(-1600, 12, 31), SysTime(DateTime(-1600, 12, 31, 0, 0, 0), hnsecs(500)));
6863         test(Date(-1600, 1, 1), SysTime(DateTime(-1600, 1, 1, 0, 0, 0), hnsecs(50_000)));
6864         test(Date(-1601, 1, 1), SysTime(DateTime(-1601, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6865         test(Date(-1900, 1, 1), SysTime(DateTime(-1900, 1, 1, 12, 13, 14)));
6866         test(Date(-1901, 1, 1), SysTime(DateTime(-1901, 1, 1, 12, 13, 14), hnsecs(500)));
6867         test(Date(-1999, 1, 1), SysTime(DateTime(-1999, 1, 1, 12, 13, 14), hnsecs(50_000)));
6868         test(Date(-1999, 7, 6), SysTime(DateTime(-1999, 7, 6, 12, 13, 14), hnsecs(9_999_999)));
6869         test(Date(-2000, 12, 31), SysTime(DateTime(-2000, 12, 31, 23, 59, 59)));
6870         test(Date(-2000, 1, 1), SysTime(DateTime(-2000, 1, 1, 23, 59, 59), hnsecs(500)));
6871         test(Date(-2001, 1, 1), SysTime(DateTime(-2001, 1, 1, 23, 59, 59), hnsecs(50_000)));
6872 
6873         test(Date(-2010, 1, 1), SysTime(DateTime(-2010, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
6874         test(Date(-2010, 1, 31), SysTime(DateTime(-2010, 1, 31, 0, 0, 0)));
6875         test(Date(-2010, 2, 1), SysTime(DateTime(-2010, 2, 1, 0, 0, 0), hnsecs(500)));
6876         test(Date(-2010, 2, 28), SysTime(DateTime(-2010, 2, 28, 0, 0, 0), hnsecs(50_000)));
6877         test(Date(-2010, 3, 1), SysTime(DateTime(-2010, 3, 1, 0, 0, 0), hnsecs(9_999_999)));
6878         test(Date(-2010, 3, 31), SysTime(DateTime(-2010, 3, 31, 12, 13, 14)));
6879         test(Date(-2010, 4, 1), SysTime(DateTime(-2010, 4, 1, 12, 13, 14), hnsecs(500)));
6880         test(Date(-2010, 4, 30), SysTime(DateTime(-2010, 4, 30, 12, 13, 14), hnsecs(50_000)));
6881         test(Date(-2010, 5, 1), SysTime(DateTime(-2010, 5, 1, 12, 13, 14), hnsecs(9_999_999)));
6882         test(Date(-2010, 5, 31), SysTime(DateTime(-2010, 5, 31, 23, 59, 59)));
6883         test(Date(-2010, 6, 1), SysTime(DateTime(-2010, 6, 1, 23, 59, 59), hnsecs(500)));
6884         test(Date(-2010, 6, 30), SysTime(DateTime(-2010, 6, 30, 23, 59, 59), hnsecs(50_000)));
6885         test(Date(-2010, 7, 1), SysTime(DateTime(-2010, 7, 1, 23, 59, 59), hnsecs(9_999_999)));
6886         test(Date(-2010, 7, 31), SysTime(DateTime(-2010, 7, 31, 0, 0, 0)));
6887         test(Date(-2010, 8, 1), SysTime(DateTime(-2010, 8, 1, 0, 0, 0), hnsecs(500)));
6888         test(Date(-2010, 8, 31), SysTime(DateTime(-2010, 8, 31, 0, 0, 0), hnsecs(50_000)));
6889         test(Date(-2010, 9, 1), SysTime(DateTime(-2010, 9, 1, 0, 0, 0), hnsecs(9_999_999)));
6890         test(Date(-2010, 9, 30), SysTime(DateTime(-2010, 9, 30, 12, 0, 0)));
6891         test(Date(-2010, 10, 1), SysTime(DateTime(-2010, 10, 1, 0, 12, 0), hnsecs(500)));
6892         test(Date(-2010, 10, 31), SysTime(DateTime(-2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
6893         test(Date(-2010, 11, 1), SysTime(DateTime(-2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
6894         test(Date(-2010, 11, 30), SysTime(DateTime(-2010, 11, 30, 0, 59, 0)));
6895         test(Date(-2010, 12, 1), SysTime(DateTime(-2010, 12, 1, 0, 0, 59), hnsecs(500)));
6896         test(Date(-2010, 12, 31), SysTime(DateTime(-2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
6897 
6898         test(Date(-2012, 2, 1), SysTime(DateTime(-2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
6899         test(Date(-2012, 2, 28), SysTime(DateTime(-2012, 2, 28, 23, 59, 0)));
6900         test(Date(-2012, 2, 29), SysTime(DateTime(-2012, 2, 29, 7, 7, 7), hnsecs(7)));
6901         test(Date(-2012, 3, 1), SysTime(DateTime(-2012, 3, 1, 7, 7, 7), hnsecs(7)));
6902 
6903         test(Date(-3760, 9, 7), SysTime(DateTime(-3760, 9, 7, 0, 0, 0)));
6904     }
6905 
6906 
6907     /++
6908         The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on.
6909         Setting this property does not affect the time portion of $(LREF SysTime).
6910 
6911         Params:
6912             days = The day of the Gregorian Calendar to set this $(LREF SysTime)
6913                    to.
6914      +/
6915     @property void dayOfGregorianCal(int days) @safe nothrow
6916     {
6917         auto hnsecs = adjTime;
6918         hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
6919 
6920         if (hnsecs < 0)
6921             hnsecs += convert!("hours", "hnsecs")(24);
6922 
6923         if (--days < 0)
6924         {
6925             hnsecs -= convert!("hours", "hnsecs")(24);
6926             ++days;
6927         }
6928 
6929         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
6930 
6931         adjTime = newDaysHNSecs + hnsecs;
6932     }
6933 
6934     ///
6935     @safe unittest
6936     {
6937         import std.datetime.date : DateTime;
6938 
6939         auto st = SysTime(DateTime(0, 1, 1, 12, 0, 0));
6940         st.dayOfGregorianCal = 1;
6941         assert(st == SysTime(DateTime(1, 1, 1, 12, 0, 0)));
6942 
6943         st.dayOfGregorianCal = 365;
6944         assert(st == SysTime(DateTime(1, 12, 31, 12, 0, 0)));
6945 
6946         st.dayOfGregorianCal = 366;
6947         assert(st == SysTime(DateTime(2, 1, 1, 12, 0, 0)));
6948 
6949         st.dayOfGregorianCal = 0;
6950         assert(st == SysTime(DateTime(0, 12, 31, 12, 0, 0)));
6951 
6952         st.dayOfGregorianCal = -365;
6953         assert(st == SysTime(DateTime(-0, 1, 1, 12, 0, 0)));
6954 
6955         st.dayOfGregorianCal = -366;
6956         assert(st == SysTime(DateTime(-1, 12, 31, 12, 0, 0)));
6957 
6958         st.dayOfGregorianCal = 730_120;
6959         assert(st == SysTime(DateTime(2000, 1, 1, 12, 0, 0)));
6960 
6961         st.dayOfGregorianCal = 734_137;
6962         assert(st == SysTime(DateTime(2010, 12, 31, 12, 0, 0)));
6963     }
6964 
6965     @safe unittest
6966     {
6967         void testST(SysTime orig, int day, in SysTime expected, size_t line = __LINE__)
6968         {
6969             orig.dayOfGregorianCal = day;
6970             if (orig != expected)
6971                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
6972         }
6973 
6974         // Test A.D.
6975         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6976         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6977         testST(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 1,
6978                SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
6979 
6980         // Test B.C.
6981         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
6982         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 0,
6983                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6984         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(1)), 0,
6985                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
6986         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6987 
6988         // Test Both.
6989         testST(SysTime(DateTime(-512, 7, 20, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6990         testST(SysTime(DateTime(-513, 6, 6, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6991         testST(SysTime(DateTime(-511, 5, 7, 23, 59, 59), hnsecs(9_999_999)), 1,
6992                SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
6993 
6994         testST(SysTime(DateTime(1607, 4, 8, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
6995         testST(SysTime(DateTime(1500, 3, 9, 23, 59, 59), hnsecs(9_999_999)), 0,
6996                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6997         testST(SysTime(DateTime(999, 2, 10, 23, 59, 59), hnsecs(1)), 0,
6998                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
6999         testST(SysTime(DateTime(2007, 12, 11, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
7000 
7001 
7002         auto st = SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212));
7003 
7004         void testST2(int day, in SysTime expected, size_t line = __LINE__)
7005         {
7006             st.dayOfGregorianCal = day;
7007             if (st != expected)
7008                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", st, expected), __FILE__, line);
7009         }
7010 
7011         // Test A.D.
7012         testST2(1, SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)));
7013         testST2(2, SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)));
7014         testST2(32, SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)));
7015         testST2(366, SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)));
7016         testST2(731, SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)));
7017         testST2(1096, SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)));
7018         testST2(1462, SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)));
7019         testST2(17_898, SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)));
7020         testST2(35_065, SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)));
7021         testST2(36_160, SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)));
7022         testST2(36_525, SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)));
7023         testST2(37_986, SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)));
7024         testST2(72_684, SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)));
7025         testST2(73_049, SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)));
7026         testST2(109_208, SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)));
7027         testST2(109_573, SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)));
7028         testST2(145_732, SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)));
7029         testST2(146_098, SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)));
7030         testST2(182_257, SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)));
7031         testST2(182_622, SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)));
7032         testST2(364_878, SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)));
7033         testST2(365_243, SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)));
7034         testST2(584_023, SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)));
7035         testST2(584_389, SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)));
7036         testST2(693_596, SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)));
7037         testST2(693_961, SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)));
7038         testST2(729_755, SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)));
7039         testST2(730_120, SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)));
7040         testST2(730_486, SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)));
7041 
7042         testST2(733_773, SysTime(DateTime(2010, 1, 1, 12, 2, 9), msecs(212)));
7043         testST2(733_803, SysTime(DateTime(2010, 1, 31, 12, 2, 9), msecs(212)));
7044         testST2(733_804, SysTime(DateTime(2010, 2, 1, 12, 2, 9), msecs(212)));
7045         testST2(733_831, SysTime(DateTime(2010, 2, 28, 12, 2, 9), msecs(212)));
7046         testST2(733_832, SysTime(DateTime(2010, 3, 1, 12, 2, 9), msecs(212)));
7047         testST2(733_862, SysTime(DateTime(2010, 3, 31, 12, 2, 9), msecs(212)));
7048         testST2(733_863, SysTime(DateTime(2010, 4, 1, 12, 2, 9), msecs(212)));
7049         testST2(733_892, SysTime(DateTime(2010, 4, 30, 12, 2, 9), msecs(212)));
7050         testST2(733_893, SysTime(DateTime(2010, 5, 1, 12, 2, 9), msecs(212)));
7051         testST2(733_923, SysTime(DateTime(2010, 5, 31, 12, 2, 9), msecs(212)));
7052         testST2(733_924, SysTime(DateTime(2010, 6, 1, 12, 2, 9), msecs(212)));
7053         testST2(733_953, SysTime(DateTime(2010, 6, 30, 12, 2, 9), msecs(212)));
7054         testST2(733_954, SysTime(DateTime(2010, 7, 1, 12, 2, 9), msecs(212)));
7055         testST2(733_984, SysTime(DateTime(2010, 7, 31, 12, 2, 9), msecs(212)));
7056         testST2(733_985, SysTime(DateTime(2010, 8, 1, 12, 2, 9), msecs(212)));
7057         testST2(734_015, SysTime(DateTime(2010, 8, 31, 12, 2, 9), msecs(212)));
7058         testST2(734_016, SysTime(DateTime(2010, 9, 1, 12, 2, 9), msecs(212)));
7059         testST2(734_045, SysTime(DateTime(2010, 9, 30, 12, 2, 9), msecs(212)));
7060         testST2(734_046, SysTime(DateTime(2010, 10, 1, 12, 2, 9), msecs(212)));
7061         testST2(734_076, SysTime(DateTime(2010, 10, 31, 12, 2, 9), msecs(212)));
7062         testST2(734_077, SysTime(DateTime(2010, 11, 1, 12, 2, 9), msecs(212)));
7063         testST2(734_106, SysTime(DateTime(2010, 11, 30, 12, 2, 9), msecs(212)));
7064         testST2(734_107, SysTime(DateTime(2010, 12, 1, 12, 2, 9), msecs(212)));
7065         testST2(734_137, SysTime(DateTime(2010, 12, 31, 12, 2, 9), msecs(212)));
7066 
7067         testST2(734_534, SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
7068         testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
7069         testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
7070         testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
7071 
7072         testST2(734_534,  SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
7073 
7074         testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
7075         testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
7076         testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
7077 
7078         // Test B.C.
7079         testST2(0, SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)));
7080         testST2(-1, SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)));
7081         testST2(-30, SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)));
7082         testST2(-31, SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)));
7083 
7084         testST2(-366, SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)));
7085         testST2(-367, SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)));
7086         testST2(-730, SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)));
7087         testST2(-731, SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)));
7088         testST2(-1095, SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)));
7089         testST2(-1096, SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)));
7090         testST2(-1460, SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)));
7091         testST2(-1461, SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)));
7092         testST2(-1826, SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)));
7093         testST2(-1827, SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)));
7094         testST2(-2191, SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)));
7095         testST2(-3652, SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)));
7096 
7097         testST2(-18_262, SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)));
7098         testST2(-18_627, SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)));
7099         testST2(-35_794, SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)));
7100         testST2(-36_160, SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)));
7101         testST2(-36_524, SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)));
7102         testST2(-36_889, SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)));
7103         testST2(-37_254, SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)));
7104         testST2(-38_715, SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)));
7105         testST2(-73_413, SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)));
7106         testST2(-73_778, SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)));
7107         testST2(-109_937, SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)));
7108         testST2(-110_302, SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)));
7109         testST2(-146_097, SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)));
7110         testST2(-146_462, SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)));
7111         testST2(-146_827, SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)));
7112         testST2(-182_621, SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)));
7113         testST2(-182_986, SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)));
7114         testST2(-183_351, SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)));
7115         testST2(-365_607, SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)));
7116         testST2(-365_972, SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)));
7117         testST2(-584_387, SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)));
7118         testST2(-584_388, SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)));
7119         testST2(-584_753, SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)));
7120         testST2(-585_118, SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)));
7121         testST2(-694_325, SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)));
7122         testST2(-694_690, SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)));
7123         testST2(-730_484, SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)));
7124         testST2(-730_485, SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)));
7125         testST2(-730_850, SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)));
7126         testST2(-731_215, SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)));
7127 
7128         testST2(-734_502, SysTime(DateTime(-2010, 1, 1, 12, 2, 9), msecs(212)));
7129         testST2(-734_472, SysTime(DateTime(-2010, 1, 31, 12, 2, 9), msecs(212)));
7130         testST2(-734_471, SysTime(DateTime(-2010, 2, 1, 12, 2, 9), msecs(212)));
7131         testST2(-734_444, SysTime(DateTime(-2010, 2, 28, 12, 2, 9), msecs(212)));
7132         testST2(-734_443, SysTime(DateTime(-2010, 3, 1, 12, 2, 9), msecs(212)));
7133         testST2(-734_413, SysTime(DateTime(-2010, 3, 31, 12, 2, 9), msecs(212)));
7134         testST2(-734_412, SysTime(DateTime(-2010, 4, 1, 12, 2, 9), msecs(212)));
7135         testST2(-734_383, SysTime(DateTime(-2010, 4, 30, 12, 2, 9), msecs(212)));
7136         testST2(-734_382, SysTime(DateTime(-2010, 5, 1, 12, 2, 9), msecs(212)));
7137         testST2(-734_352, SysTime(DateTime(-2010, 5, 31, 12, 2, 9), msecs(212)));
7138         testST2(-734_351, SysTime(DateTime(-2010, 6, 1, 12, 2, 9), msecs(212)));
7139         testST2(-734_322, SysTime(DateTime(-2010, 6, 30, 12, 2, 9), msecs(212)));
7140         testST2(-734_321, SysTime(DateTime(-2010, 7, 1, 12, 2, 9), msecs(212)));
7141         testST2(-734_291, SysTime(DateTime(-2010, 7, 31, 12, 2, 9), msecs(212)));
7142         testST2(-734_290, SysTime(DateTime(-2010, 8, 1, 12, 2, 9), msecs(212)));
7143         testST2(-734_260, SysTime(DateTime(-2010, 8, 31, 12, 2, 9), msecs(212)));
7144         testST2(-734_259, SysTime(DateTime(-2010, 9, 1, 12, 2, 9), msecs(212)));
7145         testST2(-734_230, SysTime(DateTime(-2010, 9, 30, 12, 2, 9), msecs(212)));
7146         testST2(-734_229, SysTime(DateTime(-2010, 10, 1, 12, 2, 9), msecs(212)));
7147         testST2(-734_199, SysTime(DateTime(-2010, 10, 31, 12, 2, 9), msecs(212)));
7148         testST2(-734_198, SysTime(DateTime(-2010, 11, 1, 12, 2, 9), msecs(212)));
7149         testST2(-734_169, SysTime(DateTime(-2010, 11, 30, 12, 2, 9), msecs(212)));
7150         testST2(-734_168, SysTime(DateTime(-2010, 12, 1, 12, 2, 9), msecs(212)));
7151         testST2(-734_138, SysTime(DateTime(-2010, 12, 31, 12, 2, 9), msecs(212)));
7152 
7153         testST2(-735_202, SysTime(DateTime(-2012, 2, 1, 12, 2, 9), msecs(212)));
7154         testST2(-735_175, SysTime(DateTime(-2012, 2, 28, 12, 2, 9), msecs(212)));
7155         testST2(-735_174, SysTime(DateTime(-2012, 2, 29, 12, 2, 9), msecs(212)));
7156         testST2(-735_173, SysTime(DateTime(-2012, 3, 1, 12, 2, 9), msecs(212)));
7157 
7158         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7159         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7160         static assert(!__traits(compiles, cst.dayOfGregorianCal = 7));
7161         //static assert(!__traits(compiles, ist.dayOfGregorianCal = 7));
7162     }
7163 
7164 
7165     /++
7166         The ISO 8601 week of the year that this $(LREF SysTime) is in.
7167 
7168         See_Also:
7169             $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date).
7170       +/
7171     @property ubyte isoWeek() @safe const nothrow
7172     {
7173         return (cast(Date) this).isoWeek;
7174     }
7175 
7176     ///
7177     @safe unittest
7178     {
7179         import std.datetime.date : Date;
7180 
7181         auto st = SysTime(Date(1999, 7, 6));
7182         const cst = SysTime(Date(2010, 5, 1));
7183         immutable ist = SysTime(Date(2015, 10, 10));
7184 
7185         assert(st.isoWeek == 27);
7186         assert(cst.isoWeek == 17);
7187         assert(ist.isoWeek == 41);
7188     }
7189 
7190 
7191     /++
7192         $(LREF SysTime) for the last day in the month that this Date is in.
7193         The time portion of endOfMonth is always 23:59:59.9999999.
7194       +/
7195     @property SysTime endOfMonth() @safe const nothrow
7196     {
7197         immutable hnsecs = adjTime;
7198         immutable days = getUnitsFromHNSecs!"days"(hnsecs);
7199 
7200         auto date = Date(cast(int) days + 1).endOfMonth;
7201         auto newDays = date.dayOfGregorianCal - 1;
7202         long theTimeHNSecs;
7203 
7204         if (newDays < 0)
7205         {
7206             theTimeHNSecs = -1;
7207             ++newDays;
7208         }
7209         else
7210             theTimeHNSecs = convert!("days", "hnsecs")(1) - 1;
7211 
7212         immutable newDaysHNSecs = convert!("days", "hnsecs")(newDays);
7213 
7214         auto retval = SysTime(this._stdTime, this._timezone);
7215         retval.adjTime = newDaysHNSecs + theTimeHNSecs;
7216 
7217         return retval;
7218     }
7219 
7220     ///
7221     @safe unittest
7222     {
7223         import core.time : msecs, usecs, hnsecs;
7224         import std.datetime.date : DateTime;
7225 
7226         assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonth ==
7227                SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7228 
7229         assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0), msecs(24)).endOfMonth ==
7230                SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7231 
7232         assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27), usecs(5203)).endOfMonth ==
7233                SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7234 
7235         assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9), hnsecs(12345)).endOfMonth ==
7236                SysTime(DateTime(2000, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7237     }
7238 
7239     @safe unittest
7240     {
7241         // Test A.D.
7242         assert(SysTime(Date(1999, 1, 1)).endOfMonth == SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7243         assert(SysTime(Date(1999, 2, 1)).endOfMonth == SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7244         assert(SysTime(Date(2000, 2, 1)).endOfMonth == SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7245         assert(SysTime(Date(1999, 3, 1)).endOfMonth == SysTime(DateTime(1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
7246         assert(SysTime(Date(1999, 4, 1)).endOfMonth == SysTime(DateTime(1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
7247         assert(SysTime(Date(1999, 5, 1)).endOfMonth == SysTime(DateTime(1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
7248         assert(SysTime(Date(1999, 6, 1)).endOfMonth == SysTime(DateTime(1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7249         assert(SysTime(Date(1999, 7, 1)).endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7250         assert(SysTime(Date(1999, 8, 1)).endOfMonth == SysTime(DateTime(1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
7251         assert(SysTime(Date(1999, 9, 1)).endOfMonth == SysTime(DateTime(1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
7252         assert(SysTime(Date(1999, 10, 1)).endOfMonth == SysTime(DateTime(1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
7253         assert(SysTime(Date(1999, 11, 1)).endOfMonth == SysTime(DateTime(1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
7254         assert(SysTime(Date(1999, 12, 1)).endOfMonth == SysTime(DateTime(1999, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7255 
7256         // Test B.C.
7257         assert(SysTime(Date(-1999, 1, 1)).endOfMonth == SysTime(DateTime(-1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7258         assert(SysTime(Date(-1999, 2, 1)).endOfMonth == SysTime(DateTime(-1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7259         assert(SysTime(Date(-2000, 2, 1)).endOfMonth == SysTime(DateTime(-2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7260         assert(SysTime(Date(-1999, 3, 1)).endOfMonth == SysTime(DateTime(-1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
7261         assert(SysTime(Date(-1999, 4, 1)).endOfMonth == SysTime(DateTime(-1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
7262         assert(SysTime(Date(-1999, 5, 1)).endOfMonth == SysTime(DateTime(-1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
7263         assert(SysTime(Date(-1999, 6, 1)).endOfMonth == SysTime(DateTime(-1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7264         assert(SysTime(Date(-1999, 7, 1)).endOfMonth == SysTime(DateTime(-1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7265         assert(SysTime(Date(-1999, 8, 1)).endOfMonth == SysTime(DateTime(-1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
7266         assert(SysTime(Date(-1999, 9, 1)).endOfMonth == SysTime(DateTime(-1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
7267         assert(SysTime(Date(-1999, 10, 1)).endOfMonth ==
7268                SysTime(DateTime(-1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
7269         assert(SysTime(Date(-1999, 11, 1)).endOfMonth ==
7270                SysTime(DateTime(-1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
7271         assert(SysTime(Date(-1999, 12, 1)).endOfMonth ==
7272                SysTime(DateTime(-1999, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7273 
7274         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7275         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7276         assert(cst.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7277         //assert(ist.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7278     }
7279 
7280 
7281     /++
7282         The last day in the month that this $(LREF SysTime) is in.
7283       +/
7284     @property ubyte daysInMonth() @safe const nothrow
7285     {
7286         return Date(dayOfGregorianCal).daysInMonth;
7287     }
7288 
7289     ///
7290     @safe unittest
7291     {
7292         import std.datetime.date : DateTime;
7293 
7294         assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).daysInMonth == 31);
7295         assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0)).daysInMonth == 28);
7296         assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27)).daysInMonth == 29);
7297         assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9)).daysInMonth == 30);
7298     }
7299 
7300     @safe unittest
7301     {
7302         // Test A.D.
7303         assert(SysTime(DateTime(1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
7304         assert(SysTime(DateTime(1999, 2, 1, 17, 13, 12)).daysInMonth == 28);
7305         assert(SysTime(DateTime(2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
7306         assert(SysTime(DateTime(1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
7307         assert(SysTime(DateTime(1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
7308         assert(SysTime(DateTime(1999, 5, 1, 15, 13, 12)).daysInMonth == 31);
7309         assert(SysTime(DateTime(1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
7310         assert(SysTime(DateTime(1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
7311         assert(SysTime(DateTime(1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
7312         assert(SysTime(DateTime(1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
7313         assert(SysTime(DateTime(1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
7314         assert(SysTime(DateTime(1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
7315         assert(SysTime(DateTime(1999, 12, 1, 12, 52, 13)).daysInMonth == 31);
7316 
7317         // Test B.C.
7318         assert(SysTime(DateTime(-1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
7319         assert(SysTime(DateTime(-1999, 2, 1, 7, 13, 12)).daysInMonth == 28);
7320         assert(SysTime(DateTime(-2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
7321         assert(SysTime(DateTime(-1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
7322         assert(SysTime(DateTime(-1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
7323         assert(SysTime(DateTime(-1999, 5, 1, 5, 13, 12)).daysInMonth == 31);
7324         assert(SysTime(DateTime(-1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
7325         assert(SysTime(DateTime(-1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
7326         assert(SysTime(DateTime(-1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
7327         assert(SysTime(DateTime(-1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
7328         assert(SysTime(DateTime(-1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
7329         assert(SysTime(DateTime(-1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
7330         assert(SysTime(DateTime(-1999, 12, 1, 12, 52, 13)).daysInMonth == 31);
7331 
7332         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7333         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7334         assert(cst.daysInMonth == 31);
7335         //assert(ist.daysInMonth == 31);
7336     }
7337 
7338 
7339     /++
7340         Whether the current year is a date in A.D.
7341       +/
7342     @property bool isAD() @safe const nothrow
7343     {
7344         return adjTime >= 0;
7345     }
7346 
7347     ///
7348     @safe unittest
7349     {
7350         import std.datetime.date : DateTime;
7351 
7352         assert(SysTime(DateTime(1, 1, 1, 12, 7, 0)).isAD);
7353         assert(SysTime(DateTime(2010, 12, 31, 0, 0, 0)).isAD);
7354         assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
7355         assert(!SysTime(DateTime(-2010, 1, 1, 2, 2, 2)).isAD);
7356     }
7357 
7358     @safe unittest
7359     {
7360         assert(SysTime(DateTime(2010, 7, 4, 12, 0, 9)).isAD);
7361         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).isAD);
7362         assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
7363         assert(!SysTime(DateTime(0, 1, 1, 23, 59, 59)).isAD);
7364         assert(!SysTime(DateTime(-1, 1, 1, 23 ,59 ,59)).isAD);
7365         assert(!SysTime(DateTime(-2010, 7, 4, 12, 2, 2)).isAD);
7366 
7367         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7368         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7369         assert(cst.isAD);
7370         //assert(ist.isAD);
7371     }
7372 
7373 
7374     /++
7375         The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day)
7376         for this $(LREF SysTime) at the given time. For example,
7377         prior to noon, 1996-03-31 would be the Julian day number 2_450_173, so
7378         this function returns 2_450_173, while from noon onward, the Julian
7379         day number would be 2_450_174, so this function returns 2_450_174.
7380       +/
7381     @property long julianDay() @safe const nothrow
7382     {
7383         immutable jd = dayOfGregorianCal + 1_721_425;
7384         return hour < 12 ? jd - 1 : jd;
7385     }
7386 
7387     @safe unittest
7388     {
7389         assert(SysTime(DateTime(-4713, 11, 24, 0, 0, 0)).julianDay == -1);
7390         assert(SysTime(DateTime(-4713, 11, 24, 12, 0, 0)).julianDay == 0);
7391 
7392         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).julianDay == 1_721_424);
7393         assert(SysTime(DateTime(0, 12, 31, 12, 0, 0)).julianDay == 1_721_425);
7394 
7395         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).julianDay == 1_721_425);
7396         assert(SysTime(DateTime(1, 1, 1, 12, 0, 0)).julianDay == 1_721_426);
7397 
7398         assert(SysTime(DateTime(1582, 10, 15, 0, 0, 0)).julianDay == 2_299_160);
7399         assert(SysTime(DateTime(1582, 10, 15, 12, 0, 0)).julianDay == 2_299_161);
7400 
7401         assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).julianDay == 2_400_000);
7402         assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).julianDay == 2_400_001);
7403 
7404         assert(SysTime(DateTime(1982, 1, 4, 0, 0, 0)).julianDay == 2_444_973);
7405         assert(SysTime(DateTime(1982, 1, 4, 12, 0, 0)).julianDay == 2_444_974);
7406 
7407         assert(SysTime(DateTime(1996, 3, 31, 0, 0, 0)).julianDay == 2_450_173);
7408         assert(SysTime(DateTime(1996, 3, 31, 12, 0, 0)).julianDay == 2_450_174);
7409 
7410         assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).julianDay == 2_455_432);
7411         assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).julianDay == 2_455_433);
7412 
7413         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7414         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7415         assert(cst.julianDay == 2_451_366);
7416         //assert(ist.julianDay == 2_451_366);
7417     }
7418 
7419 
7420     /++
7421         The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for
7422         any time on this date (since, the modified Julian day changes at
7423         midnight).
7424       +/
7425     @property long modJulianDay() @safe const nothrow
7426     {
7427         return dayOfGregorianCal + 1_721_425 - 2_400_001;
7428     }
7429 
7430     @safe unittest
7431     {
7432         assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).modJulianDay == 0);
7433         assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).modJulianDay == 0);
7434 
7435         assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).modJulianDay == 55_432);
7436         assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).modJulianDay == 55_432);
7437 
7438         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7439         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7440         assert(cst.modJulianDay == 51_365);
7441         //assert(ist.modJulianDay == 51_365);
7442     }
7443 
7444 
7445     /++
7446         Returns a $(REF Date,std,datetime,date) equivalent to this $(LREF SysTime).
7447       +/
7448     Date opCast(T)() @safe const nothrow
7449         if (is(Unqual!T == Date))
7450     {
7451         return Date(dayOfGregorianCal);
7452     }
7453 
7454     @safe unittest
7455     {
7456         assert(cast(Date) SysTime(Date(1999, 7, 6)) == Date(1999, 7, 6));
7457         assert(cast(Date) SysTime(Date(2000, 12, 31)) == Date(2000, 12, 31));
7458         assert(cast(Date) SysTime(Date(2001, 1, 1)) == Date(2001, 1, 1));
7459 
7460         assert(cast(Date) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == Date(1999, 7, 6));
7461         assert(cast(Date) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == Date(2000, 12, 31));
7462         assert(cast(Date) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == Date(2001, 1, 1));
7463 
7464         assert(cast(Date) SysTime(Date(-1999, 7, 6)) == Date(-1999, 7, 6));
7465         assert(cast(Date) SysTime(Date(-2000, 12, 31)) == Date(-2000, 12, 31));
7466         assert(cast(Date) SysTime(Date(-2001, 1, 1)) == Date(-2001, 1, 1));
7467 
7468         assert(cast(Date) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == Date(-1999, 7, 6));
7469         assert(cast(Date) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == Date(-2000, 12, 31));
7470         assert(cast(Date) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == Date(-2001, 1, 1));
7471 
7472         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7473         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7474         assert(cast(Date) cst != Date.init);
7475         //assert(cast(Date) ist != Date.init);
7476     }
7477 
7478 
7479     /++
7480         Returns a $(REF DateTime,std,datetime,date) equivalent to this
7481         $(LREF SysTime).
7482       +/
7483     DateTime opCast(T)() @safe const nothrow
7484         if (is(Unqual!T == DateTime))
7485     {
7486         try
7487         {
7488             auto hnsecs = adjTime;
7489             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
7490 
7491             if (hnsecs < 0)
7492             {
7493                 hnsecs += convert!("hours", "hnsecs")(24);
7494                 --days;
7495             }
7496 
7497             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
7498             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
7499             immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
7500 
7501             return DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour, cast(int) minute, cast(int) second));
7502         }
7503         catch (Exception e)
7504             assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw.");
7505     }
7506 
7507     @safe unittest
7508     {
7509         assert(cast(DateTime) SysTime(DateTime(1, 1, 6, 7, 12, 22)) == DateTime(1, 1, 6, 7, 12, 22));
7510         assert(cast(DateTime) SysTime(DateTime(1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(1, 1, 6, 7, 12, 22));
7511         assert(cast(DateTime) SysTime(Date(1999, 7, 6)) == DateTime(1999, 7, 6, 0, 0, 0));
7512         assert(cast(DateTime) SysTime(Date(2000, 12, 31)) == DateTime(2000, 12, 31, 0, 0, 0));
7513         assert(cast(DateTime) SysTime(Date(2001, 1, 1)) == DateTime(2001, 1, 1, 0, 0, 0));
7514 
7515         assert(cast(DateTime) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == DateTime(1999, 7, 6, 12, 10, 9));
7516         assert(cast(DateTime) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == DateTime(2000, 12, 31, 13, 11, 10));
7517         assert(cast(DateTime) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == DateTime(2001, 1, 1, 14, 12, 11));
7518 
7519         assert(cast(DateTime) SysTime(DateTime(-1, 1, 6, 7, 12, 22)) == DateTime(-1, 1, 6, 7, 12, 22));
7520         assert(cast(DateTime) SysTime(DateTime(-1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(-1, 1, 6, 7, 12, 22));
7521         assert(cast(DateTime) SysTime(Date(-1999, 7, 6)) == DateTime(-1999, 7, 6, 0, 0, 0));
7522         assert(cast(DateTime) SysTime(Date(-2000, 12, 31)) == DateTime(-2000, 12, 31, 0, 0, 0));
7523         assert(cast(DateTime) SysTime(Date(-2001, 1, 1)) == DateTime(-2001, 1, 1, 0, 0, 0));
7524 
7525         assert(cast(DateTime) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == DateTime(-1999, 7, 6, 12, 10, 9));
7526         assert(cast(DateTime) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == DateTime(-2000, 12, 31, 13, 11, 10));
7527         assert(cast(DateTime) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == DateTime(-2001, 1, 1, 14, 12, 11));
7528 
7529         assert(cast(DateTime) SysTime(DateTime(2011, 1, 13, 8, 17, 2), msecs(296), LocalTime()) ==
7530                DateTime(2011, 1, 13, 8, 17, 2));
7531 
7532         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7533         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7534         assert(cast(DateTime) cst != DateTime.init);
7535         //assert(cast(DateTime) ist != DateTime.init);
7536     }
7537 
7538 
7539     /++
7540         Returns a $(REF TimeOfDay,std,datetime,date) equivalent to this
7541         $(LREF SysTime).
7542       +/
7543     TimeOfDay opCast(T)() @safe const nothrow
7544         if (is(Unqual!T == TimeOfDay))
7545     {
7546         try
7547         {
7548             auto hnsecs = adjTime;
7549             hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
7550 
7551             if (hnsecs < 0)
7552                 hnsecs += convert!("hours", "hnsecs")(24);
7553 
7554             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
7555             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
7556             immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
7557 
7558             return TimeOfDay(cast(int) hour, cast(int) minute, cast(int) second);
7559         }
7560         catch (Exception e)
7561             assert(0, "TimeOfDay's constructor threw.");
7562     }
7563 
7564     @safe unittest
7565     {
7566         assert(cast(TimeOfDay) SysTime(Date(1999, 7, 6)) == TimeOfDay(0, 0, 0));
7567         assert(cast(TimeOfDay) SysTime(Date(2000, 12, 31)) == TimeOfDay(0, 0, 0));
7568         assert(cast(TimeOfDay) SysTime(Date(2001, 1, 1)) == TimeOfDay(0, 0, 0));
7569 
7570         assert(cast(TimeOfDay) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
7571         assert(cast(TimeOfDay) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
7572         assert(cast(TimeOfDay) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11));
7573 
7574         assert(cast(TimeOfDay) SysTime(Date(-1999, 7, 6)) == TimeOfDay(0, 0, 0));
7575         assert(cast(TimeOfDay) SysTime(Date(-2000, 12, 31)) == TimeOfDay(0, 0, 0));
7576         assert(cast(TimeOfDay) SysTime(Date(-2001, 1, 1)) == TimeOfDay(0, 0, 0));
7577 
7578         assert(cast(TimeOfDay) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
7579         assert(cast(TimeOfDay) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
7580         assert(cast(TimeOfDay) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11));
7581 
7582         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7583         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7584         assert(cast(TimeOfDay) cst != TimeOfDay.init);
7585         //assert(cast(TimeOfDay) ist != TimeOfDay.init);
7586     }
7587 
7588 
7589     // Temporary hack until bug http://d.puremagic.com/issues/show_bug.cgi?id=4867 is fixed.
7590     // This allows assignment from const(SysTime) to SysTime.
7591     // It may be a good idea to keep it though, since casting from a type to itself
7592     // should be allowed, and it doesn't work without this opCast() since opCast()
7593     // has already been defined for other types.
7594     SysTime opCast(T)() @safe const pure nothrow
7595         if (is(Unqual!T == SysTime))
7596     {
7597         return SysTime(_stdTime, _timezone);
7598     }
7599 
7600 
7601     /++
7602         Converts this $(LREF SysTime) to a string with the format
7603         YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds and TZ is time
7604         zone).
7605 
7606         Note that the number of digits in the fractional seconds varies with the
7607         number of fractional seconds. It's a maximum of 7 (which would be
7608         hnsecs), but only has as many as are necessary to hold the correct value
7609         (so no trailing zeroes), and if there are no fractional seconds, then
7610         there is no decimal point.
7611 
7612         If this $(LREF SysTime)'s time zone is
7613         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
7614         zone is $(D UTC), then it is "Z". Otherwise, it is the offset from UTC
7615         (e.g. +0100 or -0700). Note that the offset from UTC is $(I not) enough
7616         to uniquely identify the time zone.
7617 
7618         Time zone offsets will be in the form +HHMM or -HHMM.
7619 
7620         $(RED Warning:
7621             Previously, toISOString did the same as $(LREF toISOExtString) and
7622             generated +HH:MM or -HH:MM for the time zone when it was not
7623             $(REF LocalTime,std,datetime,timezone) or
7624             $(REF UTC,std,datetime,timezone), which is not in conformance with
7625             ISO 8601 for the non-extended string format. This has now been
7626             fixed. However, for now, fromISOString will continue to accept the
7627             extended format for the time zone so that any code which has been
7628             writing out the result of toISOString to read in later will continue
7629             to work. The current behavior will be kept until July 2019 at which
7630             point, fromISOString will be fixed to be standards compliant.)
7631       +/
7632     string toISOString() @safe const nothrow
7633     {
7634         try
7635         {
7636             immutable adjustedTime = adjTime;
7637             long hnsecs = adjustedTime;
7638 
7639             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
7640 
7641             if (hnsecs < 0)
7642             {
7643                 hnsecs += convert!("hours", "hnsecs")(24);
7644                 --days;
7645             }
7646 
7647             auto hour = splitUnitsFromHNSecs!"hours"(hnsecs);
7648             auto minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
7649             auto second = splitUnitsFromHNSecs!"seconds"(hnsecs);
7650 
7651             auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
7652                                           cast(int) minute, cast(int) second));
7653             auto fracSecStr = fracSecsToISOString(cast(int) hnsecs);
7654 
7655             if (_timezone is LocalTime())
7656                 return dateTime.toISOString() ~ fracSecStr;
7657 
7658             if (_timezone is UTC())
7659                 return dateTime.toISOString() ~ fracSecStr ~ "Z";
7660 
7661             immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
7662 
7663             return format("%s%s%s",
7664                           dateTime.toISOString(),
7665                           fracSecStr,
7666                           SimpleTimeZone.toISOExtString(utcOffset));
7667         }
7668         catch (Exception e)
7669             assert(0, "format() threw.");
7670     }
7671 
7672     ///
7673     @safe unittest
7674     {
7675         import core.time : msecs, hnsecs;
7676         import std.datetime.date : DateTime;
7677 
7678         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOString() ==
7679                "20100704T070612");
7680 
7681         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOString() ==
7682                "19981225T021500.024");
7683 
7684         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOString() ==
7685                "00000105T230959");
7686 
7687         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOString() ==
7688                "-00040105T000002.052092");
7689     }
7690 
7691     @safe unittest
7692     {
7693         // Test A.D.
7694         assert(SysTime(DateTime.init, UTC()).toISOString() == "00010101T000000Z");
7695         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOString() == "00010101T000000.0000001Z");
7696 
7697         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOString() == "00091204T000000");
7698         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOString() == "00991204T050612");
7699         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOString() == "09991204T134459");
7700         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOString() == "99990704T235959");
7701         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOString() == "+100001020T010101");
7702 
7703         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "00091204T000000.042");
7704         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "00991204T050612.1");
7705         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "09991204T134459.04502");
7706         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "99990704T235959.0000012");
7707         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "+100001020T010101.050789");
7708 
7709         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
7710                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOString() ==
7711                "20121221T121212-06:00");
7712 
7713         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
7714                        new immutable SimpleTimeZone(dur!"minutes"(420))).toISOString() ==
7715                "20121221T121212+07:00");
7716 
7717         // Test B.C.
7718         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOString() ==
7719                "00001231T235959.9999999Z");
7720         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOString() == "00001231T235959.0000001Z");
7721         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOString() == "00001231T235959Z");
7722 
7723         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOString() == "00001204T001204");
7724         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOString() == "-00091204T000000");
7725         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOString() == "-00991204T050612");
7726         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOString() == "-09991204T134459");
7727         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOString() == "-99990704T235959");
7728         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOString() == "-100001020T010101");
7729 
7730         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOString() == "00001204T000000.007");
7731         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "-00091204T000000.042");
7732         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "-00991204T050612.1");
7733         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "-09991204T134459.04502");
7734         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "-99990704T235959.0000012");
7735         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "-100001020T010101.050789");
7736 
7737         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7738         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7739         assert(cast(TimeOfDay) cst != TimeOfDay.init);
7740         //assert(cast(TimeOfDay) ist != TimeOfDay.init);
7741     }
7742 
7743 
7744 
7745     /++
7746         Converts this $(LREF SysTime) to a string with the format
7747         YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
7748         is the time zone).
7749 
7750         Note that the number of digits in the fractional seconds varies with the
7751         number of fractional seconds. It's a maximum of 7 (which would be
7752         hnsecs), but only has as many as are necessary to hold the correct value
7753         (so no trailing zeroes), and if there are no fractional seconds, then
7754         there is no decimal point.
7755 
7756         If this $(LREF SysTime)'s time zone is
7757         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
7758         zone is $(D UTC), then it is "Z". Otherwise, it is the offset from UTC
7759         (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not)
7760         enough to uniquely identify the time zone.
7761 
7762         Time zone offsets will be in the form +HH:MM or -HH:MM.
7763       +/
7764     string toISOExtString() @safe const nothrow
7765     {
7766         try
7767         {
7768             immutable adjustedTime = adjTime;
7769             long hnsecs = adjustedTime;
7770 
7771             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
7772 
7773             if (hnsecs < 0)
7774             {
7775                 hnsecs += convert!("hours", "hnsecs")(24);
7776                 --days;
7777             }
7778 
7779             auto hour = splitUnitsFromHNSecs!"hours"(hnsecs);
7780             auto minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
7781             auto second = splitUnitsFromHNSecs!"seconds"(hnsecs);
7782 
7783             auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
7784                                           cast(int) minute, cast(int) second));
7785             auto fracSecStr = fracSecsToISOString(cast(int) hnsecs);
7786 
7787             if (_timezone is LocalTime())
7788                 return dateTime.toISOExtString() ~ fracSecStr;
7789 
7790             if (_timezone is UTC())
7791                 return dateTime.toISOExtString() ~ fracSecStr ~ "Z";
7792 
7793             immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
7794 
7795             return format("%s%s%s",
7796                           dateTime.toISOExtString(),
7797                           fracSecStr,
7798                           SimpleTimeZone.toISOExtString(utcOffset));
7799         }
7800         catch (Exception e)
7801             assert(0, "format() threw.");
7802     }
7803 
7804     ///
7805     @safe unittest
7806     {
7807         import core.time : msecs, hnsecs;
7808         import std.datetime.date : DateTime;
7809 
7810         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOExtString() ==
7811                "2010-07-04T07:06:12");
7812 
7813         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOExtString() ==
7814                "1998-12-25T02:15:00.024");
7815 
7816         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOExtString() ==
7817                "0000-01-05T23:09:59");
7818 
7819         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString() ==
7820                "-0004-01-05T00:00:02.052092");
7821     }
7822 
7823     @safe unittest
7824     {
7825         // Test A.D.
7826         assert(SysTime(DateTime.init, UTC()).toISOExtString() == "0001-01-01T00:00:00Z");
7827         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOExtString() ==
7828                "0001-01-01T00:00:00.0000001Z");
7829 
7830         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00");
7831         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12");
7832         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59");
7833         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59");
7834         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01");
7835 
7836         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "0009-12-04T00:00:00.042");
7837         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "0099-12-04T05:06:12.1");
7838         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() == "0999-12-04T13:44:59.04502");
7839         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() == "9999-07-04T23:59:59.0000012");
7840         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
7841                "+10000-10-20T01:01:01.050789");
7842 
7843         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
7844                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOExtString() ==
7845                "2012-12-21T12:12:12-06:00");
7846 
7847         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
7848                        new immutable SimpleTimeZone(dur!"minutes"(420))).toISOExtString() ==
7849                "2012-12-21T12:12:12+07:00");
7850 
7851         // Test B.C.
7852         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOExtString() ==
7853                "0000-12-31T23:59:59.9999999Z");
7854         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOExtString() ==
7855                "0000-12-31T23:59:59.0000001Z");
7856         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOExtString() == "0000-12-31T23:59:59Z");
7857 
7858         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04");
7859         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00");
7860         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12");
7861         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59");
7862         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59");
7863         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01");
7864 
7865         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOExtString() == "0000-12-04T00:00:00.007");
7866         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "-0009-12-04T00:00:00.042");
7867         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "-0099-12-04T05:06:12.1");
7868         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() ==
7869                "-0999-12-04T13:44:59.04502");
7870         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() ==
7871                "-9999-07-04T23:59:59.0000012");
7872         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
7873                "-10000-10-20T01:01:01.050789");
7874 
7875         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7876         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7877         assert(cast(TimeOfDay) cst != TimeOfDay.init);
7878         //assert(cast(TimeOfDay) ist != TimeOfDay.init);
7879     }
7880 
7881     /++
7882         Converts this $(LREF SysTime) to a string with the format
7883         YYYY-Mon-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
7884         is the time zone).
7885 
7886         Note that the number of digits in the fractional seconds varies with the
7887         number of fractional seconds. It's a maximum of 7 (which would be
7888         hnsecs), but only has as many as are necessary to hold the correct value
7889         (so no trailing zeroes), and if there are no fractional seconds, then
7890         there is no decimal point.
7891 
7892         If this $(LREF SysTime)'s time zone is
7893         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
7894         zone is $(D UTC), then it is "Z". Otherwise, it is the offset from UTC
7895         (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not)
7896         enough to uniquely identify the time zone.
7897 
7898         Time zone offsets will be in the form +HH:MM or -HH:MM.
7899       +/
7900     string toSimpleString() @safe const nothrow
7901     {
7902         try
7903         {
7904             immutable adjustedTime = adjTime;
7905             long hnsecs = adjustedTime;
7906 
7907             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
7908 
7909             if (hnsecs < 0)
7910             {
7911                 hnsecs += convert!("hours", "hnsecs")(24);
7912                 --days;
7913             }
7914 
7915             auto hour = splitUnitsFromHNSecs!"hours"(hnsecs);
7916             auto minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
7917             auto second = splitUnitsFromHNSecs!"seconds"(hnsecs);
7918 
7919             auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
7920                                           cast(int) minute, cast(int) second));
7921             auto fracSecStr = fracSecsToISOString(cast(int) hnsecs);
7922 
7923             if (_timezone is LocalTime())
7924                 return dateTime.toSimpleString() ~ fracSecStr;
7925 
7926             if (_timezone is UTC())
7927                 return dateTime.toSimpleString() ~ fracSecStr ~ "Z";
7928 
7929             immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
7930 
7931             return format("%s%s%s",
7932                           dateTime.toSimpleString(),
7933                           fracSecStr,
7934                           SimpleTimeZone.toISOExtString(utcOffset));
7935         }
7936         catch (Exception e)
7937             assert(0, "format() threw.");
7938     }
7939 
7940     ///
7941     @safe unittest
7942     {
7943         import core.time : msecs, hnsecs;
7944         import std.datetime.date : DateTime;
7945 
7946         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toSimpleString() ==
7947                "2010-Jul-04 07:06:12");
7948 
7949         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toSimpleString() ==
7950                "1998-Dec-25 02:15:00.024");
7951 
7952         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toSimpleString() ==
7953                "0000-Jan-05 23:09:59");
7954 
7955         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toSimpleString() ==
7956                 "-0004-Jan-05 00:00:02.052092");
7957     }
7958 
7959     @safe unittest
7960     {
7961         // Test A.D.
7962         assert(SysTime(DateTime.init, UTC()).toString() == "0001-Jan-01 00:00:00Z");
7963         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toString() == "0001-Jan-01 00:00:00.0000001Z");
7964 
7965         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00");
7966         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12");
7967         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59");
7968         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59");
7969         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01");
7970 
7971         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "0009-Dec-04 00:00:00.042");
7972         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "0099-Dec-04 05:06:12.1");
7973         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
7974                "0999-Dec-04 13:44:59.04502");
7975         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
7976                "9999-Jul-04 23:59:59.0000012");
7977         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() ==
7978                "+10000-Oct-20 01:01:01.050789");
7979 
7980         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
7981                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toSimpleString() ==
7982                "2012-Dec-21 12:12:12-06:00");
7983 
7984         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
7985                        new immutable SimpleTimeZone(dur!"minutes"(420))).toSimpleString() ==
7986                "2012-Dec-21 12:12:12+07:00");
7987 
7988         // Test B.C.
7989         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toSimpleString() ==
7990                "0000-Dec-31 23:59:59.9999999Z");
7991         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toSimpleString() ==
7992                "0000-Dec-31 23:59:59.0000001Z");
7993         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toSimpleString() == "0000-Dec-31 23:59:59Z");
7994 
7995         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04");
7996         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00");
7997         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12");
7998         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59");
7999         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59");
8000         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01");
8001 
8002         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toSimpleString() == "0000-Dec-04 00:00:00.007");
8003         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "-0009-Dec-04 00:00:00.042");
8004         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "-0099-Dec-04 05:06:12.1");
8005         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
8006                "-0999-Dec-04 13:44:59.04502");
8007         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
8008                "-9999-Jul-04 23:59:59.0000012");
8009         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() ==
8010                "-10000-Oct-20 01:01:01.050789");
8011 
8012         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8013         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8014         assert(cast(TimeOfDay) cst != TimeOfDay.init);
8015         //assert(cast(TimeOfDay) ist != TimeOfDay.init);
8016     }
8017 
8018 
8019     /++
8020         Converts this $(LREF SysTime) to a string.
8021 
8022         This function exists to make it easy to convert a $(LREF SysTime) to a
8023         string for code that does not care what the exact format is - just that
8024         it presents the information in a clear manner. It also makes it easy to
8025         simply convert a $(LREF SysTime) to a string when using functions such
8026         as `to!string`, `format`, or `writeln` which use toString to convert
8027         user-defined types. So, it is unlikely that much code will call
8028         toString directly.
8029 
8030         The format of the string is purposefully unspecified, and code that
8031         cares about the format of the string should use `toISOString`,
8032         `toISOExtString`, `toSimpleString`, or some other custom formatting
8033         function that explicitly generates the format that the code needs. The
8034         reason is that the code is then clear about what format it's using,
8035         making it less error-prone to maintain the code and interact with other
8036         software that consumes the generated strings. It's for this same reason
8037         that $(LREF SysTime) has no `fromString` function, whereas it does have
8038         `fromISOString`, `fromISOExtString`, and `fromSimpleString`.
8039 
8040         The format returned by toString may or may not change in the future.
8041       +/
8042     string toString() @safe const nothrow
8043     {
8044         return toSimpleString();
8045     }
8046 
8047     @safe unittest
8048     {
8049         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8050         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8051         //immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8052         assert(st.toString());
8053         assert(cst.toString());
8054         //assert(ist.toString());
8055     }
8056 
8057 
8058     /++
8059         Creates a $(LREF SysTime) from a string with the format
8060         YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds is the time
8061         zone). Whitespace is stripped from the given string.
8062 
8063         The exact format is exactly as described in $(D toISOString) except that
8064         trailing zeroes are permitted - including having fractional seconds with
8065         all zeroes. However, a decimal point with nothing following it is
8066         invalid. Also, while $(LREF toISOString) will never generate a string
8067         with more than 7 digits in the fractional seconds (because that's the
8068         limit with hecto-nanosecond precision), it will allow more than 7 digits
8069         in order to read strings from other sources that have higher precision
8070         (however, any digits beyond 7 will be truncated).
8071 
8072         If there is no time zone in the string, then
8073         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
8074         then $(D UTC) is used. Otherwise, a
8075         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
8076         given offset from UTC is used. To get the returned $(LREF SysTime) to be
8077         a particular time zone, pass in that time zone and the $(LREF SysTime)
8078         to be returned will be converted to that time zone (though it will still
8079         be read in as whatever time zone is in its string).
8080 
8081         The accepted formats for time zone offsets are +HH, -HH, +HHMM, and
8082         -HHMM.
8083 
8084         $(RED Warning:
8085             Previously, $(LREF toISOString) did the same as
8086             $(LREF toISOExtString) and generated +HH:MM or -HH:MM for the time
8087             zone when it was not $(REF LocalTime,std,datetime,timezone) or
8088             $(REF UTC,std,datetime,timezone), which is not in conformance with
8089             ISO 8601 for the non-extended string format. This has now been
8090             fixed. However, for now, fromISOString will continue to accept the
8091             extended format for the time zone so that any code which has been
8092             writing out the result of toISOString to read in later will continue
8093             to work. The current behavior will be kept until July 2019 at which
8094             point, fromISOString will be fixed to be standards compliant.)
8095 
8096         Params:
8097             isoString = A string formatted in the ISO format for dates and times.
8098             tz        = The time zone to convert the given time to (no
8099                         conversion occurs if null).
8100 
8101         Throws:
8102             $(REF DateTimeException,std,datetime,date) if the given string is
8103             not in the ISO format or if the resulting $(LREF SysTime) would not
8104             be valid.
8105       +/
8106     static SysTime fromISOString(S)(in S isoString, immutable TimeZone tz = null) @safe
8107         if (isSomeString!S)
8108     {
8109         import std.algorithm.searching : startsWith, find;
8110         import std.conv : to;
8111         import std.string : strip;
8112 
8113         auto dstr = to!dstring(strip(isoString));
8114         immutable skipFirst = dstr.startsWith('+', '-') != 0;
8115 
8116         auto found = (skipFirst ? dstr[1..$] : dstr).find('.', 'Z', '+', '-');
8117         auto dateTimeStr = dstr[0 .. $ - found[0].length];
8118 
8119         dstring fracSecStr;
8120         dstring zoneStr;
8121 
8122         if (found[1] != 0)
8123         {
8124             if (found[1] == 1)
8125             {
8126                 auto foundTZ = found[0].find('Z', '+', '-');
8127 
8128                 if (foundTZ[1] != 0)
8129                 {
8130                     fracSecStr = found[0][0 .. $ - foundTZ[0].length];
8131                     zoneStr = foundTZ[0];
8132                 }
8133                 else
8134                     fracSecStr = found[0];
8135             }
8136             else
8137                 zoneStr = found[0];
8138         }
8139 
8140         try
8141         {
8142             auto dateTime = DateTime.fromISOString(dateTimeStr);
8143             auto fracSec = fracSecsFromISOString(fracSecStr);
8144             Rebindable!(immutable TimeZone) parsedZone;
8145 
8146             if (zoneStr.empty)
8147                 parsedZone = LocalTime();
8148             else if (zoneStr == "Z")
8149                 parsedZone = UTC();
8150             else
8151             {
8152                 try
8153                     parsedZone = SimpleTimeZone.fromISOString(zoneStr);
8154                 catch (DateTimeException dte)
8155                     parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
8156             }
8157 
8158             auto retval = SysTime(dateTime, fracSec, parsedZone);
8159 
8160             if (tz !is null)
8161                 retval.timezone = tz;
8162 
8163             return retval;
8164         }
8165         catch (DateTimeException dte)
8166             throw new DateTimeException(format("Invalid ISO String: %s", isoString));
8167     }
8168 
8169     ///
8170     @safe unittest
8171     {
8172         import core.time : hours, msecs, usecs, hnsecs;
8173         import std.datetime.date : DateTime;
8174         import std.datetime.timezone : SimpleTimeZone, UTC;
8175 
8176         assert(SysTime.fromISOString("20100704T070612") ==
8177                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8178 
8179         assert(SysTime.fromISOString("19981225T021500.007") ==
8180                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
8181 
8182         assert(SysTime.fromISOString("00000105T230959.00002") ==
8183                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
8184 
8185         assert(SysTime.fromISOString("20130207T043937.000050392") ==
8186                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
8187 
8188         assert(SysTime.fromISOString("-00040105T000002") ==
8189                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
8190 
8191         assert(SysTime.fromISOString(" 20100704T070612 ") ==
8192                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8193 
8194         assert(SysTime.fromISOString("20100704T070612Z") ==
8195                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
8196 
8197         assert(SysTime.fromISOString("20100704T070612-0800") ==
8198                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8199                        new immutable SimpleTimeZone(hours(-8))));
8200 
8201         assert(SysTime.fromISOString("20100704T070612+0800") ==
8202                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8203                        new immutable SimpleTimeZone(hours(8))));
8204     }
8205 
8206     @safe unittest
8207     {
8208         foreach (str; ["", "20100704000000", "20100704 000000", "20100704t000000",
8209                        "20100704T000000.", "20100704T000000.A", "20100704T000000.Z",
8210                        "20100704T000000.0000000A", "20100704T000000.00000000A",
8211                        "20100704T000000+", "20100704T000000-", "20100704T000000:",
8212                        "20100704T000000-:", "20100704T000000+:", "20100704T000000-1:",
8213                        "20100704T000000+1:", "20100704T000000+1:0",
8214                        "20100704T000000-12.00", "20100704T000000+12.00",
8215                        "20100704T000000-8", "20100704T000000+8",
8216                        "20100704T000000-800", "20100704T000000+800",
8217                        "20100704T000000-080", "20100704T000000+080",
8218                        "20100704T000000-2400", "20100704T000000+2400",
8219                        "20100704T000000-1260", "20100704T000000+1260",
8220                        "20100704T000000.0-8", "20100704T000000.0+8",
8221                        "20100704T000000.0-800", "20100704T000000.0+800",
8222                        "20100704T000000.0-080", "20100704T000000.0+080",
8223                        "20100704T000000.0-2400", "20100704T000000.0+2400",
8224                        "20100704T000000.0-1260", "20100704T000000.0+1260",
8225                        "20100704T000000-8:00", "20100704T000000+8:00",
8226                        "20100704T000000-08:0", "20100704T000000+08:0",
8227                        "20100704T000000-24:00", "20100704T000000+24:00",
8228                        "20100704T000000-12:60", "20100704T000000+12:60",
8229                        "20100704T000000.0-8:00", "20100704T000000.0+8:00",
8230                        "20100704T000000.0-08:0", "20100704T000000.0+08:0",
8231                        "20100704T000000.0-24:00", "20100704T000000.0+24:00",
8232                        "20100704T000000.0-12:60", "20100704T000000.0+12:60",
8233                        "2010-07-0400:00:00", "2010-07-04 00:00:00",
8234                        "2010-07-04t00:00:00", "2010-07-04T00:00:00.",
8235                        "2010-Jul-0400:00:00", "2010-Jul-04 00:00:00", "2010-Jul-04t00:00:00",
8236                        "2010-Jul-04T00:00:00", "2010-Jul-04 00:00:00.",
8237                        "2010-12-22T172201", "2010-Dec-22 17:22:01"])
8238         {
8239             assertThrown!DateTimeException(SysTime.fromISOString(str), format("[%s]", str));
8240         }
8241 
8242         static void test(string str, SysTime st, size_t line = __LINE__)
8243         {
8244             if (SysTime.fromISOString(str) != st)
8245                 throw new AssertError("unittest failure", __FILE__, line);
8246         }
8247 
8248         test("20101222T172201", SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
8249         test("19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8250         test("-19990706T123033", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
8251         test("+019990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8252         test("19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8253         test(" 19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8254         test(" 19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8255 
8256         test("19070707T121212.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
8257         test("19070707T121212.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
8258         test("19070707T121212.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
8259         test("20100704T000000.00000000", SysTime(Date(2010, 07, 04)));
8260         test("20100704T000000.00000009", SysTime(Date(2010, 07, 04)));
8261         test("20100704T000000.00000019", SysTime(DateTime(2010, 07, 04), hnsecs(1)));
8262         test("19070707T121212.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
8263         test("19070707T121212.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
8264         test("19070707T121212.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
8265         test("19070707T121212.0010000", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
8266 
8267         auto west60 = new immutable SimpleTimeZone(hours(-1));
8268         auto west90 = new immutable SimpleTimeZone(minutes(-90));
8269         auto west480 = new immutable SimpleTimeZone(hours(-8));
8270         auto east60 = new immutable SimpleTimeZone(hours(1));
8271         auto east90 = new immutable SimpleTimeZone(minutes(90));
8272         auto east480 = new immutable SimpleTimeZone(hours(8));
8273 
8274         test("20101222T172201Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
8275         test("20101222T172201-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8276         test("20101222T172201-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8277         test("20101222T172201-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
8278         test("20101222T172201-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
8279         test("20101222T172201+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8280         test("20101222T172201+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8281         test("20101222T172201+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8282         test("20101222T172201+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
8283 
8284         test("20101103T065106.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
8285         test("20101222T172201.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC()));
8286         test("20101222T172201.23112-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
8287         test("20101222T172201.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), west60));
8288         test("20101222T172201.1-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
8289         test("20101222T172201.55-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
8290         test("20101222T172201.1234567+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
8291         test("20101222T172201.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8292         test("20101222T172201.0000000+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8293         test("20101222T172201.45+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
8294 
8295         // @@@DEPRECATED_2019-07@@@
8296         // This isn't deprecated per se, but that text will make it so that it
8297         // pops up when deprecations are moved along around July 2019. At that
8298         // time, we will update fromISOString so that it is conformant with ISO
8299         // 8601, and it will no longer accept ISO extended time zones (it does
8300         // currently because of issue #15654 - toISOString used to incorrectly
8301         // use the ISO extended time zone format). These tests will then start
8302         // failing will need to be updated accordingly. Also, the notes about
8303         // this issue in toISOString and fromISOString's documentation will need
8304         // to be removed.
8305         test("20101222T172201-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8306         test("20101222T172201-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
8307         test("20101222T172201-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
8308         test("20101222T172201+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8309         test("20101222T172201+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8310         test("20101222T172201+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
8311 
8312         test("20101222T172201.23112-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
8313         test("20101222T172201.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
8314         test("20101222T172201.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
8315         test("20101222T172201.1234567+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
8316         test("20101222T172201.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8317         test("20101222T172201.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
8318     }
8319 
8320     // bug# 17801
8321     @safe unittest
8322     {
8323         import std.conv : to;
8324         import std.meta : AliasSeq;
8325         foreach (C; AliasSeq!(char, wchar, dchar))
8326         {
8327             foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
8328             {
8329                 assert(SysTime.fromISOString(to!S("20121221T141516Z")) ==
8330                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
8331             }
8332         }
8333     }
8334 
8335 
8336     /++
8337         Creates a $(LREF SysTime) from a string with the format
8338         YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds is the
8339         time zone). Whitespace is stripped from the given string.
8340 
8341         The exact format is exactly as described in $(D toISOExtString)
8342         except that trailing zeroes are permitted - including having fractional
8343         seconds with all zeroes. However, a decimal point with nothing following
8344         it is invalid. Also, while $(LREF toISOExtString) will never generate a
8345         string with more than 7 digits in the fractional seconds (because that's
8346         the limit with hecto-nanosecond precision), it will allow more than 7
8347         digits in order to read strings from other sources that have higher
8348         precision (however, any digits beyond 7 will be truncated).
8349 
8350         If there is no time zone in the string, then
8351         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
8352         then $(D UTC) is used. Otherwise, a
8353         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
8354         given offset from UTC is used. To get the returned $(LREF SysTime) to be
8355         a particular time zone, pass in that time zone and the $(LREF SysTime)
8356         to be returned will be converted to that time zone (though it will still
8357         be read in as whatever time zone is in its string).
8358 
8359         The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and
8360         -HH:MM.
8361 
8362         Params:
8363             isoExtString = A string formatted in the ISO Extended format for
8364                            dates and times.
8365             tz           = The time zone to convert the given time to (no
8366                            conversion occurs if null).
8367 
8368         Throws:
8369             $(REF DateTimeException,std,datetime,date) if the given string is
8370             not in the ISO format or if the resulting $(LREF SysTime) would not
8371             be valid.
8372       +/
8373     static SysTime fromISOExtString(S)(in S isoExtString, immutable TimeZone tz = null) @safe
8374         if (isSomeString!(S))
8375     {
8376         import std.algorithm.searching : countUntil, find;
8377         import std.conv : to;
8378         import std.string : strip;
8379 
8380         auto dstr = to!dstring(strip(isoExtString));
8381 
8382         auto tIndex = dstr.countUntil('T');
8383         enforce(tIndex != -1, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
8384 
8385         auto found = dstr[tIndex + 1 .. $].find('.', 'Z', '+', '-');
8386         auto dateTimeStr = dstr[0 .. $ - found[0].length];
8387 
8388         dstring fracSecStr;
8389         dstring zoneStr;
8390 
8391         if (found[1] != 0)
8392         {
8393             if (found[1] == 1)
8394             {
8395                 auto foundTZ = found[0].find('Z', '+', '-');
8396 
8397                 if (foundTZ[1] != 0)
8398                 {
8399                     fracSecStr = found[0][0 .. $ - foundTZ[0].length];
8400                     zoneStr = foundTZ[0];
8401                 }
8402                 else
8403                     fracSecStr = found[0];
8404             }
8405             else
8406                 zoneStr = found[0];
8407         }
8408 
8409         try
8410         {
8411             auto dateTime = DateTime.fromISOExtString(dateTimeStr);
8412             auto fracSec = fracSecsFromISOString(fracSecStr);
8413             Rebindable!(immutable TimeZone) parsedZone;
8414 
8415             if (zoneStr.empty)
8416                 parsedZone = LocalTime();
8417             else if (zoneStr == "Z")
8418                 parsedZone = UTC();
8419             else
8420                 parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
8421 
8422             auto retval = SysTime(dateTime, fracSec, parsedZone);
8423 
8424             if (tz !is null)
8425                 retval.timezone = tz;
8426 
8427             return retval;
8428         }
8429         catch (DateTimeException dte)
8430             throw new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString));
8431     }
8432 
8433     ///
8434     @safe unittest
8435     {
8436         import core.time : hours, msecs, usecs, hnsecs;
8437         import std.datetime.date : DateTime;
8438         import std.datetime.timezone : SimpleTimeZone, UTC;
8439 
8440         assert(SysTime.fromISOExtString("2010-07-04T07:06:12") ==
8441                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8442 
8443         assert(SysTime.fromISOExtString("1998-12-25T02:15:00.007") ==
8444                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
8445 
8446         assert(SysTime.fromISOExtString("0000-01-05T23:09:59.00002") ==
8447                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
8448 
8449         assert(SysTime.fromISOExtString("2013-02-07T04:39:37.000050392") ==
8450                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
8451 
8452         assert(SysTime.fromISOExtString("-0004-01-05T00:00:02") ==
8453                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
8454 
8455         assert(SysTime.fromISOExtString(" 2010-07-04T07:06:12 ") ==
8456                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8457 
8458         assert(SysTime.fromISOExtString("2010-07-04T07:06:12Z") ==
8459                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
8460 
8461         assert(SysTime.fromISOExtString("2010-07-04T07:06:12-08:00") ==
8462                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8463                        new immutable SimpleTimeZone(hours(-8))));
8464         assert(SysTime.fromISOExtString("2010-07-04T07:06:12+08:00") ==
8465                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8466                        new immutable SimpleTimeZone(hours(8))));
8467     }
8468 
8469     @safe unittest
8470     {
8471         foreach (str; ["", "20100704000000", "20100704 000000",
8472                        "20100704t000000", "20100704T000000.", "20100704T000000.0",
8473                        "2010-07:0400:00:00", "2010-07-04 00:00:00",
8474                        "2010-07-04 00:00:00", "2010-07-04t00:00:00",
8475                        "2010-07-04T00:00:00.", "2010-07-04T00:00:00.A", "2010-07-04T00:00:00.Z",
8476                        "2010-07-04T00:00:00.0000000A", "2010-07-04T00:00:00.00000000A",
8477                        "2010-07-04T00:00:00+", "2010-07-04T00:00:00-",
8478                        "2010-07-04T00:00:00:", "2010-07-04T00:00:00-:", "2010-07-04T00:00:00+:",
8479                        "2010-07-04T00:00:00-1:", "2010-07-04T00:00:00+1:", "2010-07-04T00:00:00+1:0",
8480                        "2010-07-04T00:00:00-12.00", "2010-07-04T00:00:00+12.00",
8481                        "2010-07-04T00:00:00-8", "2010-07-04T00:00:00+8",
8482                        "20100704T000000-800", "20100704T000000+800",
8483                        "20100704T000000-080", "20100704T000000+080",
8484                        "20100704T000000-2400", "20100704T000000+2400",
8485                        "20100704T000000-1260", "20100704T000000+1260",
8486                        "20100704T000000.0-800", "20100704T000000.0+800",
8487                        "20100704T000000.0-8", "20100704T000000.0+8",
8488                        "20100704T000000.0-080", "20100704T000000.0+080",
8489                        "20100704T000000.0-2400", "20100704T000000.0+2400",
8490                        "20100704T000000.0-1260", "20100704T000000.0+1260",
8491                        "2010-07-04T00:00:00-8:00", "2010-07-04T00:00:00+8:00",
8492                        "2010-07-04T00:00:00-24:00", "2010-07-04T00:00:00+24:00",
8493                        "2010-07-04T00:00:00-12:60", "2010-07-04T00:00:00+12:60",
8494                        "2010-07-04T00:00:00.0-8:00", "2010-07-04T00:00:00.0+8:00",
8495                        "2010-07-04T00:00:00.0-8", "2010-07-04T00:00:00.0+8",
8496                        "2010-07-04T00:00:00.0-24:00", "2010-07-04T00:00:00.0+24:00",
8497                        "2010-07-04T00:00:00.0-12:60", "2010-07-04T00:00:00.0+12:60",
8498                        "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00",
8499                        "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.0",
8500                        "20101222T172201", "2010-Dec-22 17:22:01"])
8501         {
8502             assertThrown!DateTimeException(SysTime.fromISOExtString(str), format("[%s]", str));
8503         }
8504 
8505         static void test(string str, SysTime st, size_t line = __LINE__)
8506         {
8507             if (SysTime.fromISOExtString(str) != st)
8508                 throw new AssertError("unittest failure", __FILE__, line);
8509         }
8510 
8511         test("2010-12-22T17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
8512         test("1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8513         test("-1999-07-06T12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
8514         test("+01999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8515         test("1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8516         test(" 1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8517         test(" 1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8518 
8519         test("1907-07-07T12:12:12.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
8520         test("1907-07-07T12:12:12.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
8521         test("1907-07-07T12:12:12.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
8522         test("2010-07-04T00:00:00.00000000", SysTime(Date(2010, 07, 04)));
8523         test("2010-07-04T00:00:00.00000009", SysTime(Date(2010, 07, 04)));
8524         test("2010-07-04T00:00:00.00000019", SysTime(DateTime(2010, 07, 04), hnsecs(1)));
8525         test("1907-07-07T12:12:12.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
8526         test("1907-07-07T12:12:12.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
8527         test("1907-07-07T12:12:12.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
8528         test("1907-07-07T12:12:12.0010000", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
8529 
8530         auto west60 = new immutable SimpleTimeZone(hours(-1));
8531         auto west90 = new immutable SimpleTimeZone(minutes(-90));
8532         auto west480 = new immutable SimpleTimeZone(hours(-8));
8533         auto east60 = new immutable SimpleTimeZone(hours(1));
8534         auto east90 = new immutable SimpleTimeZone(minutes(90));
8535         auto east480 = new immutable SimpleTimeZone(hours(8));
8536 
8537         test("2010-12-22T17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
8538         test("2010-12-22T17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8539         test("2010-12-22T17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8540         test("2010-12-22T17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
8541         test("2010-12-22T17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
8542         test("2010-12-22T17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8543         test("2010-12-22T17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8544         test("2010-12-22T17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8545         test("2010-12-22T17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
8546 
8547         test("2010-11-03T06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
8548         test("2010-12-22T17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC()));
8549         test("2010-12-22T17:22:01.23112-01:00",
8550              SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
8551         test("2010-12-22T17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), west60));
8552         test("2010-12-22T17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
8553         test("2010-12-22T17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
8554         test("2010-12-22T17:22:01.1234567+01:00",
8555              SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
8556         test("2010-12-22T17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8557         test("2010-12-22T17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8558         test("2010-12-22T17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
8559     }
8560 
8561     // bug# 17801
8562     @safe unittest
8563     {
8564         import std.conv : to;
8565         import std.meta : AliasSeq;
8566         foreach (C; AliasSeq!(char, wchar, dchar))
8567         {
8568             foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
8569             {
8570                 assert(SysTime.fromISOExtString(to!S("2012-12-21T14:15:16Z")) ==
8571                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
8572             }
8573         }
8574     }
8575 
8576 
8577     /++
8578         Creates a $(LREF SysTime) from a string with the format
8579         YYYY-MM-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds is the
8580         time zone). Whitespace is stripped from the given string.
8581 
8582         The exact format is exactly as described in $(D toSimpleString) except
8583         that trailing zeroes are permitted - including having fractional seconds
8584         with all zeroes. However, a decimal point with nothing following it is
8585         invalid. Also, while $(LREF toSimpleString) will never generate a
8586         string with more than 7 digits in the fractional seconds (because that's
8587         the limit with hecto-nanosecond precision), it will allow more than 7
8588         digits in order to read strings from other sources that have higher
8589         precision (however, any digits beyond 7 will be truncated).
8590 
8591         If there is no time zone in the string, then
8592         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
8593         then $(D UTC) is used. Otherwise, a
8594         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
8595         given offset from UTC is used. To get the returned $(LREF SysTime) to be
8596         a particular time zone, pass in that time zone and the $(LREF SysTime)
8597         to be returned will be converted to that time zone (though it will still
8598         be read in as whatever time zone is in its string).
8599 
8600         The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and
8601         -HH:MM.
8602 
8603         Params:
8604             simpleString = A string formatted in the way that
8605                            $(D toSimpleString) formats dates and times.
8606             tz           = The time zone to convert the given time to (no
8607                            conversion occurs if null).
8608 
8609         Throws:
8610             $(REF DateTimeException,std,datetime,date) if the given string is
8611             not in the ISO format or if the resulting $(LREF SysTime) would not
8612             be valid.
8613       +/
8614     static SysTime fromSimpleString(S)(in S simpleString, immutable TimeZone tz = null) @safe
8615         if (isSomeString!(S))
8616     {
8617         import std.algorithm.searching : countUntil, find;
8618         import std.conv : to;
8619         import std.string : strip;
8620 
8621         auto dstr = to!dstring(strip(simpleString));
8622 
8623         auto spaceIndex = dstr.countUntil(' ');
8624         enforce(spaceIndex != -1, new DateTimeException(format("Invalid Simple String: %s", simpleString)));
8625 
8626         auto found = dstr[spaceIndex + 1 .. $].find('.', 'Z', '+', '-');
8627         auto dateTimeStr = dstr[0 .. $ - found[0].length];
8628 
8629         dstring fracSecStr;
8630         dstring zoneStr;
8631 
8632         if (found[1] != 0)
8633         {
8634             if (found[1] == 1)
8635             {
8636                 auto foundTZ = found[0].find('Z', '+', '-');
8637 
8638                 if (foundTZ[1] != 0)
8639                 {
8640                     fracSecStr = found[0][0 .. $ - foundTZ[0].length];
8641                     zoneStr = foundTZ[0];
8642                 }
8643                 else
8644                     fracSecStr = found[0];
8645             }
8646             else
8647                 zoneStr = found[0];
8648         }
8649 
8650         try
8651         {
8652             auto dateTime = DateTime.fromSimpleString(dateTimeStr);
8653             auto fracSec = fracSecsFromISOString(fracSecStr);
8654             Rebindable!(immutable TimeZone) parsedZone;
8655 
8656             if (zoneStr.empty)
8657                 parsedZone = LocalTime();
8658             else if (zoneStr == "Z")
8659                 parsedZone = UTC();
8660             else
8661                 parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
8662 
8663             auto retval = SysTime(dateTime, fracSec, parsedZone);
8664 
8665             if (tz !is null)
8666                 retval.timezone = tz;
8667 
8668             return retval;
8669         }
8670         catch (DateTimeException dte)
8671             throw new DateTimeException(format("Invalid Simple String: %s", simpleString));
8672     }
8673 
8674     ///
8675     @safe unittest
8676     {
8677         import core.time : hours, msecs, usecs, hnsecs;
8678         import std.datetime.date : DateTime;
8679         import std.datetime.timezone : SimpleTimeZone, UTC;
8680 
8681         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12") ==
8682                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8683 
8684         assert(SysTime.fromSimpleString("1998-Dec-25 02:15:00.007") ==
8685                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
8686 
8687         assert(SysTime.fromSimpleString("0000-Jan-05 23:09:59.00002") ==
8688                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
8689 
8690         assert(SysTime.fromSimpleString("2013-Feb-07 04:39:37.000050392") ==
8691                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
8692 
8693         assert(SysTime.fromSimpleString("-0004-Jan-05 00:00:02") ==
8694                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
8695 
8696         assert(SysTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") ==
8697                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8698 
8699         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12Z") ==
8700                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
8701 
8702         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12-08:00") ==
8703                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8704                        new immutable SimpleTimeZone(hours(-8))));
8705 
8706         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12+08:00") ==
8707                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8708                        new immutable SimpleTimeZone(hours(8))));
8709     }
8710 
8711     @safe unittest
8712     {
8713         foreach (str; ["", "20100704000000", "20100704 000000",
8714                        "20100704t000000", "20100704T000000.", "20100704T000000.0",
8715                        "2010-07-0400:00:00", "2010-07-04 00:00:00", "2010-07-04t00:00:00",
8716                        "2010-07-04T00:00:00.", "2010-07-04T00:00:00.0",
8717                        "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00", "2010-Jul-04T00:00:00",
8718                        "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.A", "2010-Jul-04 00:00:00.Z",
8719                        "2010-Jul-04 00:00:00.0000000A", "2010-Jul-04 00:00:00.00000000A",
8720                        "2010-Jul-04 00:00:00+", "2010-Jul-04 00:00:00-",
8721                        "2010-Jul-04 00:00:00:", "2010-Jul-04 00:00:00-:",
8722                        "2010-Jul-04 00:00:00+:", "2010-Jul-04 00:00:00-1:",
8723                        "2010-Jul-04 00:00:00+1:", "2010-Jul-04 00:00:00+1:0",
8724                        "2010-Jul-04 00:00:00-12.00", "2010-Jul-04 00:00:00+12.00",
8725                        "2010-Jul-04 00:00:00-8", "2010-Jul-04 00:00:00+8",
8726                        "20100704T000000-800", "20100704T000000+800",
8727                        "20100704T000000-080", "20100704T000000+080",
8728                        "20100704T000000-2400", "20100704T000000+2400",
8729                        "20100704T000000-1260", "20100704T000000+1260",
8730                        "20100704T000000.0-800", "20100704T000000.0+800",
8731                        "20100704T000000.0-8", "20100704T000000.0+8",
8732                        "20100704T000000.0-080", "20100704T000000.0+080",
8733                        "20100704T000000.0-2400", "20100704T000000.0+2400",
8734                        "20100704T000000.0-1260", "20100704T000000.0+1260",
8735                        "2010-Jul-04 00:00:00-8:00", "2010-Jul-04 00:00:00+8:00",
8736                        "2010-Jul-04 00:00:00-08:0", "2010-Jul-04 00:00:00+08:0",
8737                        "2010-Jul-04 00:00:00-24:00", "2010-Jul-04 00:00:00+24:00",
8738                        "2010-Jul-04 00:00:00-12:60", "2010-Jul-04 00:00:00+24:60",
8739                        "2010-Jul-04 00:00:00.0-8:00", "2010-Jul-04 00:00:00+8:00",
8740                        "2010-Jul-04 00:00:00.0-8", "2010-Jul-04 00:00:00.0+8",
8741                        "2010-Jul-04 00:00:00.0-08:0", "2010-Jul-04 00:00:00.0+08:0",
8742                        "2010-Jul-04 00:00:00.0-24:00", "2010-Jul-04 00:00:00.0+24:00",
8743                        "2010-Jul-04 00:00:00.0-12:60", "2010-Jul-04 00:00:00.0+24:60",
8744                        "20101222T172201", "2010-12-22T172201"])
8745         {
8746             assertThrown!DateTimeException(SysTime.fromSimpleString(str), format("[%s]", str));
8747         }
8748 
8749         static void test(string str, SysTime st, size_t line = __LINE__)
8750         {
8751             if (SysTime.fromSimpleString(str) != st)
8752                 throw new AssertError("unittest failure", __FILE__, line);
8753         }
8754 
8755         test("2010-Dec-22 17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
8756         test("1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8757         test("-1999-Jul-06 12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
8758         test("+01999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8759         test("1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8760         test(" 1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8761         test(" 1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8762 
8763         test("1907-Jul-07 12:12:12.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
8764         test("1907-Jul-07 12:12:12.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
8765         test("2010-Jul-04 00:00:00.00000000", SysTime(Date(2010, 07, 04)));
8766         test("2010-Jul-04 00:00:00.00000009", SysTime(Date(2010, 07, 04)));
8767         test("2010-Jul-04 00:00:00.00000019", SysTime(DateTime(2010, 07, 04), hnsecs(1)));
8768         test("1907-Jul-07 12:12:12.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
8769         test("1907-Jul-07 12:12:12.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
8770         test("1907-Jul-07 12:12:12.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
8771         test("1907-Jul-07 12:12:12.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
8772         test("1907-Jul-07 12:12:12.0010000", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
8773 
8774         auto west60 = new immutable SimpleTimeZone(hours(-1));
8775         auto west90 = new immutable SimpleTimeZone(minutes(-90));
8776         auto west480 = new immutable SimpleTimeZone(hours(-8));
8777         auto east60 = new immutable SimpleTimeZone(hours(1));
8778         auto east90 = new immutable SimpleTimeZone(minutes(90));
8779         auto east480 = new immutable SimpleTimeZone(hours(8));
8780 
8781         test("2010-Dec-22 17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
8782         test("2010-Dec-22 17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8783         test("2010-Dec-22 17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
8784         test("2010-Dec-22 17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
8785         test("2010-Dec-22 17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
8786         test("2010-Dec-22 17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8787         test("2010-Dec-22 17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8788         test("2010-Dec-22 17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8789         test("2010-Dec-22 17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
8790 
8791         test("2010-Nov-03 06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
8792         test("2010-Dec-22 17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC()));
8793         test("2010-Dec-22 17:22:01.23112-01:00",
8794              SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
8795         test("2010-Dec-22 17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), west60));
8796         test("2010-Dec-22 17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
8797         test("2010-Dec-22 17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
8798         test("2010-Dec-22 17:22:01.1234567+01:00",
8799              SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
8800         test("2010-Dec-22 17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
8801         test("2010-Dec-22 17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
8802         test("2010-Dec-22 17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
8803     }
8804 
8805     // bug# 17801
8806     @safe unittest
8807     {
8808         import std.conv : to;
8809         import std.meta : AliasSeq;
8810         foreach (C; AliasSeq!(char, wchar, dchar))
8811         {
8812             foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
8813             {
8814                 assert(SysTime.fromSimpleString(to!S("2012-Dec-21 14:15:16Z")) ==
8815                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
8816             }
8817         }
8818     }
8819 
8820 
8821     /++
8822         Returns the $(LREF SysTime) farthest in the past which is representable
8823         by $(LREF SysTime).
8824 
8825         The $(LREF SysTime) which is returned is in UTC.
8826       +/
8827     @property static SysTime min() @safe pure nothrow
8828     {
8829         return SysTime(long.min, UTC());
8830     }
8831 
8832     @safe unittest
8833     {
8834         assert(SysTime.min.year < 0);
8835         assert(SysTime.min < SysTime.max);
8836     }
8837 
8838 
8839     /++
8840         Returns the $(LREF SysTime) farthest in the future which is representable
8841         by $(LREF SysTime).
8842 
8843         The $(LREF SysTime) which is returned is in UTC.
8844       +/
8845     @property static SysTime max() @safe pure nothrow
8846     {
8847         return SysTime(long.max, UTC());
8848     }
8849 
8850     @safe unittest
8851     {
8852         assert(SysTime.max.year > 0);
8853         assert(SysTime.max > SysTime.min);
8854     }
8855 
8856 
8857 private:
8858 
8859     /+
8860         Returns $(D stdTime) converted to $(LREF SysTime)'s time zone.
8861       +/
8862     @property long adjTime() @safe const nothrow
8863     {
8864         return _timezone.utcToTZ(_stdTime);
8865     }
8866 
8867 
8868     /+
8869         Converts the given hnsecs from $(LREF SysTime)'s time zone to std time.
8870       +/
8871     @property void adjTime(long adjTime) @safe nothrow
8872     {
8873         _stdTime = _timezone.tzToUTC(adjTime);
8874     }
8875 
8876 
8877     // Commented out due to bug http://d.puremagic.com/issues/show_bug.cgi?id=5058
8878     /+
8879     invariant()
8880     {
8881         assert(_timezone !is null, "Invariant Failure: timezone is null. Were you foolish enough to use " ~
8882                                    "SysTime.init? (since timezone for SysTime.init can't be set at compile time).");
8883     }
8884     +/
8885 
8886 
8887     long  _stdTime;
8888     Rebindable!(immutable TimeZone) _timezone;
8889 }
8890 
8891 
8892 /++
8893     Converts from unix time (which uses midnight, January 1st, 1970 UTC as its
8894     epoch and seconds as its units) to "std time" (which uses midnight,
8895     January 1st, 1 A.D. UTC and hnsecs as its units).
8896 
8897     The C standard does not specify the representation of time_t, so it is
8898     implementation defined. On POSIX systems, unix time is equivalent to
8899     time_t, but that's not necessarily true on other systems (e.g. it is
8900     not true for the Digital Mars C runtime). So, be careful when using unix
8901     time with C functions on non-POSIX systems.
8902 
8903     "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO
8904     8601 and is what $(LREF SysTime) uses internally. However, holding the time
8905     as an integer in hnescs since that epoch technically isn't actually part of
8906     the standard, much as it's based on it, so the name "std time" isn't
8907     particularly good, but there isn't an official name for it. C# uses "ticks"
8908     for the same thing, but they aren't actually clock ticks, and the term
8909     "ticks" $(I is) used for actual clock ticks for $(REF MonoTime, core,time),
8910     so it didn't make sense to use the term ticks here. So, for better or worse,
8911     std.datetime uses the term "std time" for this.
8912 
8913     Params:
8914         unixTime = The unix time to convert.
8915 
8916     See_Also:
8917         SysTime.fromUnixTime
8918   +/
unixTimeToStdTime(long unixTime)8919 long unixTimeToStdTime(long unixTime) @safe pure nothrow
8920 {
8921     return 621_355_968_000_000_000L + convert!("seconds", "hnsecs")(unixTime);
8922 }
8923 
8924 ///
8925 @safe unittest
8926 {
8927     import std.datetime.date : DateTime;
8928     import std.datetime.timezone : UTC;
8929 
8930     // Midnight, January 1st, 1970
8931     assert(unixTimeToStdTime(0) == 621_355_968_000_000_000L);
8932     assert(SysTime(unixTimeToStdTime(0)) ==
8933            SysTime(DateTime(1970, 1, 1), UTC()));
8934 
8935     assert(unixTimeToStdTime(int.max) == 642_830_804_470_000_000L);
8936     assert(SysTime(unixTimeToStdTime(int.max)) ==
8937            SysTime(DateTime(2038, 1, 19, 3, 14, 07), UTC()));
8938 
8939     assert(unixTimeToStdTime(-127_127) == 621_354_696_730_000_000L);
8940     assert(SysTime(unixTimeToStdTime(-127_127)) ==
8941            SysTime(DateTime(1969, 12, 30, 12, 41, 13), UTC()));
8942 }
8943 
8944 @safe unittest
8945 {
8946     // Midnight, January 2nd, 1970
8947     assert(unixTimeToStdTime(86_400) == 621_355_968_000_000_000L + 864_000_000_000L);
8948     // Midnight, December 31st, 1969
8949     assert(unixTimeToStdTime(-86_400) == 621_355_968_000_000_000L - 864_000_000_000L);
8950 
8951     assert(unixTimeToStdTime(0) == (Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs");
8952     assert(unixTimeToStdTime(0) == (DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs");
8953 
8954     foreach (dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)])
8955         assert(unixTimeToStdTime((dt - DateTime(1970, 1, 1)).total!"seconds") == (dt - DateTime.init).total!"hnsecs");
8956 }
8957 
8958 
8959 /++
8960     Converts std time (which uses midnight, January 1st, 1 A.D. UTC as its epoch
8961     and hnsecs as its units) to unix time (which uses midnight, January 1st,
8962     1970 UTC as its epoch and seconds as its units).
8963 
8964     The C standard does not specify the representation of time_t, so it is
8965     implementation defined. On POSIX systems, unix time is equivalent to
8966     time_t, but that's not necessarily true on other systems (e.g. it is
8967     not true for the Digital Mars C runtime). So, be careful when using unix
8968     time with C functions on non-POSIX systems.
8969 
8970     "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO
8971     8601 and is what $(LREF SysTime) uses internally. However, holding the time
8972     as an integer in hnescs since that epoch technically isn't actually part of
8973     the standard, much as it's based on it, so the name "std time" isn't
8974     particularly good, but there isn't an official name for it. C# uses "ticks"
8975     for the same thing, but they aren't actually clock ticks, and the term
8976     "ticks" $(I is) used for actual clock ticks for $(REF MonoTime, core,time),
8977     so it didn't make sense to use the term ticks here. So, for better or worse,
8978     std.datetime uses the term "std time" for this.
8979 
8980     By default, the return type is time_t (which is normally an alias for
8981     int on 32-bit systems and long on 64-bit systems), but if a different
8982     size is required than either int or long can be passed as a template
8983     argument to get the desired size.
8984 
8985     If the return type is int, and the result can't fit in an int, then the
8986     closest value that can be held in 32 bits will be used (so $(D int.max)
8987     if it goes over and $(D int.min) if it goes under). However, no attempt
8988     is made to deal with integer overflow if the return type is long.
8989 
8990     Params:
8991         T = The return type (int or long). It defaults to time_t, which is
8992             normally 32 bits on a 32-bit system and 64 bits on a 64-bit
8993             system.
8994         stdTime = The std time to convert.
8995 
8996     Returns:
8997         A signed integer representing the unix time which is equivalent to
8998         the given std time.
8999 
9000     See_Also:
9001         SysTime.toUnixTime
9002   +/
9003 T stdTimeToUnixTime(T = time_t)(long stdTime) @safe pure nothrow
9004 if (is(T == int) || is(T == long))
9005 {
9006     immutable unixTime = convert!("hnsecs", "seconds")(stdTime - 621_355_968_000_000_000L);
9007 
9008     static assert(is(time_t == int) || is(time_t == long),
9009                   "Currently, std.datetime only supports systems where time_t is int or long");
9010 
9011     static if (is(T == long))
9012         return unixTime;
9013     else static if (is(T == int))
9014     {
9015         if (unixTime > int.max)
9016             return int.max;
9017         return unixTime < int.min ? int.min : cast(int) unixTime;
9018     }
9019     else
9020         static assert(0, "Bug in template constraint. Only int and long allowed.");
9021 }
9022 
9023 ///
9024 @safe unittest
9025 {
9026     // Midnight, January 1st, 1970 UTC
9027     assert(stdTimeToUnixTime(621_355_968_000_000_000L) == 0);
9028 
9029     // 2038-01-19 03:14:07 UTC
9030     assert(stdTimeToUnixTime(642_830_804_470_000_000L) == int.max);
9031 }
9032 
9033 @safe unittest
9034 {
9035     enum unixEpochAsStdTime = (Date(1970, 1, 1) - Date.init).total!"hnsecs";
9036 
9037     assert(stdTimeToUnixTime(unixEpochAsStdTime) == 0);  // Midnight, January 1st, 1970
9038     assert(stdTimeToUnixTime(unixEpochAsStdTime + 864_000_000_000L) == 86_400);  // Midnight, January 2nd, 1970
9039     assert(stdTimeToUnixTime(unixEpochAsStdTime - 864_000_000_000L) == -86_400);  // Midnight, December 31st, 1969
9040 
9041     assert(stdTimeToUnixTime((Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs") == 0);
9042     assert(stdTimeToUnixTime((DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs") == 0);
9043 
9044     foreach (dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)])
9045         assert(stdTimeToUnixTime((dt - DateTime.init).total!"hnsecs") == (dt - DateTime(1970, 1, 1)).total!"seconds");
9046 
9047     enum max = convert!("seconds", "hnsecs")(int.max);
9048     enum min = convert!("seconds", "hnsecs")(int.min);
9049     enum one = convert!("seconds", "hnsecs")(1);
9050 
9051     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max) == int.max);
9052     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max) == int.max);
9053 
9054     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + one) == int.max + 1L);
9055     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + one) == int.max);
9056     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + 9_999_999) == int.max);
9057     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + 9_999_999) == int.max);
9058 
9059     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min) == int.min);
9060     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min) == int.min);
9061 
9062     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - one) == int.min - 1L);
9063     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - one) == int.min);
9064     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - 9_999_999) == int.min);
9065     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - 9_999_999) == int.min);
9066 }
9067 
9068 
version(StdDdoc)9069 version (StdDdoc)
9070 {
9071     version (Windows)
9072     {}
9073     else
9074     {
9075         alias SYSTEMTIME = void*;
9076         alias FILETIME = void*;
9077     }
9078 
9079     /++
9080         $(BLUE This function is Windows-Only.)
9081 
9082         Converts a $(D SYSTEMTIME) struct to a $(LREF SysTime).
9083 
9084         Params:
9085             st = The $(D SYSTEMTIME) struct to convert.
9086             tz = The time zone that the time in the $(D SYSTEMTIME) struct is
9087                  assumed to be (if the $(D SYSTEMTIME) was supplied by a Windows
9088                  system call, the $(D SYSTEMTIME) will either be in local time
9089                  or UTC, depending on the call).
9090 
9091         Throws:
9092             $(REF DateTimeException,std,datetime,date) if the given
9093             $(D SYSTEMTIME) will not fit in a $(LREF SysTime), which is highly
9094             unlikely to happen given that $(D SysTime.max) is in 29,228 A.D. and
9095             the maximum $(D SYSTEMTIME) is in 30,827 A.D.
9096       +/
9097     SysTime SYSTEMTIMEToSysTime(const SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe;
9098 
9099 
9100     /++
9101         $(BLUE This function is Windows-Only.)
9102 
9103         Converts a $(LREF SysTime) to a $(D SYSTEMTIME) struct.
9104 
9105         The $(D SYSTEMTIME) which is returned will be set using the given
9106         $(LREF SysTime)'s time zone, so to get the $(D SYSTEMTIME) in
9107         UTC, set the $(LREF SysTime)'s time zone to UTC.
9108 
9109         Params:
9110             sysTime = The $(LREF SysTime) to convert.
9111 
9112         Throws:
9113             $(REF DateTimeException,std,datetime,date) if the given
9114             $(LREF SysTime) will not fit in a $(D SYSTEMTIME). This will only
9115             happen if the $(LREF SysTime)'s date is prior to 1601 A.D.
9116       +/
9117     SYSTEMTIME SysTimeToSYSTEMTIME(in SysTime sysTime) @safe;
9118 
9119 
9120     /++
9121         $(BLUE This function is Windows-Only.)
9122 
9123         Converts a $(D FILETIME) struct to the number of hnsecs since midnight,
9124         January 1st, 1 A.D.
9125 
9126         Params:
9127             ft = The $(D FILETIME) struct to convert.
9128 
9129         Throws:
9130             $(REF DateTimeException,std,datetime,date) if the given
9131             $(D FILETIME) cannot be represented as the return value.
9132       +/
9133     long FILETIMEToStdTime(scope const FILETIME* ft) @safe;
9134 
9135 
9136     /++
9137         $(BLUE This function is Windows-Only.)
9138 
9139         Converts a $(D FILETIME) struct to a $(LREF SysTime).
9140 
9141         Params:
9142             ft = The $(D FILETIME) struct to convert.
9143             tz = The time zone that the $(LREF SysTime) will be in
9144                  ($(D FILETIME)s are in UTC).
9145 
9146         Throws:
9147             $(REF DateTimeException,std,datetime,date) if the given
9148             $(D FILETIME) will not fit in a $(LREF SysTime).
9149       +/
9150     SysTime FILETIMEToSysTime(scope const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe;
9151 
9152 
9153     /++
9154         $(BLUE This function is Windows-Only.)
9155 
9156         Converts a number of hnsecs since midnight, January 1st, 1 A.D. to a
9157         $(D FILETIME) struct.
9158 
9159         Params:
9160             stdTime = The number of hnsecs since midnight, January 1st, 1 A.D.
9161                       UTC.
9162 
9163         Throws:
9164             $(REF DateTimeException,std,datetime,date) if the given value will
9165             not fit in a $(D FILETIME).
9166       +/
9167     FILETIME stdTimeToFILETIME(long stdTime) @safe;
9168 
9169 
9170     /++
9171         $(BLUE This function is Windows-Only.)
9172 
9173         Converts a $(LREF SysTime) to a $(D FILETIME) struct.
9174 
9175         $(D FILETIME)s are always in UTC.
9176 
9177         Params:
9178             sysTime = The $(LREF SysTime) to convert.
9179 
9180         Throws:
9181             $(REF DateTimeException,std,datetime,date) if the given
9182             $(LREF SysTime) will not fit in a $(D FILETIME).
9183       +/
9184     FILETIME SysTimeToFILETIME(SysTime sysTime) @safe;
9185 }
9186 else version (Windows)
9187 {
9188     SysTime SYSTEMTIMEToSysTime(const SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe
9189     {
9190         const max = SysTime.max;
9191 
9192         static void throwLaterThanMax()
9193         {
9194             throw new DateTimeException("The given SYSTEMTIME is for a date greater than SysTime.max.");
9195         }
9196 
9197         if (st.wYear > max.year)
9198             throwLaterThanMax();
9199         else if (st.wYear == max.year)
9200         {
9201             if (st.wMonth > max.month)
9202                 throwLaterThanMax();
9203             else if (st.wMonth == max.month)
9204             {
9205                 if (st.wDay > max.day)
9206                     throwLaterThanMax();
9207                 else if (st.wDay == max.day)
9208                 {
9209                     if (st.wHour > max.hour)
9210                         throwLaterThanMax();
9211                     else if (st.wHour == max.hour)
9212                     {
9213                         if (st.wMinute > max.minute)
9214                             throwLaterThanMax();
9215                         else if (st.wMinute == max.minute)
9216                         {
9217                             if (st.wSecond > max.second)
9218                                 throwLaterThanMax();
9219                             else if (st.wSecond == max.second)
9220                             {
9221                                 if (st.wMilliseconds > max.fracSecs.total!"msecs")
9222                                     throwLaterThanMax();
9223                             }
9224                         }
9225                     }
9226                 }
9227             }
9228         }
9229 
9230         auto dt = DateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
9231 
9232         return SysTime(dt, msecs(st.wMilliseconds), tz);
9233     }
9234 
9235     @system unittest
9236     {
9237         auto sysTime = Clock.currTime(UTC());
9238         SYSTEMTIME st = void;
9239         GetSystemTime(&st);
9240         auto converted = SYSTEMTIMEToSysTime(&st, UTC());
9241 
9242         assert(abs((converted - sysTime)) <= dur!"seconds"(2));
9243     }
9244 
9245 
9246     SYSTEMTIME SysTimeToSYSTEMTIME(in SysTime sysTime) @safe
9247     {
9248         immutable dt = cast(DateTime) sysTime;
9249 
9250         if (dt.year < 1601)
9251             throw new DateTimeException("SYSTEMTIME cannot hold dates prior to the year 1601.");
9252 
9253         SYSTEMTIME st;
9254 
9255         st.wYear = dt.year;
9256         st.wMonth = dt.month;
9257         st.wDayOfWeek = dt.dayOfWeek;
9258         st.wDay = dt.day;
9259         st.wHour = dt.hour;
9260         st.wMinute = dt.minute;
9261         st.wSecond = dt.second;
9262         st.wMilliseconds = cast(ushort) sysTime.fracSecs.total!"msecs";
9263 
9264         return st;
9265     }
9266 
9267     @system unittest
9268     {
9269         SYSTEMTIME st = void;
9270         GetSystemTime(&st);
9271         auto sysTime = SYSTEMTIMEToSysTime(&st, UTC());
9272 
9273         SYSTEMTIME result = SysTimeToSYSTEMTIME(sysTime);
9274 
9275         assert(st.wYear == result.wYear);
9276         assert(st.wMonth == result.wMonth);
9277         assert(st.wDayOfWeek == result.wDayOfWeek);
9278         assert(st.wDay == result.wDay);
9279         assert(st.wHour == result.wHour);
9280         assert(st.wMinute == result.wMinute);
9281         assert(st.wSecond == result.wSecond);
9282         assert(st.wMilliseconds == result.wMilliseconds);
9283     }
9284 
9285     private enum hnsecsFrom1601 = 504_911_232_000_000_000L;
9286 
9287     long FILETIMEToStdTime(scope const FILETIME* ft) @safe
9288     {
9289         ULARGE_INTEGER ul;
9290         ul.HighPart = ft.dwHighDateTime;
9291         ul.LowPart = ft.dwLowDateTime;
9292         ulong tempHNSecs = ul.QuadPart;
9293 
9294         if (tempHNSecs > long.max - hnsecsFrom1601)
9295             throw new DateTimeException("The given FILETIME cannot be represented as a stdTime value.");
9296 
9297         return cast(long) tempHNSecs + hnsecsFrom1601;
9298     }
9299 
9300     SysTime FILETIMEToSysTime(scope const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe
9301     {
9302         auto sysTime = SysTime(FILETIMEToStdTime(ft), UTC());
9303         sysTime.timezone = tz;
9304         return sysTime;
9305     }
9306 
9307     @system unittest
9308     {
9309         auto sysTime = Clock.currTime(UTC());
9310         SYSTEMTIME st = void;
9311         GetSystemTime(&st);
9312 
9313         FILETIME ft = void;
9314         SystemTimeToFileTime(&st, &ft);
9315 
9316         auto converted = FILETIMEToSysTime(&ft);
9317 
9318         assert(abs((converted - sysTime)) <= dur!"seconds"(2));
9319     }
9320 
9321 
9322     FILETIME stdTimeToFILETIME(long stdTime) @safe
9323     {
9324         if (stdTime < hnsecsFrom1601)
9325             throw new DateTimeException("The given stdTime value cannot be represented as a FILETIME.");
9326 
9327         ULARGE_INTEGER ul;
9328         ul.QuadPart = cast(ulong) stdTime - hnsecsFrom1601;
9329 
9330         FILETIME ft;
9331         ft.dwHighDateTime = ul.HighPart;
9332         ft.dwLowDateTime = ul.LowPart;
9333 
9334         return ft;
9335     }
9336 
9337     FILETIME SysTimeToFILETIME(SysTime sysTime) @safe
9338     {
9339         return stdTimeToFILETIME(sysTime.stdTime);
9340     }
9341 
9342     @system unittest
9343     {
9344         SYSTEMTIME st = void;
9345         GetSystemTime(&st);
9346 
9347         FILETIME ft = void;
9348         SystemTimeToFileTime(&st, &ft);
9349         auto sysTime = FILETIMEToSysTime(&ft, UTC());
9350 
9351         FILETIME result = SysTimeToFILETIME(sysTime);
9352 
9353         assert(ft.dwLowDateTime == result.dwLowDateTime);
9354         assert(ft.dwHighDateTime == result.dwHighDateTime);
9355     }
9356 }
9357 
9358 
9359 /++
9360     Type representing the DOS file date/time format.
9361   +/
9362 alias DosFileTime = uint;
9363 
9364 /++
9365     Converts from DOS file date/time to $(LREF SysTime).
9366 
9367     Params:
9368         dft = The DOS file time to convert.
9369         tz  = The time zone which the DOS file time is assumed to be in.
9370 
9371     Throws:
9372         $(REF DateTimeException,std,datetime,date) if the $(D DosFileTime) is
9373         invalid.
9374   +/
9375 SysTime DosFileTimeToSysTime(DosFileTime dft, immutable TimeZone tz = LocalTime()) @safe
9376 {
9377     uint dt = cast(uint) dft;
9378 
9379     if (dt == 0)
9380         throw new DateTimeException("Invalid DosFileTime.");
9381 
9382     int year = ((dt >> 25) & 0x7F) + 1980;
9383     int month = ((dt >> 21) & 0x0F);       // 1 .. 12
9384     int dayOfMonth = ((dt >> 16) & 0x1F);  // 1 .. 31
9385     int hour = (dt >> 11) & 0x1F;          // 0 .. 23
9386     int minute = (dt >> 5) & 0x3F;         // 0 .. 59
9387     int second = (dt << 1) & 0x3E;         // 0 .. 58 (in 2 second increments)
9388 
9389     try
9390         return SysTime(DateTime(year, month, dayOfMonth, hour, minute, second), tz);
9391     catch (DateTimeException dte)
9392         throw new DateTimeException("Invalid DosFileTime", __FILE__, __LINE__, dte);
9393 }
9394 
9395 @safe unittest
9396 {
9397     assert(DosFileTimeToSysTime(0b00000000001000010000000000000000) == SysTime(DateTime(1980, 1, 1, 0, 0, 0)));
9398     assert(DosFileTimeToSysTime(0b11111111100111111011111101111101) == SysTime(DateTime(2107, 12, 31, 23, 59, 58)));
9399     assert(DosFileTimeToSysTime(0x3E3F8456) == SysTime(DateTime(2011, 1, 31, 16, 34, 44)));
9400 }
9401 
9402 
9403 /++
9404     Converts from $(LREF SysTime) to DOS file date/time.
9405 
9406     Params:
9407         sysTime = The $(LREF SysTime) to convert.
9408 
9409     Throws:
9410         $(REF DateTimeException,std,datetime,date) if the given
9411         $(LREF SysTime) cannot be converted to a $(D DosFileTime).
9412   +/
9413 DosFileTime SysTimeToDosFileTime(SysTime sysTime) @safe
9414 {
9415     auto dateTime = cast(DateTime) sysTime;
9416 
9417     if (dateTime.year < 1980)
9418         throw new DateTimeException("DOS File Times cannot hold dates prior to 1980.");
9419 
9420     if (dateTime.year > 2107)
9421         throw new DateTimeException("DOS File Times cannot hold dates past 2107.");
9422 
9423     uint retval = 0;
9424     retval = (dateTime.year - 1980) << 25;
9425     retval |= (dateTime.month & 0x0F) << 21;
9426     retval |= (dateTime.day & 0x1F) << 16;
9427     retval |= (dateTime.hour & 0x1F) << 11;
9428     retval |= (dateTime.minute & 0x3F) << 5;
9429     retval |= (dateTime.second >> 1) & 0x1F;
9430 
9431     return cast(DosFileTime) retval;
9432 }
9433 
9434 @safe unittest
9435 {
9436     assert(SysTimeToDosFileTime(SysTime(DateTime(1980, 1, 1, 0, 0, 0))) == 0b00000000001000010000000000000000);
9437     assert(SysTimeToDosFileTime(SysTime(DateTime(2107, 12, 31, 23, 59, 58))) == 0b11111111100111111011111101111101);
9438     assert(SysTimeToDosFileTime(SysTime(DateTime(2011, 1, 31, 16, 34, 44))) == 0x3E3F8456);
9439 }
9440 
9441 
9442 /++
9443     The given array of $(D char) or random-access range of $(D char) or
9444     $(D ubyte) is expected to be in the format specified in
9445     $(HTTP tools.ietf.org/html/rfc5322, RFC 5322) section 3.3 with the
9446     grammar rule $(I date-time). It is the date-time format commonly used in
9447     internet messages such as e-mail and HTTP. The corresponding
9448     $(LREF SysTime) will be returned.
9449 
9450     RFC 822 was the original spec (hence the function's name), whereas RFC 5322
9451     is the current spec.
9452 
9453     The day of the week is ignored beyond verifying that it's a valid day of the
9454     week, as the day of the week can be inferred from the date. It is not
9455     checked whether the given day of the week matches the actual day of the week
9456     of the given date (though it is technically invalid per the spec if the
9457     day of the week doesn't match the actual day of the week of the given date).
9458 
9459     If the time zone is $(D "-0000") (or considered to be equivalent to
9460     $(D "-0000") by section 4.3 of the spec), a
9461     $(REF SimpleTimeZone,std,datetime,timezone) with a utc offset of $(D 0) is
9462     used rather than $(REF UTC,std,datetime,timezone), whereas $(D "+0000") uses
9463     $(REF UTC,std,datetime,timezone).
9464 
9465     Note that because $(LREF SysTime) does not currently support having a second
9466     value of 60 (as is sometimes done for leap seconds), if the date-time value
9467     does have a value of 60 for the seconds, it is treated as 59.
9468 
9469     The one area in which this function violates RFC 5322 is that it accepts
9470     $(D "\n") in folding whitespace in the place of $(D "\r\n"), because the
9471     HTTP spec requires it.
9472 
9473     Throws:
9474         $(REF DateTimeException,std,datetime,date) if the given string doesn't
9475         follow the grammar for a date-time field or if the resulting
9476         $(LREF SysTime) is invalid.
9477   +/
9478 SysTime parseRFC822DateTime()(in char[] value) @safe
9479 {
9480     import std.string : representation;
9481     return parseRFC822DateTime(value.representation);
9482 }
9483 
9484 /++ Ditto +/
9485 SysTime parseRFC822DateTime(R)(R value) @safe
9486 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
9487     (is(Unqual!(ElementType!R) == char) || is(Unqual!(ElementType!R) == ubyte)))
9488 {
9489     import std.algorithm.searching : find, all;
9490     import std.ascii : isDigit, isAlpha, isPrintable;
9491     import std.conv : to;
9492     import std.functional : not;
9493     import std.string : capitalize, format;
9494     import std.traits : EnumMembers, isArray;
9495     import std.typecons : Rebindable;
9496 
9497     void stripAndCheckLen(R valueBefore, size_t minLen, size_t line = __LINE__)
9498     {
9499         value = _stripCFWS(valueBefore);
9500         if (value.length < minLen)
9501             throw new DateTimeException("date-time value too short", __FILE__, line);
9502     }
9503     stripAndCheckLen(value, "7Dec1200:00A".length);
9504 
9505     static if (isArray!R && (is(ElementEncodingType!R == char) || is(ElementEncodingType!R == ubyte)))
9506     {
9507         static string sliceAsString(R str) @trusted
9508         {
9509             return cast(string) str;
9510         }
9511     }
9512     else
9513     {
9514         char[4] temp;
9515         char[] sliceAsString(R str) @trusted
9516         {
9517             size_t i = 0;
9518             foreach (c; str)
9519                 temp[i++] = cast(char) c;
9520             return temp[0 .. str.length];
9521         }
9522     }
9523 
9524     // day-of-week
9525     if (isAlpha(value[0]))
9526     {
9527         auto dowStr = sliceAsString(value[0 .. 3]);
9528         switch (dowStr)
9529         {
9530             foreach (dow; EnumMembers!DayOfWeek)
9531             {
9532                 enum dowC = capitalize(to!string(dow));
9533                 case dowC:
9534                     goto afterDoW;
9535             }
9536             default: throw new DateTimeException(format("Invalid day-of-week: %s", dowStr));
9537         }
9538 afterDoW: stripAndCheckLen(value[3 .. value.length], ",7Dec1200:00A".length);
9539         if (value[0] != ',')
9540             throw new DateTimeException("day-of-week missing comma");
9541         stripAndCheckLen(value[1 .. value.length], "7Dec1200:00A".length);
9542     }
9543 
9544     // day
9545     immutable digits = isDigit(value[1]) ? 2 : 1;
9546     immutable day = _convDigits!short(value[0 .. digits]);
9547     if (day == -1)
9548         throw new DateTimeException("Invalid day");
9549     stripAndCheckLen(value[digits .. value.length], "Dec1200:00A".length);
9550 
9551     // month
9552     Month month;
9553     {
9554         auto monStr = sliceAsString(value[0 .. 3]);
9555         switch (monStr)
9556         {
9557             foreach (mon; EnumMembers!Month)
9558             {
9559                 enum monC = capitalize(to!string(mon));
9560                 case monC:
9561                 {
9562                     month = mon;
9563                     goto afterMon;
9564                 }
9565             }
9566             default: throw new DateTimeException(format("Invalid month: %s", monStr));
9567         }
9568 afterMon: stripAndCheckLen(value[3 .. value.length], "1200:00A".length);
9569     }
9570 
9571     // year
9572     auto found = value[2 .. value.length].find!(not!(isDigit))();
9573     size_t yearLen = value.length - found.length;
9574     if (found.length == 0)
9575         throw new DateTimeException("Invalid year");
9576     if (found[0] == ':')
9577         yearLen -= 2;
9578     auto year = _convDigits!short(value[0 .. yearLen]);
9579     if (year < 1900)
9580     {
9581         if (year == -1)
9582             throw new DateTimeException("Invalid year");
9583         if (yearLen < 4)
9584         {
9585             if (yearLen == 3)
9586                 year += 1900;
9587             else if (yearLen == 2)
9588                 year += year < 50 ? 2000 : 1900;
9589             else
9590                 throw new DateTimeException("Invalid year. Too few digits.");
9591         }
9592         else
9593             throw new DateTimeException("Invalid year. Cannot be earlier than 1900.");
9594     }
9595     stripAndCheckLen(value[yearLen .. value.length], "00:00A".length);
9596 
9597     // hour
9598     immutable hour = _convDigits!short(value[0 .. 2]);
9599     stripAndCheckLen(value[2 .. value.length], ":00A".length);
9600     if (value[0] != ':')
9601         throw new DateTimeException("Invalid hour");
9602     stripAndCheckLen(value[1 .. value.length], "00A".length);
9603 
9604     // minute
9605     immutable minute = _convDigits!short(value[0 .. 2]);
9606     stripAndCheckLen(value[2 .. value.length], "A".length);
9607 
9608     // second
9609     short second;
9610     if (value[0] == ':')
9611     {
9612         stripAndCheckLen(value[1 .. value.length], "00A".length);
9613         second = _convDigits!short(value[0 .. 2]);
9614         // this is just if/until SysTime is sorted out to fully support leap seconds
9615         if (second == 60)
9616             second = 59;
9617         stripAndCheckLen(value[2 .. value.length], "A".length);
9618     }
9619 
9620     immutable(TimeZone) parseTZ(int sign)
9621     {
9622         if (value.length < 5)
9623             throw new DateTimeException("Invalid timezone");
9624         immutable zoneHours = _convDigits!short(value[1 .. 3]);
9625         immutable zoneMinutes = _convDigits!short(value[3 .. 5]);
9626         if (zoneHours == -1 || zoneMinutes == -1 || zoneMinutes > 59)
9627             throw new DateTimeException("Invalid timezone");
9628         value = value[5 .. value.length];
9629         immutable utcOffset = (dur!"hours"(zoneHours) + dur!"minutes"(zoneMinutes)) * sign;
9630         if (utcOffset == Duration.zero)
9631         {
9632             return sign == 1 ? cast(immutable(TimeZone))UTC()
9633                              : cast(immutable(TimeZone))new immutable SimpleTimeZone(Duration.zero);
9634         }
9635         return new immutable(SimpleTimeZone)(utcOffset);
9636     }
9637 
9638     // zone
9639     Rebindable!(immutable TimeZone) tz;
9640     if (value[0] == '-')
9641         tz = parseTZ(-1);
9642     else if (value[0] == '+')
9643         tz = parseTZ(1);
9644     else
9645     {
9646         // obs-zone
9647         immutable tzLen = value.length - find(value, ' ', '\t', '(')[0].length;
9648         switch (sliceAsString(value[0 .. tzLen <= 4 ? tzLen : 4]))
9649         {
9650             case "UT": case "GMT": tz = UTC(); break;
9651             case "EST": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
9652             case "EDT": tz = new immutable SimpleTimeZone(dur!"hours"(-4)); break;
9653             case "CST": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
9654             case "CDT": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
9655             case "MST": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
9656             case "MDT": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
9657             case "PST": tz = new immutable SimpleTimeZone(dur!"hours"(-8)); break;
9658             case "PDT": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
9659             case "J": case "j": throw new DateTimeException("Invalid timezone");
9660             default:
9661             {
9662                 if (all!(isAlpha)(value[0 .. tzLen]))
9663                 {
9664                     tz = new immutable SimpleTimeZone(Duration.zero);
9665                     break;
9666                 }
9667                 throw new DateTimeException("Invalid timezone");
9668             }
9669         }
9670         value = value[tzLen .. value.length];
9671     }
9672 
9673     // This is kind of arbitrary. Technically, nothing but CFWS is legal past
9674     // the end of the timezone, but we don't want to be picky about that in a
9675     // function that's just parsing rather than validating. So, the idea here is
9676     // that if the next character is printable (and not part of CFWS), then it
9677     // might be part of the timezone and thus affect what the timezone was
9678     // supposed to be, so we'll throw, but otherwise, we'll just ignore it.
9679     if (!value.empty && isPrintable(value[0]) && value[0] != ' ' && value[0] != '(')
9680         throw new DateTimeException("Invalid timezone");
9681 
9682     try
9683         return SysTime(DateTime(year, month, day, hour, minute, second), tz);
9684     catch (DateTimeException dte)
9685         throw new DateTimeException("date-time format is correct, but the resulting SysTime is invalid.", dte);
9686 }
9687 
9688 ///
9689 @safe unittest
9690 {
9691     import core.time : hours;
9692     import std.datetime.date : DateTime, DateTimeException;
9693     import std.datetime.timezone : SimpleTimeZone, UTC;
9694     import std.exception : assertThrown;
9695 
9696     auto tz = new immutable SimpleTimeZone(hours(-8));
9697     assert(parseRFC822DateTime("Sat, 6 Jan 1990 12:14:19 -0800") ==
9698            SysTime(DateTime(1990, 1, 6, 12, 14, 19), tz));
9699 
9700     assert(parseRFC822DateTime("9 Jul 2002 13:11 +0000") ==
9701            SysTime(DateTime(2002, 7, 9, 13, 11, 0), UTC()));
9702 
9703     auto badStr = "29 Feb 2001 12:17:16 +0200";
9704     assertThrown!DateTimeException(parseRFC822DateTime(badStr));
9705 }
9706 
version(unittest)9707 version (unittest) void testParse822(alias cr)(string str, SysTime expected, size_t line = __LINE__)
9708 {
9709     import std.format : format;
9710     auto value = cr(str);
9711     auto result = parseRFC822DateTime(value);
9712     if (result != expected)
9713         throw new AssertError(format("wrong result. expected [%s], actual[%s]", expected, result), __FILE__, line);
9714 }
9715 
version(unittest)9716 version (unittest) void testBadParse822(alias cr)(string str, size_t line = __LINE__)
9717 {
9718     try
9719         parseRFC822DateTime(cr(str));
9720     catch (DateTimeException)
9721         return;
9722     throw new AssertError("No DateTimeException was thrown", __FILE__, line);
9723 }
9724 
9725 @system unittest
9726 {
9727     import std.algorithm.iteration : filter, map;
9728     import std.algorithm.searching : canFind;
9729     import std.array : array;
9730     import std.ascii : letters;
9731     import std.format : format;
9732     import std.meta : AliasSeq;
9733     import std.range : chain, iota, take;
9734     import std.stdio : writefln, writeln;
9735     import std.string : representation;
9736 
9737     static struct Rand3Letters
9738     {
9739         enum empty = false;
frontRand3Letters9740         @property auto front() { return _mon; }
popFrontRand3Letters9741         void popFront()
9742         {
9743             import std.exception : assumeUnique;
9744             import std.random : rndGen;
9745             _mon = rndGen.map!(a => letters[a % letters.length])().take(3).array().assumeUnique();
9746         }
9747         string _mon;
startRand3Letters9748         static auto start() { Rand3Letters retval; retval.popFront(); return retval; }
9749     }
9750 
9751     foreach (cr; AliasSeq!(function(string a){return cast(char[]) a;},
9752                            function(string a){return cast(ubyte[]) a;},
9753                            function(string a){return a;},
9754                            function(string a){return map!(b => cast(char) b)(a.representation);}))
9755     (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
9756         scope(failure) writeln(typeof(cr).stringof);
9757         alias test = testParse822!cr;
9758         alias testBad = testBadParse822!cr;
9759 
9760         immutable std1 = DateTime(2012, 12, 21, 13, 14, 15);
9761         immutable std2 = DateTime(2012, 12, 21, 13, 14, 0);
9762         immutable dst1 = DateTime(1976, 7, 4, 5, 4, 22);
9763         immutable dst2 = DateTime(1976, 7, 4, 5, 4, 0);
9764 
9765         test("21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
9766         test("21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
9767         test("Fri, 21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
9768         test("Fri, 21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
9769 
9770         test("04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
9771         test("04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
9772         test("Sun, 04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
9773         test("Sun, 04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
9774 
9775         test("4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
9776         test("4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
9777         test("Sun, 4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
9778         test("Sun, 4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
9779 
9780         auto badTZ = new immutable SimpleTimeZone(Duration.zero);
9781         test("21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
9782         test("21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
9783         test("Fri, 21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
9784         test("Fri, 21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
9785 
9786         test("04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
9787         test("04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
9788         test("Sun, 04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
9789         test("Sun, 04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
9790 
9791         test("4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
9792         test("4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
9793         test("Sun, 4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
9794         test("Sun, 4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
9795 
9796         auto pst = new immutable SimpleTimeZone(dur!"hours"(-8));
9797         auto pdt = new immutable SimpleTimeZone(dur!"hours"(-7));
9798         test("21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
9799         test("21 Dec 2012 13:14 -0800", SysTime(std2, pst));
9800         test("Fri, 21 Dec 2012 13:14 -0800", SysTime(std2, pst));
9801         test("Fri, 21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
9802 
9803         test("04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
9804         test("04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
9805         test("Sun, 04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
9806         test("Sun, 04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
9807 
9808         test("4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
9809         test("4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
9810         test("Sun, 4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
9811         test("Sun, 4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
9812 
9813         auto cet = new immutable SimpleTimeZone(dur!"hours"(1));
9814         auto cest = new immutable SimpleTimeZone(dur!"hours"(2));
9815         test("21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
9816         test("21 Dec 2012 13:14 +0100", SysTime(std2, cet));
9817         test("Fri, 21 Dec 2012 13:14 +0100", SysTime(std2, cet));
9818         test("Fri, 21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
9819 
9820         test("04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
9821         test("04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
9822         test("Sun, 04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
9823         test("Sun, 04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
9824 
9825         test("4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
9826         test("4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
9827         test("Sun, 4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
9828         test("Sun, 4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
9829 
9830         // dst and std times are switched in the Southern Hemisphere which is why the
9831         // time zone names and DateTime variables don't match.
9832         auto cstStd = new immutable SimpleTimeZone(dur!"hours"(9) + dur!"minutes"(30));
9833         auto cstDST = new immutable SimpleTimeZone(dur!"hours"(10) + dur!"minutes"(30));
9834         test("21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
9835         test("21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
9836         test("Fri, 21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
9837         test("Fri, 21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
9838 
9839         test("04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
9840         test("04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
9841         test("Sun, 04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
9842         test("Sun, 04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
9843 
9844         test("4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
9845         test("4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
9846         test("Sun, 4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
9847         test("Sun, 4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
9848 
foreach(int i,mon;_monthNames)9849         foreach (int i, mon; _monthNames)
9850         {
9851             test(format("17 %s 2012 00:05:02 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 2), UTC()));
9852             test(format("17 %s 2012 00:05 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 0), UTC()));
9853         }
9854 
9855         import std.uni : toLower, toUpper;
9856         foreach (mon; chain(_monthNames[].map!(a => toLower(a))(),
9857                             _monthNames[].map!(a => toUpper(a))(),
9858                             ["Jam", "Jen", "Fec", "Fdb", "Mas", "Mbr", "Aps", "Aqr", "Mai", "Miy",
9859                              "Jum", "Jbn", "Jup", "Jal", "Aur", "Apg", "Sem", "Sap", "Ocm", "Odt",
9860                              "Nom", "Nav", "Dem", "Dac"],
9861                             Rand3Letters.start().filter!(a => !_monthNames[].canFind(a)).take(20)))
9862         {
9863             scope(failure) writefln("Month: %s", mon);
9864             testBad(format("17 %s 2012 00:05:02 +0000", mon));
9865             testBad(format("17 %s 2012 00:05 +0000", mon));
9866         }
9867 
9868         immutable string[7] daysOfWeekNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
9869 
9870         {
9871             auto start = SysTime(DateTime(2012, 11, 11, 9, 42, 0), UTC());
9872             int day = 11;
9873 
foreach(int i,dow;daysOfWeekNames)9874             foreach (int i, dow; daysOfWeekNames)
9875             {
9876                 auto curr = start + dur!"days"(i);
9877                 test(format("%s, %s Nov 2012 09:42:00 +0000", dow, day), curr);
9878                 test(format("%s, %s Nov 2012 09:42 +0000", dow, day++), curr);
9879 
9880                 // Whether the day of the week matches the date is ignored.
9881                 test(format("%s, 11 Nov 2012 09:42:00 +0000", dow), start);
9882                 test(format("%s, 11 Nov 2012 09:42 +0000", dow), start);
9883             }
9884         }
9885 
9886         foreach (dow; chain(daysOfWeekNames[].map!(a => toLower(a))(),
9887                             daysOfWeekNames[].map!(a => toUpper(a))(),
9888                             ["Sum", "Spn", "Mom", "Man", "Tuf", "Tae", "Wem", "Wdd", "The", "Tur",
9889                              "Fro", "Fai", "San", "Sut"],
9890                             Rand3Letters.start().filter!(a => !daysOfWeekNames[].canFind(a)).take(20)))
9891         {
9892             scope(failure) writefln("Day of Week: %s", dow);
9893             testBad(format("%s, 11 Nov 2012 09:42:00 +0000", dow));
9894             testBad(format("%s, 11 Nov 2012 09:42 +0000", dow));
9895         }
9896 
9897         testBad("31 Dec 1899 23:59:59 +0000");
9898         test("01 Jan 1900 00:00:00 +0000", SysTime(Date(1900, 1, 1), UTC()));
9899         test("01 Jan 1900 00:00:00 -0000", SysTime(Date(1900, 1, 1),
9900                                                    new immutable SimpleTimeZone(Duration.zero)));
9901         test("01 Jan 1900 00:00:00 -0700", SysTime(Date(1900, 1, 1),
9902                                                    new immutable SimpleTimeZone(dur!"hours"(-7))));
9903 
9904         {
9905             auto st1 = SysTime(Date(1900, 1, 1), UTC());
9906             auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
9907             foreach (i; 1900 .. 2102)
9908             {
9909                 test(format("1 Jan %05d 00:00 +0000", i), st1);
9910                 test(format("1 Jan %05d 00:00 -1100", i), st2);
9911                 st1.add!"years"(1);
9912                 st2.add!"years"(1);
9913             }
9914             st1.year = 9998;
9915             st2.year = 9998;
9916             foreach (i; 9998 .. 11_002)
9917             {
9918                 test(format("1 Jan %05d 00:00 +0000", i), st1);
9919                 test(format("1 Jan %05d 00:00 -1100", i), st2);
9920                 st1.add!"years"(1);
9921                 st2.add!"years"(1);
9922             }
9923         }
9924 
9925         testBad("12 Feb 1907 23:17:09 0000");
9926         testBad("12 Feb 1907 23:17:09 +000");
9927         testBad("12 Feb 1907 23:17:09 -000");
9928         testBad("12 Feb 1907 23:17:09 +00000");
9929         testBad("12 Feb 1907 23:17:09 -00000");
9930         testBad("12 Feb 1907 23:17:09 +A");
9931         testBad("12 Feb 1907 23:17:09 +PST");
9932         testBad("12 Feb 1907 23:17:09 -A");
9933         testBad("12 Feb 1907 23:17:09 -PST");
9934 
9935         // test trailing stuff that gets ignored
9936         {
9937             foreach (c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
9938             {
9939                 scope(failure) writefln("c: %d", c);
9940                 test(format("21 Dec 2012 13:14:15 +0000%c", cast(char) c), SysTime(std1, UTC()));
9941                 test(format("21 Dec 2012 13:14:15 +0000%c  ", cast(char) c), SysTime(std1, UTC()));
9942                 test(format("21 Dec 2012 13:14:15 +0000%chello", cast(char) c), SysTime(std1, UTC()));
9943             }
9944         }
9945 
9946         // test trailing stuff that doesn't get ignored
9947         {
9948             foreach (c; chain(iota(33, '('), iota('(' + 1, 127)))
9949             {
9950                 scope(failure) writefln("c: %d", c);
9951                 testBad(format("21 Dec 2012 13:14:15 +0000%c", cast(char) c));
9952                 testBad(format("21 Dec 2012 13:14:15 +0000%c   ", cast(char) c));
9953                 testBad(format("21 Dec 2012 13:14:15 +0000%chello", cast(char) c));
9954             }
9955         }
9956 
9957         testBad("32 Jan 2012 12:13:14 -0800");
9958         testBad("31 Jan 2012 24:13:14 -0800");
9959         testBad("31 Jan 2012 12:60:14 -0800");
9960         testBad("31 Jan 2012 12:13:61 -0800");
9961         testBad("31 Jan 2012 12:13:14 -0860");
9962         test("31 Jan 2012 12:13:14 -0859",
9963              SysTime(DateTime(2012, 1, 31, 12, 13, 14),
9964                      new immutable SimpleTimeZone(dur!"hours"(-8) + dur!"minutes"(-59))));
9965 
9966         // leap-seconds
9967         test("21 Dec 2012 15:59:60 -0800", SysTime(DateTime(2012, 12, 21, 15, 59, 59), pst));
9968 
9969         // FWS
9970         test("Sun,4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
9971         test("Sun,4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
9972         test("Sun,4 Jul 1976 05:04 +0930 (foo)", SysTime(dst2, cstStd));
9973         test("Sun,4 Jul 1976 05:04:22 +0930 (foo)", SysTime(dst1, cstStd));
9974         test("Sun,4  \r\n  Jul  \r\n  1976  \r\n  05:04  \r\n  +0930  \r\n  (foo)", SysTime(dst2, cstStd));
9975         test("Sun,4  \r\n  Jul  \r\n  1976  \r\n  05:04:22  \r\n  +0930  \r\n  (foo)", SysTime(dst1, cstStd));
9976 
9977         auto str = "01 Jan 2012 12:13:14 -0800 ";
9978         test(str, SysTime(DateTime(2012, 1, 1, 12, 13, 14), new immutable SimpleTimeZone(hours(-8))));
9979         foreach (i; 0 .. str.length)
9980         {
9981             auto currStr = str.dup;
9982             currStr[i] = 'x';
9983             scope(failure) writefln("failed: %s", currStr);
9984             testBad(cast(string) currStr);
9985         }
9986         foreach (i; 2 .. str.length)
9987         {
9988             auto currStr = str[0 .. $ - i];
9989             scope(failure) writefln("failed: %s", currStr);
9990             testBad(cast(string) currStr);
9991             testBad((cast(string) currStr) ~ "                                    ");
9992         }
9993     }();
9994 }
9995 
9996 // Obsolete Format per section 4.3 of RFC 5322.
9997 @system unittest
9998 {
9999     import std.algorithm.iteration : filter, map;
10000     import std.ascii : letters;
10001     import std.exception : collectExceptionMsg;
10002     import std.format : format;
10003     import std.meta : AliasSeq;
10004     import std.range : chain, iota;
10005     import std.stdio : writefln, writeln;
10006     import std.string : representation;
10007 
10008     auto std1 = SysTime(DateTime(2012, 12, 21, 13, 14, 15), UTC());
10009     auto std2 = SysTime(DateTime(2012, 12, 21, 13, 14, 0), UTC());
10010     auto std3 = SysTime(DateTime(1912, 12, 21, 13, 14, 15), UTC());
10011     auto std4 = SysTime(DateTime(1912, 12, 21, 13, 14, 0), UTC());
10012     auto dst1 = SysTime(DateTime(1976, 7, 4, 5, 4, 22), UTC());
10013     auto dst2 = SysTime(DateTime(1976, 7, 4, 5, 4, 0), UTC());
10014     auto tooLate1 = SysTime(Date(10_000, 1, 1), UTC());
10015     auto tooLate2 = SysTime(DateTime(12_007, 12, 31, 12, 22, 19), UTC());
10016 
10017     foreach (cr; AliasSeq!(function(string a){return cast(char[]) a;},
10018                            function(string a){return cast(ubyte[]) a;},
10019                            function(string a){return a;},
10020                            function(string a){return map!(b => cast(char) b)(a.representation);}))
10021     (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
10022         scope(failure) writeln(typeof(cr).stringof);
10023         alias test = testParse822!cr;
10024         {
10025             auto list = ["", " ", " \r\n\t", "\t\r\n (hello world( frien(dog)) silly \r\n )  \t\t \r\n ()",
10026                          " \n ", "\t\n\t", " \n\t (foo) \n (bar) \r\n (baz) \n "];
10027 
foreach(i,cfws;list)10028             foreach (i, cfws; list)
10029             {
10030                 scope(failure) writefln("i: %s", i);
10031 
10032                 test(format("%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10033                 test(format("%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
10034                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
10035                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10036 
10037                 test(format("%1$s04%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10038                 test(format("%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10039                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10040                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04:22 +0000%1$s", cfws), dst1);
10041 
10042                 test(format("%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10043                 test(format("%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10044                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10045                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10046 
10047                 test(format("%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10048                 test(format("%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
10049                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
10050                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10051 
10052                 test(format("%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10053                 test(format("%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10054                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10055                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10056 
10057                 test(format("%1$s4%1$sJul%1$s76 05:04:22%1$s+0000%1$s", cfws), dst1);
10058                 test(format("%1$s4%1$sJul%1$s76 05:04%1$s+0000%1$s", cfws), dst2);
10059                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10060                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10061 
10062                 test(format("%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
10063                 test(format("%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
10064                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
10065                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
10066 
10067                 test(format("%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10068                 test(format("%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10069                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10070                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10071 
10072                 test(format("%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10073                 test(format("%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10074                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10075                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10076 
10077                 test(format("%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
10078                 test(format("%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
10079                 test(format("%1$sSat%1$s,%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
10080                 test(format("%1$sSun%1$s,%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
10081             }
10082         }
10083 
10084         // test years of 1, 2, and 3 digits.
10085         {
10086             auto st1 = SysTime(Date(2000, 1, 1), UTC());
10087             auto st2 = SysTime(Date(2000, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
10088             foreach (i; 0 .. 50)
10089             {
10090                 test(format("1 Jan %02d 00:00 GMT", i), st1);
10091                 test(format("1 Jan %02d 00:00 -1200", i), st2);
10092                 st1.add!"years"(1);
10093                 st2.add!"years"(1);
10094             }
10095         }
10096 
10097         {
10098             auto st1 = SysTime(Date(1950, 1, 1), UTC());
10099             auto st2 = SysTime(Date(1950, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
10100             foreach (i; 50 .. 100)
10101             {
10102                 test(format("1 Jan %02d 00:00 GMT", i), st1);
10103                 test(format("1 Jan %02d 00:00 -1200", i), st2);
10104                 st1.add!"years"(1);
10105                 st2.add!"years"(1);
10106             }
10107         }
10108 
10109         {
10110             auto st1 = SysTime(Date(1900, 1, 1), UTC());
10111             auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
10112             foreach (i; 0 .. 1000)
10113             {
10114                 test(format("1 Jan %03d 00:00 GMT", i), st1);
10115                 test(format("1 Jan %03d 00:00 -1100", i), st2);
10116                 st1.add!"years"(1);
10117                 st2.add!"years"(1);
10118             }
10119         }
10120 
10121         foreach (i; 0 .. 10)
10122         {
10123             auto str1 = cr(format("1 Jan %d 00:00 GMT", i));
10124             auto str2 = cr(format("1 Jan %d 00:00 -1200", i));
10125             assertThrown!DateTimeException(parseRFC822DateTime(str1));
10126             assertThrown!DateTimeException(parseRFC822DateTime(str1));
10127         }
10128 
10129         // test time zones
10130         {
10131             auto dt = DateTime(1982, 05, 03, 12, 22, 04);
10132             test("Wed, 03 May 1982 12:22:04 UT", SysTime(dt, UTC()));
10133             test("Wed, 03 May 1982 12:22:04 GMT", SysTime(dt, UTC()));
10134             test("Wed, 03 May 1982 12:22:04 EST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
10135             test("Wed, 03 May 1982 12:22:04 EDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-4))));
10136             test("Wed, 03 May 1982 12:22:04 CST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
10137             test("Wed, 03 May 1982 12:22:04 CDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
10138             test("Wed, 03 May 1982 12:22:04 MST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
10139             test("Wed, 03 May 1982 12:22:04 MDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
10140             test("Wed, 03 May 1982 12:22:04 PST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-8))));
10141             test("Wed, 03 May 1982 12:22:04 PDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
10142 
10143             auto badTZ = new immutable SimpleTimeZone(Duration.zero);
10144             foreach (dchar c; filter!(a => a != 'j' && a != 'J')(letters))
10145             {
10146                 scope(failure) writefln("c: %s", c);
10147                 test(format("Wed, 03 May 1982 12:22:04 %s", c), SysTime(dt, badTZ));
10148                 test(format("Wed, 03 May 1982 12:22:04%s", c), SysTime(dt, badTZ));
10149             }
10150 
foreach(dchar c;['j','J'])10151             foreach (dchar c; ['j', 'J'])
10152             {
10153                 scope(failure) writefln("c: %s", c);
10154                 assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04 %s", c))));
10155                 assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04%s", c))));
10156             }
10157 
foreach(string s;["AAA","GQW","DDT","PDA","GT","GM"])10158             foreach (string s; ["AAA", "GQW", "DDT", "PDA", "GT", "GM"])
10159             {
10160                 scope(failure) writefln("s: %s", s);
10161                 test(format("Wed, 03 May 1982 12:22:04 %s", s), SysTime(dt, badTZ));
10162             }
10163 
10164             // test trailing stuff that gets ignored
10165             {
10166                 foreach (c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
10167                 {
10168                     scope(failure) writefln("c: %d", c);
10169                     test(format("21Dec1213:14:15+0000%c", cast(char) c), std1);
10170                     test(format("21Dec1213:14:15+0000%c  ", cast(char) c), std1);
10171                     test(format("21Dec1213:14:15+0000%chello", cast(char) c), std1);
10172                 }
10173             }
10174 
10175             // test trailing stuff that doesn't get ignored
10176             {
10177                 foreach (c; chain(iota(33, '('), iota('(' + 1, 127)))
10178                 {
10179                     scope(failure) writefln("c: %d", c);
10180                     assertThrown!DateTimeException(
10181                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c", cast(char) c))));
10182                     assertThrown!DateTimeException(
10183                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c  ", cast(char) c))));
10184                     assertThrown!DateTimeException(
10185                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%chello", cast(char) c))));
10186                 }
10187             }
10188         }
10189 
10190         // test that the checks for minimum length work correctly and avoid
10191         // any RangeErrors.
10192         test("7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
10193                                      new immutable SimpleTimeZone(Duration.zero)));
10194         test("Fri,7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
10195                                          new immutable SimpleTimeZone(Duration.zero)));
10196         test("7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
10197                                         new immutable SimpleTimeZone(Duration.zero)));
10198         test("Fri,7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
10199                                             new immutable SimpleTimeZone(Duration.zero)));
10200 
10201         auto tooShortMsg = collectExceptionMsg!DateTimeException(parseRFC822DateTime(""));
foreach(str;["Fri,7Dec1200:00:00","7Dec1200:00:00"])10202         foreach (str; ["Fri,7Dec1200:00:00", "7Dec1200:00:00"])
10203         {
10204             foreach (i; 0 .. str.length)
10205             {
10206                 auto value = str[0 .. $ - i];
10207                 scope(failure) writeln(value);
10208                 assert(collectExceptionMsg!DateTimeException(parseRFC822DateTime(value)) == tooShortMsg);
10209             }
10210         }
10211     }();
10212 }
10213 
10214 
10215 private:
10216 
10217 /+
10218     Returns the given hnsecs as an ISO string of fractional seconds.
10219   +/
fracSecsToISOString(int hnsecs)10220 static string fracSecsToISOString(int hnsecs) @safe pure nothrow
10221 {
10222     assert(hnsecs >= 0);
10223 
10224     try
10225     {
10226         if (hnsecs == 0)
10227             return "";
10228 
10229         string isoString = format(".%07d", hnsecs);
10230 
10231         while (isoString[$ - 1] == '0')
10232             isoString.popBack();
10233 
10234         return isoString;
10235     }
10236     catch (Exception e)
10237         assert(0, "format() threw.");
10238 }
10239 
10240 @safe unittest
10241 {
10242     assert(fracSecsToISOString(0) == "");
10243     assert(fracSecsToISOString(1) == ".0000001");
10244     assert(fracSecsToISOString(10) == ".000001");
10245     assert(fracSecsToISOString(100) == ".00001");
10246     assert(fracSecsToISOString(1000) == ".0001");
10247     assert(fracSecsToISOString(10_000) == ".001");
10248     assert(fracSecsToISOString(100_000) == ".01");
10249     assert(fracSecsToISOString(1_000_000) == ".1");
10250     assert(fracSecsToISOString(1_000_001) == ".1000001");
10251     assert(fracSecsToISOString(1_001_001) == ".1001001");
10252     assert(fracSecsToISOString(1_071_601) == ".1071601");
10253     assert(fracSecsToISOString(1_271_641) == ".1271641");
10254     assert(fracSecsToISOString(9_999_999) == ".9999999");
10255     assert(fracSecsToISOString(9_999_990) == ".999999");
10256     assert(fracSecsToISOString(9_999_900) == ".99999");
10257     assert(fracSecsToISOString(9_999_000) == ".9999");
10258     assert(fracSecsToISOString(9_990_000) == ".999");
10259     assert(fracSecsToISOString(9_900_000) == ".99");
10260     assert(fracSecsToISOString(9_000_000) == ".9");
10261     assert(fracSecsToISOString(999) == ".0000999");
10262     assert(fracSecsToISOString(9990) == ".000999");
10263     assert(fracSecsToISOString(99_900) == ".00999");
10264     assert(fracSecsToISOString(999_000) == ".0999");
10265 }
10266 
10267 
10268 /+
10269     Returns a Duration corresponding to to the given ISO string of
10270     fractional seconds.
10271   +/
10272 static Duration fracSecsFromISOString(S)(in S isoString) @trusted pure
10273 if (isSomeString!S)
10274 {
10275     import std.algorithm.searching : all;
10276     import std.ascii : isDigit;
10277     import std.conv : to;
10278     import std.string : representation;
10279 
10280     if (isoString.empty)
10281         return Duration.zero;
10282 
10283     auto str = isoString.representation;
10284 
10285     enforce(str[0] == '.', new DateTimeException("Invalid ISO String"));
10286     str.popFront();
10287 
10288     enforce(!str.empty && all!isDigit(str), new DateTimeException("Invalid ISO String"));
10289 
10290     dchar[7] fullISOString = void;
foreach(i,ref dchar c;fullISOString)10291     foreach (i, ref dchar c; fullISOString)
10292     {
10293         if (i < str.length)
10294             c = str[i];
10295         else
10296             c = '0';
10297     }
10298 
10299     return hnsecs(to!int(fullISOString[]));
10300 }
10301 
10302 @safe unittest
10303 {
testFSInvalid(string isoString)10304     static void testFSInvalid(string isoString)
10305     {
10306         fracSecsFromISOString(isoString);
10307     }
10308 
10309     assertThrown!DateTimeException(testFSInvalid("."));
10310     assertThrown!DateTimeException(testFSInvalid("0."));
10311     assertThrown!DateTimeException(testFSInvalid("0"));
10312     assertThrown!DateTimeException(testFSInvalid("0000000"));
10313     assertThrown!DateTimeException(testFSInvalid("T"));
10314     assertThrown!DateTimeException(testFSInvalid("T."));
10315     assertThrown!DateTimeException(testFSInvalid(".T"));
10316     assertThrown!DateTimeException(testFSInvalid(".00000Q0"));
10317     assertThrown!DateTimeException(testFSInvalid(".000000Q"));
10318     assertThrown!DateTimeException(testFSInvalid(".0000000Q"));
10319     assertThrown!DateTimeException(testFSInvalid(".0000000000Q"));
10320 
10321     assert(fracSecsFromISOString("") == Duration.zero);
10322     assert(fracSecsFromISOString(".0000001") == hnsecs(1));
10323     assert(fracSecsFromISOString(".000001") == hnsecs(10));
10324     assert(fracSecsFromISOString(".00001") == hnsecs(100));
10325     assert(fracSecsFromISOString(".0001") == hnsecs(1000));
10326     assert(fracSecsFromISOString(".001") == hnsecs(10_000));
10327     assert(fracSecsFromISOString(".01") == hnsecs(100_000));
10328     assert(fracSecsFromISOString(".1") == hnsecs(1_000_000));
10329     assert(fracSecsFromISOString(".1000001") == hnsecs(1_000_001));
10330     assert(fracSecsFromISOString(".1001001") == hnsecs(1_001_001));
10331     assert(fracSecsFromISOString(".1071601") == hnsecs(1_071_601));
10332     assert(fracSecsFromISOString(".1271641") == hnsecs(1_271_641));
10333     assert(fracSecsFromISOString(".9999999") == hnsecs(9_999_999));
10334     assert(fracSecsFromISOString(".9999990") == hnsecs(9_999_990));
10335     assert(fracSecsFromISOString(".999999") == hnsecs(9_999_990));
10336     assert(fracSecsFromISOString(".9999900") == hnsecs(9_999_900));
10337     assert(fracSecsFromISOString(".99999") == hnsecs(9_999_900));
10338     assert(fracSecsFromISOString(".9999000") == hnsecs(9_999_000));
10339     assert(fracSecsFromISOString(".9999") == hnsecs(9_999_000));
10340     assert(fracSecsFromISOString(".9990000") == hnsecs(9_990_000));
10341     assert(fracSecsFromISOString(".999") == hnsecs(9_990_000));
10342     assert(fracSecsFromISOString(".9900000") == hnsecs(9_900_000));
10343     assert(fracSecsFromISOString(".9900") == hnsecs(9_900_000));
10344     assert(fracSecsFromISOString(".99") == hnsecs(9_900_000));
10345     assert(fracSecsFromISOString(".9000000") == hnsecs(9_000_000));
10346     assert(fracSecsFromISOString(".9") == hnsecs(9_000_000));
10347     assert(fracSecsFromISOString(".0000999") == hnsecs(999));
10348     assert(fracSecsFromISOString(".0009990") == hnsecs(9990));
10349     assert(fracSecsFromISOString(".000999") == hnsecs(9990));
10350     assert(fracSecsFromISOString(".0099900") == hnsecs(99_900));
10351     assert(fracSecsFromISOString(".00999") == hnsecs(99_900));
10352     assert(fracSecsFromISOString(".0999000") == hnsecs(999_000));
10353     assert(fracSecsFromISOString(".0999") == hnsecs(999_000));
10354     assert(fracSecsFromISOString(".00000000") == Duration.zero);
10355     assert(fracSecsFromISOString(".00000001") == Duration.zero);
10356     assert(fracSecsFromISOString(".00000009") == Duration.zero);
10357     assert(fracSecsFromISOString(".1234567890") == hnsecs(1_234_567));
10358     assert(fracSecsFromISOString(".12345678901234567890") == hnsecs(1_234_567));
10359 }
10360 
10361 
10362 /+
10363     This function is used to split out the units without getting the remaining
10364     hnsecs.
10365 
10366     Params:
10367         units  = The units to split out.
10368         hnsecs = The current total hnsecs.
10369 
10370     Returns:
10371         The split out value.
10372   +/
10373 long getUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
10374 if (validTimeUnits(units) &&
10375     CmpTimeUnits!(units, "months") < 0)
10376 {
10377     return convert!("hnsecs", units)(hnsecs);
10378 }
10379 
10380 @safe unittest
10381 {
10382     auto hnsecs = 2595000000007L;
10383     immutable days = getUnitsFromHNSecs!"days"(hnsecs);
10384     assert(days == 3);
10385     assert(hnsecs == 2595000000007L);
10386 }
10387 
10388 
10389 /+
10390     This function is used to split out the units without getting the units but
10391     just the remaining hnsecs.
10392 
10393     Params:
10394         units  = The units to split out.
10395         hnsecs = The current total hnsecs.
10396 
10397     Returns:
10398         The remaining hnsecs.
10399   +/
10400 long removeUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
10401 if (validTimeUnits(units) &&
10402     CmpTimeUnits!(units, "months") < 0)
10403 {
10404     immutable value = convert!("hnsecs", units)(hnsecs);
10405     return hnsecs - convert!(units, "hnsecs")(value);
10406 }
10407 
10408 @safe unittest
10409 {
10410     auto hnsecs = 2595000000007L;
10411     auto returned = removeUnitsFromHNSecs!"days"(hnsecs);
10412     assert(returned == 3000000007);
10413     assert(hnsecs == 2595000000007L);
10414 }
10415 
10416 
10417 /+
10418     Strips what RFC 5322, section 3.2.2 refers to as CFWS from the left-hand
10419     side of the given range (it strips comments delimited by $(D '(') and
10420     $(D ')') as well as folding whitespace).
10421 
10422     It is assumed that the given range contains the value of a header field and
10423     no terminating CRLF for the line (though the CRLF for folding whitespace is
10424     of course expected and stripped) and thus that the only case of CR or LF is
10425     in folding whitespace.
10426 
10427     If a comment does not terminate correctly (e.g. mismatched parens) or if the
10428     the FWS is malformed, then the range will be empty when stripCWFS is done.
10429     However, only minimal validation of the content is done (e.g. quoted pairs
10430     within a comment aren't validated beyond \$LPAREN or \$RPAREN, because
10431     they're inside a comment, and thus their value doesn't matter anyway). It's
10432     only when the content does not conform to the grammar rules for FWS and thus
10433     literally cannot be parsed that content is considered invalid, and an empty
10434     range is returned.
10435 
10436     Note that _stripCFWS is eager, not lazy. It does not create a new range.
10437     Rather, it pops off the CFWS from the range and returns it.
10438   +/
10439 R _stripCFWS(R)(R range)
10440 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
10441     (is(Unqual!(ElementType!R) == char) || is(Unqual!(ElementType!R) == ubyte)))
10442 {
10443     immutable e = range.length;
10444     outer: for (size_t i = 0; i < e; )
10445     {
10446         switch (range[i])
10447         {
10448             case ' ': case '\t':
10449             {
10450                 ++i;
10451                 break;
10452             }
10453             case '\r':
10454             {
10455                 if (i + 2 < e && range[i + 1] == '\n' && (range[i + 2] == ' ' || range[i + 2] == '\t'))
10456                 {
10457                     i += 3;
10458                     break;
10459                 }
10460                 break outer;
10461             }
10462             case '\n':
10463             {
10464                 if (i + 1 < e && (range[i + 1] == ' ' || range[i + 1] == '\t'))
10465                 {
10466                     i += 2;
10467                     break;
10468                 }
10469                 break outer;
10470             }
10471             case '(':
10472             {
10473                 ++i;
10474                 size_t commentLevel = 1;
10475                 while (i < e)
10476                 {
10477                     if (range[i] == '(')
10478                         ++commentLevel;
10479                     else if (range[i] == ')')
10480                     {
10481                         ++i;
10482                         if (--commentLevel == 0)
10483                             continue outer;
10484                         continue;
10485                     }
10486                     else if (range[i] == '\\')
10487                     {
10488                         if (++i == e)
10489                             break outer;
10490                     }
10491                     ++i;
10492                 }
10493                 break outer;
10494             }
10495             default: return range[i .. e];
10496         }
10497     }
10498     return range[e .. e];
10499 }
10500 
10501 @system unittest
10502 {
10503     import std.algorithm.comparison : equal;
10504     import std.algorithm.iteration : map;
10505     import std.meta : AliasSeq;
10506     import std.stdio : writeln;
10507     import std.string : representation;
10508 
10509     foreach (cr; AliasSeq!(function(string a){return cast(ubyte[]) a;},
10510                            function(string a){return map!(b => cast(char) b)(a.representation);}))
10511     (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
10512         scope(failure) writeln(typeof(cr).stringof);
10513 
10514         assert(_stripCFWS(cr("")).empty);
10515         assert(_stripCFWS(cr("\r")).empty);
10516         assert(_stripCFWS(cr("\r\n")).empty);
10517         assert(_stripCFWS(cr("\r\n ")).empty);
10518         assert(_stripCFWS(cr(" \t\r\n")).empty);
10519         assert(equal(_stripCFWS(cr(" \t\r\n hello")), cr("hello")));
10520         assert(_stripCFWS(cr(" \t\r\nhello")).empty);
10521         assert(_stripCFWS(cr(" \t\r\n\v")).empty);
10522         assert(equal(_stripCFWS(cr("\v \t\r\n\v")), cr("\v \t\r\n\v")));
10523         assert(_stripCFWS(cr("()")).empty);
10524         assert(_stripCFWS(cr("(hello world)")).empty);
10525         assert(_stripCFWS(cr("(hello world)(hello world)")).empty);
10526         assert(_stripCFWS(cr("(hello world\r\n foo\r where's\nwaldo)")).empty);
10527         assert(_stripCFWS(cr(" \t (hello \tworld\r\n foo\r where's\nwaldo)\t\t ")).empty);
10528         assert(_stripCFWS(cr("      ")).empty);
10529         assert(_stripCFWS(cr("\t\t\t")).empty);
10530         assert(_stripCFWS(cr("\t \r\n\r \n")).empty);
10531         assert(_stripCFWS(cr("(hello world) (can't find waldo) (he's lost)")).empty);
10532         assert(_stripCFWS(cr("(hello\\) world) (can't \\(find waldo) (he's \\(\\)lost)")).empty);
10533         assert(_stripCFWS(cr("(((((")).empty);
10534         assert(_stripCFWS(cr("(((()))")).empty);
10535         assert(_stripCFWS(cr("(((())))")).empty);
10536         assert(equal(_stripCFWS(cr("(((()))))")), cr(")")));
10537         assert(equal(_stripCFWS(cr(")))))")), cr(")))))")));
10538         assert(equal(_stripCFWS(cr("()))))")), cr("))))")));
10539         assert(equal(_stripCFWS(cr(" hello hello ")), cr("hello hello ")));
10540         assert(equal(_stripCFWS(cr("\thello (world)")), cr("hello (world)")));
10541         assert(equal(_stripCFWS(cr(" \r\n \\((\\))  foo")), cr("\\((\\))  foo")));
10542         assert(equal(_stripCFWS(cr(" \r\n (\\((\\)))  foo")), cr("foo")));
10543         assert(equal(_stripCFWS(cr(" \r\n (\\(()))  foo")), cr(")  foo")));
10544         assert(_stripCFWS(cr(" \r\n (((\\)))  foo")).empty);
10545 
10546         assert(_stripCFWS(cr("(hello)(hello)")).empty);
10547         assert(_stripCFWS(cr(" \r\n (hello)\r\n (hello)")).empty);
10548         assert(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n ")).empty);
10549         assert(_stripCFWS(cr("\t\t\t\t(hello)\t\t\t\t(hello)\t\t\t\t")).empty);
10550         assert(equal(_stripCFWS(cr(" \r\n (hello)\r\n (hello) \r\n hello")), cr("hello")));
10551         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n hello")), cr("hello")));
10552         assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\r\n\t(hello)\t\r\n hello")), cr("hello")));
10553         assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\t\r\n\t(hello)\t\r\n hello")), cr("hello")));
10554         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n \r\n (hello) \r\n hello")), cr("hello")));
10555         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n \r\n hello")), cr("hello")));
10556         assert(equal(_stripCFWS(cr(" \r\n \r\n (hello)\t\r\n (hello) \r\n hello")), cr("hello")));
10557         assert(equal(_stripCFWS(cr(" \r\n\t\r\n\t(hello)\t\r\n (hello) \r\n hello")), cr("hello")));
10558 
10559         assert(equal(_stripCFWS(cr(" (\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
10560         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) foo")), cr("foo")));
10561         assert(equal(_stripCFWS(cr(" (\t\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
10562         assert(equal(_stripCFWS(cr(" (\r\n\t( \r\n ) \r\n ) foo")), cr("foo")));
10563         assert(equal(_stripCFWS(cr(" ( \r\n (\t\r\n ) \r\n ) foo")), cr("foo")));
10564         assert(equal(_stripCFWS(cr(" ( \r\n (\r\n ) \r\n ) foo")), cr("foo")));
10565         assert(equal(_stripCFWS(cr(" ( \r\n (\r\n\t) \r\n ) foo")), cr("foo")));
10566         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n) \r\n ) foo")), cr("foo")));
10567         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\t\r\n ) foo")), cr("foo")));
10568         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\r\n ) foo")), cr("foo")));
10569         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n) foo")), cr("foo")));
10570         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n\t) foo")), cr("foo")));
10571         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) \r\n foo")), cr("foo")));
10572         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\t\r\n foo")), cr("foo")));
10573         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\r\n foo")), cr("foo")));
10574 
10575         assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
10576         assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
10577         assert(equal(_stripCFWS(cr(" (\t\r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
10578         assert(equal(_stripCFWS(cr(" (\r\n \r\n\t( \r\n \r\n ) \r\n ) foo")), cr("foo")));
10579         assert(equal(_stripCFWS(cr(" (\r\n \r\n( \r\n \r\n ) \r\n ) foo")), cr("foo")));
10580         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n\t) \r\n ) foo")), cr("foo")));
10581         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\t\r\n ) foo")), cr("foo")));
10582         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\r\n ) foo")), cr("foo")));
10583 
10584         assert(equal(_stripCFWS(cr(" ( \r\n bar \r\n ( \r\n bar \r\n ) \r\n ) foo")), cr("foo")));
10585         assert(equal(_stripCFWS(cr(" ( \r\n () \r\n ( \r\n () \r\n ) \r\n ) foo")), cr("foo")));
10586         assert(equal(_stripCFWS(cr(" ( \r\n \\\\ \r\n ( \r\n \\\\ \r\n ) \r\n ) foo")), cr("foo")));
10587 
10588         assert(_stripCFWS(cr("(hello)(hello)")).empty);
10589         assert(_stripCFWS(cr(" \n (hello)\n (hello) \n ")).empty);
10590         assert(_stripCFWS(cr(" \n (hello) \n (hello) \n ")).empty);
10591         assert(equal(_stripCFWS(cr(" \n (hello)\n (hello) \n hello")), cr("hello")));
10592         assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n hello")), cr("hello")));
10593         assert(equal(_stripCFWS(cr("\t\n\t(hello)\n\t(hello)\t\n hello")), cr("hello")));
10594         assert(equal(_stripCFWS(cr("\t\n\t(hello)\t\n\t(hello)\t\n hello")), cr("hello")));
10595         assert(equal(_stripCFWS(cr(" \n (hello) \n \n (hello) \n hello")), cr("hello")));
10596         assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n \n hello")), cr("hello")));
10597         assert(equal(_stripCFWS(cr(" \n \n (hello)\t\n (hello) \n hello")), cr("hello")));
10598         assert(equal(_stripCFWS(cr(" \n\t\n\t(hello)\t\n (hello) \n hello")), cr("hello")));
10599     }();
10600 }
10601 
10602 // This is so that we don't have to worry about std.conv.to throwing. It also
10603 // doesn't have to worry about quite as many cases as std.conv.to, since it
10604 // doesn't have to worry about a sign on the value or about whether it fits.
10605 T _convDigits(T, R)(R str)
10606 if (isIntegral!T && isSigned!T) // The constraints on R were already covered by parseRFC822DateTime.
10607 {
10608     import std.ascii : isDigit;
10609 
10610     assert(!str.empty);
10611     T num = 0;
10612     foreach (i; 0 .. str.length)
10613     {
10614         if (i != 0)
10615             num *= 10;
10616         if (!isDigit(str[i]))
10617             return -1;
10618         num += str[i] - '0';
10619     }
10620     return num;
10621 }
10622 
10623 @safe unittest
10624 {
10625     import std.conv : to;
10626     import std.range : chain, iota;
10627     import std.stdio : writeln;
10628     foreach (i; chain(iota(0, 101), [250, 999, 1000, 1001, 2345, 9999]))
10629     {
10630         scope(failure) writeln(i);
10631         assert(_convDigits!int(to!string(i)) == i);
10632     }
foreach(str;["-42","+42","1a","1 "," "," 42 "])10633     foreach (str; ["-42", "+42", "1a", "1 ", " ", " 42 "])
10634     {
10635         scope(failure) writeln(str);
10636         assert(_convDigits!int(str) == -1);
10637     }
10638 }
10639 
10640 
version(unittest)10641 version (unittest)
10642 {
10643     // Variables to help in testing.
10644     Duration currLocalDiffFromUTC;
10645     immutable (TimeZone)[] testTZs;
10646 
10647     // All of these helper arrays are sorted in ascending order.
10648     auto testYearsBC = [-1999, -1200, -600, -4, -1, 0];
10649     auto testYearsAD = [1, 4, 1000, 1999, 2000, 2012];
10650 
10651     // I'd use a Tuple, but I get forward reference errors if I try.
10652     struct MonthDay
10653     {
10654         Month month;
10655         short day;
10656 
10657         this(int m, short d)
10658         {
10659             month = cast(Month) m;
10660             day = d;
10661         }
10662     }
10663 
10664     MonthDay[] testMonthDays = [MonthDay(1, 1),
10665                                 MonthDay(1, 2),
10666                                 MonthDay(3, 17),
10667                                 MonthDay(7, 4),
10668                                 MonthDay(10, 27),
10669                                 MonthDay(12, 30),
10670                                 MonthDay(12, 31)];
10671 
10672     auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31];
10673 
10674     auto testTODs = [TimeOfDay(0, 0, 0),
10675                      TimeOfDay(0, 0, 1),
10676                      TimeOfDay(0, 1, 0),
10677                      TimeOfDay(1, 0, 0),
10678                      TimeOfDay(13, 13, 13),
10679                      TimeOfDay(23, 59, 59)];
10680 
10681     auto testHours = [0, 1, 12, 22, 23];
10682     auto testMinSecs = [0, 1, 30, 58, 59];
10683 
10684     // Throwing exceptions is incredibly expensive, so we want to use a smaller
10685     // set of values for tests using assertThrown.
10686     auto testTODsThrown = [TimeOfDay(0, 0, 0),
10687                            TimeOfDay(13, 13, 13),
10688                            TimeOfDay(23, 59, 59)];
10689 
10690     Date[] testDatesBC;
10691     Date[] testDatesAD;
10692 
10693     DateTime[] testDateTimesBC;
10694     DateTime[] testDateTimesAD;
10695 
10696     Duration[] testFracSecs;
10697 
10698     SysTime[] testSysTimesBC;
10699     SysTime[] testSysTimesAD;
10700 
10701     // I'd use a Tuple, but I get forward reference errors if I try.
10702     struct GregDay { int day; Date date; }
10703     auto testGregDaysBC = [GregDay(-1_373_427, Date(-3760, 9, 7)), // Start of the Hebrew Calendar
10704                            GregDay(-735_233, Date(-2012, 1, 1)),
10705                            GregDay(-735_202, Date(-2012, 2, 1)),
10706                            GregDay(-735_175, Date(-2012, 2, 28)),
10707                            GregDay(-735_174, Date(-2012, 2, 29)),
10708                            GregDay(-735_173, Date(-2012, 3, 1)),
10709                            GregDay(-734_502, Date(-2010, 1, 1)),
10710                            GregDay(-734_472, Date(-2010, 1, 31)),
10711                            GregDay(-734_471, Date(-2010, 2, 1)),
10712                            GregDay(-734_444, Date(-2010, 2, 28)),
10713                            GregDay(-734_443, Date(-2010, 3, 1)),
10714                            GregDay(-734_413, Date(-2010, 3, 31)),
10715                            GregDay(-734_412, Date(-2010, 4, 1)),
10716                            GregDay(-734_383, Date(-2010, 4, 30)),
10717                            GregDay(-734_382, Date(-2010, 5, 1)),
10718                            GregDay(-734_352, Date(-2010, 5, 31)),
10719                            GregDay(-734_351, Date(-2010, 6, 1)),
10720                            GregDay(-734_322, Date(-2010, 6, 30)),
10721                            GregDay(-734_321, Date(-2010, 7, 1)),
10722                            GregDay(-734_291, Date(-2010, 7, 31)),
10723                            GregDay(-734_290, Date(-2010, 8, 1)),
10724                            GregDay(-734_260, Date(-2010, 8, 31)),
10725                            GregDay(-734_259, Date(-2010, 9, 1)),
10726                            GregDay(-734_230, Date(-2010, 9, 30)),
10727                            GregDay(-734_229, Date(-2010, 10, 1)),
10728                            GregDay(-734_199, Date(-2010, 10, 31)),
10729                            GregDay(-734_198, Date(-2010, 11, 1)),
10730                            GregDay(-734_169, Date(-2010, 11, 30)),
10731                            GregDay(-734_168, Date(-2010, 12, 1)),
10732                            GregDay(-734_139, Date(-2010, 12, 30)),
10733                            GregDay(-734_138, Date(-2010, 12, 31)),
10734                            GregDay(-731_215, Date(-2001, 1, 1)),
10735                            GregDay(-730_850, Date(-2000, 1, 1)),
10736                            GregDay(-730_849, Date(-2000, 1, 2)),
10737                            GregDay(-730_486, Date(-2000, 12, 30)),
10738                            GregDay(-730_485, Date(-2000, 12, 31)),
10739                            GregDay(-730_484, Date(-1999, 1, 1)),
10740                            GregDay(-694_690, Date(-1901, 1, 1)),
10741                            GregDay(-694_325, Date(-1900, 1, 1)),
10742                            GregDay(-585_118, Date(-1601, 1, 1)),
10743                            GregDay(-584_753, Date(-1600, 1, 1)),
10744                            GregDay(-584_388, Date(-1600, 12, 31)),
10745                            GregDay(-584_387, Date(-1599, 1, 1)),
10746                            GregDay(-365_972, Date(-1001, 1, 1)),
10747                            GregDay(-365_607, Date(-1000, 1, 1)),
10748                            GregDay(-183_351, Date(-501, 1, 1)),
10749                            GregDay(-182_986, Date(-500, 1, 1)),
10750                            GregDay(-182_621, Date(-499, 1, 1)),
10751                            GregDay(-146_827, Date(-401, 1, 1)),
10752                            GregDay(-146_462, Date(-400, 1, 1)),
10753                            GregDay(-146_097, Date(-400, 12, 31)),
10754                            GregDay(-110_302, Date(-301, 1, 1)),
10755                            GregDay(-109_937, Date(-300, 1, 1)),
10756                            GregDay(-73_778, Date(-201, 1, 1)),
10757                            GregDay(-73_413, Date(-200, 1, 1)),
10758                            GregDay(-38_715, Date(-105, 1, 1)),
10759                            GregDay(-37_254, Date(-101, 1, 1)),
10760                            GregDay(-36_889, Date(-100, 1, 1)),
10761                            GregDay(-36_524, Date(-99, 1, 1)),
10762                            GregDay(-36_160, Date(-99, 12, 31)),
10763                            GregDay(-35_794, Date(-97, 1, 1)),
10764                            GregDay(-18_627, Date(-50, 1, 1)),
10765                            GregDay(-18_262, Date(-49, 1, 1)),
10766                            GregDay(-3652, Date(-9, 1, 1)),
10767                            GregDay(-2191, Date(-5, 1, 1)),
10768                            GregDay(-1827, Date(-5, 12, 31)),
10769                            GregDay(-1826, Date(-4, 1, 1)),
10770                            GregDay(-1825, Date(-4, 1, 2)),
10771                            GregDay(-1462, Date(-4, 12, 30)),
10772                            GregDay(-1461, Date(-4, 12, 31)),
10773                            GregDay(-1460, Date(-3, 1, 1)),
10774                            GregDay(-1096, Date(-3, 12, 31)),
10775                            GregDay(-1095, Date(-2, 1, 1)),
10776                            GregDay(-731, Date(-2, 12, 31)),
10777                            GregDay(-730, Date(-1, 1, 1)),
10778                            GregDay(-367, Date(-1, 12, 30)),
10779                            GregDay(-366, Date(-1, 12, 31)),
10780                            GregDay(-365, Date(0, 1, 1)),
10781                            GregDay(-31, Date(0, 11, 30)),
10782                            GregDay(-30, Date(0, 12, 1)),
10783                            GregDay(-1, Date(0, 12, 30)),
10784                            GregDay(0, Date(0, 12, 31))];
10785 
10786     auto testGregDaysAD = [GregDay(1, Date(1, 1, 1)),
10787                            GregDay(2, Date(1, 1, 2)),
10788                            GregDay(32, Date(1, 2, 1)),
10789                            GregDay(365, Date(1, 12, 31)),
10790                            GregDay(366, Date(2, 1, 1)),
10791                            GregDay(731, Date(3, 1, 1)),
10792                            GregDay(1096, Date(4, 1, 1)),
10793                            GregDay(1097, Date(4, 1, 2)),
10794                            GregDay(1460, Date(4, 12, 30)),
10795                            GregDay(1461, Date(4, 12, 31)),
10796                            GregDay(1462, Date(5, 1, 1)),
10797                            GregDay(17_898, Date(50, 1, 1)),
10798                            GregDay(35_065, Date(97, 1, 1)),
10799                            GregDay(36_160, Date(100, 1, 1)),
10800                            GregDay(36_525, Date(101, 1, 1)),
10801                            GregDay(37_986, Date(105, 1, 1)),
10802                            GregDay(72_684, Date(200, 1, 1)),
10803                            GregDay(73_049, Date(201, 1, 1)),
10804                            GregDay(109_208, Date(300, 1, 1)),
10805                            GregDay(109_573, Date(301, 1, 1)),
10806                            GregDay(145_732, Date(400, 1, 1)),
10807                            GregDay(146_098, Date(401, 1, 1)),
10808                            GregDay(182_257, Date(500, 1, 1)),
10809                            GregDay(182_622, Date(501, 1, 1)),
10810                            GregDay(364_878, Date(1000, 1, 1)),
10811                            GregDay(365_243, Date(1001, 1, 1)),
10812                            GregDay(584_023, Date(1600, 1, 1)),
10813                            GregDay(584_389, Date(1601, 1, 1)),
10814                            GregDay(693_596, Date(1900, 1, 1)),
10815                            GregDay(693_961, Date(1901, 1, 1)),
10816                            GregDay(729_755, Date(1999, 1, 1)),
10817                            GregDay(730_120, Date(2000, 1, 1)),
10818                            GregDay(730_121, Date(2000, 1, 2)),
10819                            GregDay(730_484, Date(2000, 12, 30)),
10820                            GregDay(730_485, Date(2000, 12, 31)),
10821                            GregDay(730_486, Date(2001, 1, 1)),
10822                            GregDay(733_773, Date(2010, 1, 1)),
10823                            GregDay(733_774, Date(2010, 1, 2)),
10824                            GregDay(733_803, Date(2010, 1, 31)),
10825                            GregDay(733_804, Date(2010, 2, 1)),
10826                            GregDay(733_831, Date(2010, 2, 28)),
10827                            GregDay(733_832, Date(2010, 3, 1)),
10828                            GregDay(733_862, Date(2010, 3, 31)),
10829                            GregDay(733_863, Date(2010, 4, 1)),
10830                            GregDay(733_892, Date(2010, 4, 30)),
10831                            GregDay(733_893, Date(2010, 5, 1)),
10832                            GregDay(733_923, Date(2010, 5, 31)),
10833                            GregDay(733_924, Date(2010, 6, 1)),
10834                            GregDay(733_953, Date(2010, 6, 30)),
10835                            GregDay(733_954, Date(2010, 7, 1)),
10836                            GregDay(733_984, Date(2010, 7, 31)),
10837                            GregDay(733_985, Date(2010, 8, 1)),
10838                            GregDay(734_015, Date(2010, 8, 31)),
10839                            GregDay(734_016, Date(2010, 9, 1)),
10840                            GregDay(734_045, Date(2010, 9, 30)),
10841                            GregDay(734_046, Date(2010, 10, 1)),
10842                            GregDay(734_076, Date(2010, 10, 31)),
10843                            GregDay(734_077, Date(2010, 11, 1)),
10844                            GregDay(734_106, Date(2010, 11, 30)),
10845                            GregDay(734_107, Date(2010, 12, 1)),
10846                            GregDay(734_136, Date(2010, 12, 30)),
10847                            GregDay(734_137, Date(2010, 12, 31)),
10848                            GregDay(734_503, Date(2012, 1, 1)),
10849                            GregDay(734_534, Date(2012, 2, 1)),
10850                            GregDay(734_561, Date(2012, 2, 28)),
10851                            GregDay(734_562, Date(2012, 2, 29)),
10852                            GregDay(734_563, Date(2012, 3, 1)),
10853                            GregDay(734_858, Date(2012, 12, 21))];
10854 
10855     // I'd use a Tuple, but I get forward reference errors if I try.
10856     struct DayOfYear { int day; MonthDay md; }
10857     auto testDaysOfYear = [DayOfYear(1, MonthDay(1, 1)),
10858                            DayOfYear(2, MonthDay(1, 2)),
10859                            DayOfYear(3, MonthDay(1, 3)),
10860                            DayOfYear(31, MonthDay(1, 31)),
10861                            DayOfYear(32, MonthDay(2, 1)),
10862                            DayOfYear(59, MonthDay(2, 28)),
10863                            DayOfYear(60, MonthDay(3, 1)),
10864                            DayOfYear(90, MonthDay(3, 31)),
10865                            DayOfYear(91, MonthDay(4, 1)),
10866                            DayOfYear(120, MonthDay(4, 30)),
10867                            DayOfYear(121, MonthDay(5, 1)),
10868                            DayOfYear(151, MonthDay(5, 31)),
10869                            DayOfYear(152, MonthDay(6, 1)),
10870                            DayOfYear(181, MonthDay(6, 30)),
10871                            DayOfYear(182, MonthDay(7, 1)),
10872                            DayOfYear(212, MonthDay(7, 31)),
10873                            DayOfYear(213, MonthDay(8, 1)),
10874                            DayOfYear(243, MonthDay(8, 31)),
10875                            DayOfYear(244, MonthDay(9, 1)),
10876                            DayOfYear(273, MonthDay(9, 30)),
10877                            DayOfYear(274, MonthDay(10, 1)),
10878                            DayOfYear(304, MonthDay(10, 31)),
10879                            DayOfYear(305, MonthDay(11, 1)),
10880                            DayOfYear(334, MonthDay(11, 30)),
10881                            DayOfYear(335, MonthDay(12, 1)),
10882                            DayOfYear(363, MonthDay(12, 29)),
10883                            DayOfYear(364, MonthDay(12, 30)),
10884                            DayOfYear(365, MonthDay(12, 31))];
10885 
10886     auto testDaysOfLeapYear = [DayOfYear(1, MonthDay(1, 1)),
10887                                DayOfYear(2, MonthDay(1, 2)),
10888                                DayOfYear(3, MonthDay(1, 3)),
10889                                DayOfYear(31, MonthDay(1, 31)),
10890                                DayOfYear(32, MonthDay(2, 1)),
10891                                DayOfYear(59, MonthDay(2, 28)),
10892                                DayOfYear(60, MonthDay(2, 29)),
10893                                DayOfYear(61, MonthDay(3, 1)),
10894                                DayOfYear(91, MonthDay(3, 31)),
10895                                DayOfYear(92, MonthDay(4, 1)),
10896                                DayOfYear(121, MonthDay(4, 30)),
10897                                DayOfYear(122, MonthDay(5, 1)),
10898                                DayOfYear(152, MonthDay(5, 31)),
10899                                DayOfYear(153, MonthDay(6, 1)),
10900                                DayOfYear(182, MonthDay(6, 30)),
10901                                DayOfYear(183, MonthDay(7, 1)),
10902                                DayOfYear(213, MonthDay(7, 31)),
10903                                DayOfYear(214, MonthDay(8, 1)),
10904                                DayOfYear(244, MonthDay(8, 31)),
10905                                DayOfYear(245, MonthDay(9, 1)),
10906                                DayOfYear(274, MonthDay(9, 30)),
10907                                DayOfYear(275, MonthDay(10, 1)),
10908                                DayOfYear(305, MonthDay(10, 31)),
10909                                DayOfYear(306, MonthDay(11, 1)),
10910                                DayOfYear(335, MonthDay(11, 30)),
10911                                DayOfYear(336, MonthDay(12, 1)),
10912                                DayOfYear(364, MonthDay(12, 29)),
10913                                DayOfYear(365, MonthDay(12, 30)),
10914                                DayOfYear(366, MonthDay(12, 31))];
10915 
10916     void initializeTests() @safe
10917     {
10918         import std.algorithm.sorting : sort;
10919         import std.typecons : Rebindable;
10920         immutable lt = LocalTime().utcToTZ(0);
10921         currLocalDiffFromUTC = dur!"hnsecs"(lt);
10922 
10923         version (Posix)
10924         {
10925             immutable otherTZ = lt < 0 ? PosixTimeZone.getTimeZone("Australia/Sydney")
10926                                        : PosixTimeZone.getTimeZone("America/Denver");
10927         }
10928         else version (Windows)
10929         {
10930             immutable otherTZ = lt < 0 ? WindowsTimeZone.getTimeZone("AUS Eastern Standard Time")
10931                                        : WindowsTimeZone.getTimeZone("Mountain Standard Time");
10932         }
10933 
10934         immutable ot = otherTZ.utcToTZ(0);
10935 
10936         auto diffs = [0L, lt, ot];
10937         auto diffAA = [0L : Rebindable!(immutable TimeZone)(UTC())];
10938         diffAA[lt] = Rebindable!(immutable TimeZone)(LocalTime());
10939         diffAA[ot] = Rebindable!(immutable TimeZone)(otherTZ);
10940 
10941         sort(diffs);
10942         testTZs = [diffAA[diffs[0]], diffAA[diffs[1]], diffAA[diffs[2]]];
10943 
10944         testFracSecs = [Duration.zero, hnsecs(1), hnsecs(5007), hnsecs(9_999_999)];
10945 
10946         foreach (year; testYearsBC)
10947         {
10948             foreach (md; testMonthDays)
10949                 testDatesBC ~= Date(year, md.month, md.day);
10950         }
10951 
10952         foreach (year; testYearsAD)
10953         {
10954             foreach (md; testMonthDays)
10955                 testDatesAD ~= Date(year, md.month, md.day);
10956         }
10957 
10958         foreach (dt; testDatesBC)
10959         {
10960             foreach (tod; testTODs)
10961                 testDateTimesBC ~= DateTime(dt, tod);
10962         }
10963 
10964         foreach (dt; testDatesAD)
10965         {
10966             foreach (tod; testTODs)
10967                 testDateTimesAD ~= DateTime(dt, tod);
10968         }
10969 
10970         foreach (dt; testDateTimesBC)
10971         {
10972             foreach (tz; testTZs)
10973             {
10974                 foreach (fs; testFracSecs)
10975                     testSysTimesBC ~= SysTime(dt, fs, tz);
10976             }
10977         }
10978 
10979         foreach (dt; testDateTimesAD)
10980         {
10981             foreach (tz; testTZs)
10982             {
10983                 foreach (fs; testFracSecs)
10984                     testSysTimesAD ~= SysTime(dt, fs, tz);
10985             }
10986         }
10987     }
10988 }
10989