1 // Written in the D programming language
2 
3 /++
4 
5 $(DIVC quickindex,
6 $(BOOKTABLE,
7 $(TR $(TH Category) $(TH Functions))
8 $(TR $(TD Types) $(TD
9     $(LREF Clock)
10     $(LREF SysTime)
11     $(LREF DosFileTime)
12 ))
13 $(TR $(TD Conversion) $(TD
14     $(LREF parseRFC822DateTime)
15     $(LREF DosFileTimeToSysTime)
16     $(LREF FILETIMEToStdTime)
17     $(LREF FILETIMEToSysTime)
18     $(LREF stdTimeToFILETIME)
19     $(LREF stdTimeToUnixTime)
20     $(LREF SYSTEMTIMEToSysTime)
21     $(LREF SysTimeToDosFileTime)
22     $(LREF SysTimeToFILETIME)
23     $(LREF SysTimeToSYSTEMTIME)
24     $(LREF unixTimeToStdTime)
25 ))
26 ))
27 
28     License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
29     Authors:   $(HTTP jmdavisprog.com, Jonathan M Davis)
30     Source:    $(PHOBOSSRC std/datetime/systime.d)
31 +/
32 module std.datetime.systime;
33 
34 version (OSX)
35     version = Darwin;
36 else version (iOS)
37     version = Darwin;
38 else version (TVOS)
39     version = Darwin;
40 else version (WatchOS)
41     version = Darwin;
42 
43 /// Get the current time as a $(LREF SysTime)
44 @safe unittest
45 {
46     import std.datetime.timezone : LocalTime;
47     SysTime today = Clock.currTime();
48     assert(today.timezone is LocalTime());
49 }
50 
51 /// Construct a $(LREF SysTime) from a ISO time string
52 @safe unittest
53 {
54     import std.datetime.date : DateTime;
55     import std.datetime.timezone : UTC;
56 
57     auto st = SysTime.fromISOExtString("2018-01-01T10:30:00Z");
58     assert(st == SysTime(DateTime(2018, 1, 1, 10, 30, 0), UTC()));
59 }
60 
61 /// Make a specific point in time in the New York timezone
62 @safe unittest
63 {
64     import core.time : hours;
65     import std.datetime.date : DateTime;
66     import std.datetime.timezone : SimpleTimeZone;
67 
68     auto ny = SysTime(
69         DateTime(2018, 1, 1, 10, 30, 0),
70         new immutable SimpleTimeZone(-5.hours, "America/New_York")
71     );
72 
73     // ISO standard time strings
74     assert(ny.toISOString() == "20180101T103000-05:00");
75     assert(ny.toISOExtString() == "2018-01-01T10:30:00-05:00");
76 }
77 
78 // Note: reconsider using specific imports below after
79 // https://issues.dlang.org/show_bug.cgi?id=17630 has been fixed
80 import core.time;// : ClockType, convert, dur, Duration, seconds, TimeException;
81 import std.datetime.date;// : _monthNames, AllowDayOverflow, CmpTimeUnits, Date,
82     //DateTime, DateTimeException, DayOfWeek, enforceValid, getDayOfWeek, maxDay,
83     //Month, splitUnitsFromHNSecs, TimeOfDay, validTimeUnits, yearIsLeapYear;
84 import std.datetime.timezone;// : LocalTime, SimpleTimeZone, TimeZone, UTC;
85 import std.exception : enforce;
86 import std.format : format;
87 import std.range.primitives;
88 import std.traits : isIntegral, isSigned, isSomeString, isNarrowString;
89 
90 version (Windows)
91 {
92     import core.stdc.time : time_t;
93     import core.sys.windows.winbase;
94     import core.sys.windows.winnt;
95     import core.sys.windows.winsock2;
96 }
97 else version (Posix)
98 {
99     import core.sys.posix.signal : timespec;
100     import core.sys.posix.sys.types : time_t;
101 }
102 
103 version (StdUnittest)
104 {
105     import core.exception : AssertError;
106     import std.exception : assertThrown;
107 }
108 
109 
110 @safe unittest
111 {
112     initializeTests();
113 }
114 
115 version (unittest) private bool clockSupported(ClockType c)
116 {
117     // Skip unsupported clocks on older linux kernels, assume that only
118     // CLOCK_MONOTONIC and CLOCK_REALTIME exist, as that is the lowest
119     // common denominator supported by all versions of Linux pre-2.6.12.
120     version (Linux_Pre_2639)
121         return c == ClockType.normal || c == ClockType.precise;
122     else
123         return true;
124 }
125 
126 /++
127     Effectively a namespace to make it clear that the methods it contains are
128     getting the time from the system clock. It cannot be instantiated.
129  +/
130 final class Clock
131 {
132 public:
133 
134     /++
135         Returns the current time in the given time zone.
136 
137         Params:
138             clockType = The $(REF ClockType, core,time) indicates which system
139                         clock to use to get the current time. Very few programs
140                         need to use anything other than the default.
141             tz = The time zone for the SysTime that's returned.
142 
143         Throws:
144             $(REF DateTimeException,std,datetime,date) if it fails to get the
145             time.
146       +/
147     static SysTime currTime(ClockType clockType = ClockType.normal)(immutable TimeZone tz = LocalTime()) @safe
148     {
149         return SysTime(currStdTime!clockType, tz);
150     }
151 
152     @safe unittest
153     {
154         import std.format : format;
155         import core.time;
156         assert(currTime().timezone is LocalTime());
157         assert(currTime(UTC()).timezone is UTC());
158 
159         // core.stdc.time.time does not always use unix time on Windows systems.
160         // In particular, dmc does not use unix time. If we can guarantee that
161         // the MS runtime uses unix time, then we may be able run this test
162         // then, but for now, we're just not going to run this test on Windows.
163         version (Posix)
164         {
165             static import core.stdc.time;
166             static import std.math;
167             immutable unixTimeD = currTime().toUnixTime();
168             immutable unixTimeC = core.stdc.time.time(null);
169             assert(std.math.abs(unixTimeC - unixTimeD) <= 2);
170         }
171 
172         auto norm1 = Clock.currTime;
173         auto norm2 = Clock.currTime(UTC());
174         assert(norm1 <= norm2, format("%s %s", norm1, norm2));
175         assert(abs(norm1 - norm2) <= seconds(2));
176 
177         import std.meta : AliasSeq;
178         static foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
179         {{
180             static if (clockSupported(ct))
181             {
182                 auto value1 = Clock.currTime!ct;
183                 auto value2 = Clock.currTime!ct(UTC());
184                 assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
185                 assert(abs(value1 - value2) <= seconds(2), format("ClockType.%s", ct));
186             }
187         }}
188     }
189 
190 
191     /++
192         Returns the number of hnsecs since midnight, January 1st, 1 A.D. for the
193         current time.
194 
195         Params:
196             clockType = The $(REF ClockType, core,time) indicates which system
197                         clock to use to get the current time. Very few programs
198                         need to use anything other than the default.
199 
200         Throws:
201             $(REF DateTimeException,std,datetime,date) if it fails to get the
202             time.
203       +/
204     static @property long currStdTime(ClockType clockType = ClockType.normal)() @trusted
205     {
206         static if (clockType != ClockType.coarse &&
207                    clockType != ClockType.normal &&
208                    clockType != ClockType.precise &&
209                    clockType != ClockType.second)
210         {
211             static assert(0, format("ClockType.%s is not supported by Clock.currTime or Clock.currStdTime", clockType));
212         }
213 
214         version (Windows)
215         {
216             FILETIME fileTime;
217             GetSystemTimeAsFileTime(&fileTime);
218             immutable result = FILETIMEToStdTime(&fileTime);
219             static if (clockType == ClockType.second)
220             {
221                 // Ideally, this would use core.std.time.time, but the C runtime
222                 // has to be using unix time for that to work, and that's not
223                 // guaranteed on Windows. Digital Mars does not use unix time.
224                 // MS may or may not. If it does, then this can be made to use
225                 // core.stdc.time for MS, but for now, we'll leave it like this.
226                 return convert!("seconds", "hnsecs")(convert!("hnsecs", "seconds")(result));
227             }
228             else
229                 return result;
230         }
231         else version (Posix)
232         {
233             static import core.stdc.time;
234             enum hnsecsToUnixEpoch = unixTimeToStdTime(0);
235 
236             version (Darwin)
237             {
238                 static if (clockType == ClockType.second)
239                     return unixTimeToStdTime(core.stdc.time.time(null));
240                 else
241                 {
242                     import core.sys.posix.sys.time : gettimeofday, timeval;
243                     timeval tv = void;
244                     // Posix gettimeofday called with a valid timeval address
245                     // and a null second parameter doesn't fail.
246                     gettimeofday(&tv, null);
247                     return convert!("seconds", "hnsecs")(tv.tv_sec) +
248                            tv.tv_usec * 10 +
249                            hnsecsToUnixEpoch;
250                 }
251             }
252             else version (linux)
253             {
254                 static if (clockType == ClockType.second)
255                     return unixTimeToStdTime(core.stdc.time.time(null));
256                 else
257                 {
258                     import core.sys.linux.time : CLOCK_REALTIME_COARSE;
259                     import core.sys.posix.time : clock_gettime, CLOCK_REALTIME;
260                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_COARSE;
261                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
262                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
263                     else static assert(0, "Previous static if is wrong.");
264                     timespec ts = void;
265                     immutable error = clock_gettime(clockArg, &ts);
266                     // Posix clock_gettime called with a valid address and valid clock_id is only
267                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
268                     // is long or larger overflow won't happen before 292 billion years A.D.
269                     static if (ts.tv_sec.max < long.max)
270                     {
271                         if (error)
272                             throw new TimeException("Call to clock_gettime() failed");
273                     }
274                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
275                            ts.tv_nsec / 100 +
276                            hnsecsToUnixEpoch;
277                 }
278             }
279             else version (FreeBSD)
280             {
281                 import core.sys.freebsd.time : clock_gettime, CLOCK_REALTIME,
282                     CLOCK_REALTIME_FAST, CLOCK_REALTIME_PRECISE, CLOCK_SECOND;
283                 static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_FAST;
284                 else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
285                 else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE;
286                 else static if (clockType == ClockType.second)  alias clockArg = CLOCK_SECOND;
287                 else static assert(0, "Previous static if is wrong.");
288                 timespec ts = void;
289                 immutable error = clock_gettime(clockArg, &ts);
290                 // Posix clock_gettime called with a valid address and valid clock_id is only
291                 // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
292                 // is long or larger overflow won't happen before 292 billion years A.D.
293                 static if (ts.tv_sec.max < long.max)
294                 {
295                     if (error)
296                         throw new TimeException("Call to clock_gettime() failed");
297                 }
298                 return convert!("seconds", "hnsecs")(ts.tv_sec) +
299                        ts.tv_nsec / 100 +
300                        hnsecsToUnixEpoch;
301             }
302             else version (NetBSD)
303             {
304                 static if (clockType == ClockType.second)
305                     return unixTimeToStdTime(core.stdc.time.time(null));
306                 else
307                 {
308                     import core.sys.netbsd.time : clock_gettime, CLOCK_REALTIME;
309                     timespec ts = void;
310                     immutable error = clock_gettime(CLOCK_REALTIME, &ts);
311                     // Posix clock_gettime called with a valid address and valid clock_id is only
312                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
313                     // is long or larger overflow won't happen before 292 billion years A.D.
314                     static if (ts.tv_sec.max < long.max)
315                     {
316                         if (error)
317                             throw new TimeException("Call to clock_gettime() failed");
318                     }
319                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
320                            ts.tv_nsec / 100 +
321                            hnsecsToUnixEpoch;
322                 }
323             }
324             else version (OpenBSD)
325             {
326                 static if (clockType == ClockType.second)
327                     return unixTimeToStdTime(core.stdc.time.time(null));
328                 else
329                 {
330                     import core.sys.openbsd.time : clock_gettime, CLOCK_REALTIME;
331                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME;
332                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
333                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
334                     else static assert(0, "Previous static if is wrong.");
335                     timespec ts;
336                     if (clock_gettime(clockArg, &ts) != 0)
337                         throw new TimeException("Call to clock_gettime() failed");
338                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
339                            ts.tv_nsec / 100 +
340                            hnsecsToUnixEpoch;
341                 }
342             }
343             else version (DragonFlyBSD)
344             {
345                 import core.sys.dragonflybsd.time : clock_gettime, CLOCK_REALTIME,
346                     CLOCK_REALTIME_FAST, CLOCK_REALTIME_PRECISE, CLOCK_SECOND;
347                 static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_FAST;
348                 else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
349                 else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE;
350                 else static if (clockType == ClockType.second)  alias clockArg = CLOCK_SECOND;
351                 else static assert(0, "Previous static if is wrong.");
352                 timespec ts = void;
353                 immutable error = clock_gettime(clockArg, &ts);
354                 // Posix clock_gettime called with a valid address and valid clock_id is only
355                 // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
356                 // is long or larger overflow won't happen before 292 billion years A.D.
357                 static if (ts.tv_sec.max < long.max)
358                 {
359                     if (error)
360                         throw new TimeException("Call to clock_gettime() failed");
361                 }
362                 return convert!("seconds", "hnsecs")(ts.tv_sec) +
363                        ts.tv_nsec / 100 +
364                        hnsecsToUnixEpoch;
365             }
366             else version (Solaris)
367             {
368                 static if (clockType == ClockType.second)
369                     return unixTimeToStdTime(core.stdc.time.time(null));
370                 else
371                 {
372                     import core.sys.solaris.time : clock_gettime, CLOCK_REALTIME;
373                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME;
374                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
375                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
376                     else static assert(0, "Previous static if is wrong.");
377                     timespec ts = void;
378                     immutable error = clock_gettime(clockArg, &ts);
379                     // Posix clock_gettime called with a valid address and valid clock_id is only
380                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
381                     // is long or larger overflow won't happen before 292 billion years A.D.
382                     static if (ts.tv_sec.max < long.max)
383                     {
384                         if (error)
385                             throw new TimeException("Call to clock_gettime() failed");
386                     }
387                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
388                            ts.tv_nsec / 100 +
389                            hnsecsToUnixEpoch;
390                 }
391             }
392             else version (Hurd)
393             {
394                 static if (clockType == ClockType.second)
395                     return unixTimeToStdTime(core.stdc.time.time(null));
396                 else
397                 {
398                     import core.sys.hurd.time : CLOCK_REALTIME_COARSE;
399                     import core.sys.posix.time : clock_gettime, CLOCK_REALTIME;
400                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_COARSE;
401                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
402                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
403                     else static assert(0, "Previous static if is wrong.");
404                     timespec ts = void;
405                     immutable error = clock_gettime(clockArg, &ts);
406                     // Posix clock_gettime called with a valid address and valid clock_id is only
407                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
408                     // is long or larger overflow won't happen before 292 billion years A.D.
409                     static if (ts.tv_sec.max < long.max)
410                     {
411                         if (error)
412                             throw new TimeException("Call to clock_gettime() failed");
413                     }
414                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
415                            ts.tv_nsec / 100 +
416                            hnsecsToUnixEpoch;
417                 }
418             }
419             else static assert(0, "Unsupported OS");
420         }
421         else static assert(0, "Unsupported OS");
422     }
423 
424     @safe unittest
425     {
426         import std.format : format;
427         import std.math.algebraic : abs;
428         import std.meta : AliasSeq;
429         enum limit = convert!("seconds", "hnsecs")(2);
430 
431         auto norm1 = Clock.currStdTime;
432         auto norm2 = Clock.currStdTime;
433         assert(norm1 <= norm2, format("%s %s", norm1, norm2));
434         assert(abs(norm1 - norm2) <= limit);
435 
436         static foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
437         {{
438             static if (clockSupported(ct))
439             {
440                 auto value1 = Clock.currStdTime!ct;
441                 auto value2 = Clock.currStdTime!ct;
442                 assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
443                 assert(abs(value1 - value2) <= limit);
444             }
445         }}
446     }
447 
448 
449 private:
450 
451     @disable this();
452 }
453 
454 /// Get the current time as a $(LREF SysTime)
455 @safe unittest
456 {
457     import std.datetime.timezone : LocalTime;
458     SysTime today = Clock.currTime();
459     assert(today.timezone is LocalTime());
460 }
461 
462 
463 /++
464     `SysTime` is the type used to get the current time from the
465     system or doing anything that involves time zones. Unlike
466     $(REF DateTime,std,datetime,date), the time zone is an integral part of
467     `SysTime` (though for local time applications, time zones can be ignored
468     and it will work, since it defaults to using the local time zone). It holds
469     its internal time in std time (hnsecs since midnight, January 1st, 1 A.D.
470     UTC), so it interfaces well with the system time.
471 
472     An $(I hnsec) (hecto-nanosecond) is 100 nanoseconds. There are 10,000,000 hnsecs in a second.
473 
474 $(PANEL
475     Unlike $(REF_SHORT DateTime,std,datetime,date), `SysTime` is not optimized for
476     calendar-based operations, and getting individual units from it such as
477     years or days is going to involve conversions and be less efficient.
478 
479     For calendar-based operations that don't
480     care about time zones, then $(REF_SHORT DateTime,std,datetime,date) would be
481     the type to use. For system time, use `SysTime`.
482 )
483 $(P
484     Casting a `SysTime` to one of the following types will perform a conversion:
485 )
486     * $(REF Date,std,datetime,date)
487     * $(REF_SHORT DateTime,std,datetime,date)
488     * $(REF_SHORT TimeOfDay,std,datetime,date)
489 $(P
490     To convert a
491     $(REF_SHORT Date,std,datetime,date) or $(REF_SHORT DateTime,std,datetime,date) to a
492     `SysTime`, use `SysTime`'s constructor, and pass in the intended time
493     zone with it (or don't pass in a $(REF TimeZone,std,datetime,timezone), and
494     the local time zone will be used). Be aware, however, that converting from a
495     $(REF_SHORT DateTime,std,datetime,date) to a `SysTime` will not necessarily
496     be 100% accurate due to DST (one hour of the year doesn't exist and another
497     occurs twice). To not risk any conversion errors, keep times as
498     `SysTime`s. Aside from DST though, there shouldn't be any conversion
499     problems.
500 )
501 $(PANEL
502     For using time zones other than local time or UTC, use
503     $(REF PosixTimeZone,std,datetime,timezone) on Posix systems (or on Windows,
504     if providing the TZ Database files), and use
505     $(REF WindowsTimeZone,std,datetime,timezone) on Windows systems. The time in
506     `SysTime` is kept internally in hnsecs from midnight, January 1st, 1 A.D.
507     UTC. Conversion error cannot happen when changing the time zone of a
508     `SysTime`. $(REF LocalTime,std,datetime,timezone) is the
509     $(REF_SHORT TimeZone,std,datetime,timezone) class which represents the local time,
510     and `UTC` is the $(REF_SHORT TimeZone,std,datetime,timezone) class which
511     represents UTC. `SysTime` uses $(REF_SHORT LocalTime,std,datetime,timezone) if
512     no $(REF_SHORT TimeZone,std,datetime,timezone) is provided. For more details on
513     time zones, see the documentation for $(REF_SHORT TimeZone,std,datetime,timezone),
514     $(REF_SHORT PosixTimeZone,std,datetime,timezone), and
515     $(REF_SHORT WindowsTimeZone,std,datetime,timezone).
516 )
517 $(P
518     `SysTime`'s range is from approximately 29,000 B.C. to approximately
519     29,000 A.D.
520 )
521 See_Also:
522     $(RELATIVE_LINK2 .Clock.currTime, `Clock.currTime`) will return the current time as a `SysTime`.
523   +/
524 struct SysTime
525 {
526     import core.stdc.time : tm;
527     version (Posix) import core.sys.posix.sys.time : timeval;
528     import std.typecons : Rebindable;
529 
530 public:
531 
532     /++
533         Params:
534             dateTime = The $(REF DateTime,std,datetime,date) to use to set
535                        this $(LREF SysTime)'s internal std time. As
536                        $(REF DateTime,std,datetime,date) has no concept of
537                        time zone, tz is used as its time zone.
538             tz       = The $(REF TimeZone,std,datetime,timezone) to use for this
539                        $(LREF SysTime). If null,
540                        $(REF LocalTime,std,datetime,timezone) will be used. The
541                        given $(REF DateTime,std,datetime,date) is assumed to
542                        be in the given time zone.
543       +/
544     this(DateTime dateTime, return scope immutable TimeZone tz = null) return scope @safe nothrow
545     {
546         try
547             this(dateTime, Duration.zero, tz);
548         catch (Exception e)
549             assert(0, "SysTime's constructor threw when it shouldn't have.");
550     }
551 
552     @safe unittest
553     {
554         static void test(DateTime dt, immutable TimeZone tz, long expected)
555         {
556             auto sysTime = SysTime(dt, tz);
557             assert(sysTime._stdTime == expected);
558             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given DateTime: %s", dt));
559         }
560 
561         test(DateTime.init, UTC(), 0);
562         test(DateTime(1, 1, 1, 12, 30, 33), UTC(), 450_330_000_000L);
563         test(DateTime(0, 12, 31, 12, 30, 33), UTC(), -413_670_000_000L);
564         test(DateTime(1, 1, 1, 0, 0, 0), UTC(), 0);
565         test(DateTime(1, 1, 1, 0, 0, 1), UTC(), 10_000_000L);
566         test(DateTime(0, 12, 31, 23, 59, 59), UTC(), -10_000_000L);
567 
568         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(-60)), 36_000_000_000L);
569         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(Duration.zero), 0);
570         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(60)), -36_000_000_000L);
571 
572         static void testScope(scope ref DateTime dt) @safe
573         {
574             auto st = SysTime(dt);
575         }
576     }
577 
578     /++
579         Params:
580             dateTime = The $(REF DateTime,std,datetime,date) to use to set
581                        this $(LREF SysTime)'s internal std time. As
582                        $(REF DateTime,std,datetime,date) has no concept of
583                        time zone, tz is used as its time zone.
584             fracSecs = The fractional seconds portion of the time.
585             tz       = The $(REF TimeZone,std,datetime,timezone) to use for this
586                        $(LREF SysTime). If null,
587                        $(REF LocalTime,std,datetime,timezone) will be used. The
588                        given $(REF DateTime,std,datetime,date) is assumed to
589                        be in the given time zone.
590 
591         Throws:
592             $(REF DateTimeException,std,datetime,date) if `fracSecs` is negative or if it's
593             greater than or equal to one second.
594       +/
595     this(DateTime dateTime, Duration fracSecs, return scope immutable TimeZone tz = null) return scope @safe
596     {
597         enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
598         enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
599         auto nonNullTZ = tz is null ? LocalTime() : tz;
600 
601         immutable dateDiff = dateTime.date - Date.init;
602         immutable todDiff = dateTime.timeOfDay - TimeOfDay.init;
603 
604         immutable adjustedTime = dateDiff + todDiff + fracSecs;
605         immutable standardTime = nonNullTZ.tzToUTC(adjustedTime.total!"hnsecs");
606 
607         this(standardTime, nonNullTZ);
608     }
609 
610     @safe unittest
611     {
612         import core.time;
613         static void test(DateTime dt, Duration fracSecs, immutable TimeZone tz, long expected)
614         {
615             auto sysTime = SysTime(dt, fracSecs, tz);
616             assert(sysTime._stdTime == expected);
617             assert(sysTime._timezone is (tz is null ? LocalTime() : tz),
618                    format("Given DateTime: %s, Given Duration: %s", dt, fracSecs));
619         }
620 
621         test(DateTime.init, Duration.zero, UTC(), 0);
622         test(DateTime(1, 1, 1, 12, 30, 33), Duration.zero, UTC(), 450_330_000_000L);
623         test(DateTime(0, 12, 31, 12, 30, 33), Duration.zero, UTC(), -413_670_000_000L);
624         test(DateTime(1, 1, 1, 0, 0, 0), msecs(1), UTC(), 10_000L);
625         test(DateTime(0, 12, 31, 23, 59, 59), msecs(999), UTC(), -10_000L);
626 
627         test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC(), -1);
628         test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC(), -9_999_999);
629         test(DateTime(0, 12, 31, 23, 59, 59), Duration.zero, UTC(), -10_000_000);
630 
631         assertThrown!DateTimeException(SysTime(DateTime.init, hnsecs(-1), UTC()));
632         assertThrown!DateTimeException(SysTime(DateTime.init, seconds(1), UTC()));
633 
634         static void testScope(scope ref DateTime dt, scope ref Duration d) @safe
635         {
636             auto st = SysTime(dt, d);
637         }
638     }
639 
640     /++
641         Params:
642             date = The $(REF Date,std,datetime,date) to use to set this
643                    $(LREF SysTime)'s internal std time. As
644                    $(REF Date,std,datetime,date) has no concept of time zone, tz
645                    is used as its time zone.
646             tz   = The $(REF TimeZone,std,datetime,timezone) to use for this
647                    $(LREF SysTime). If null,
648                    $(REF LocalTime,std,datetime,timezone) will be used. The
649                    given $(REF Date,std,datetime,date) is assumed to be in the
650                    given time zone.
651       +/
652     this(Date date, return scope immutable TimeZone tz = null) return scope @safe nothrow
653     {
654         _timezone = tz is null ? LocalTime() : tz;
655 
656         try
657         {
658             immutable adjustedTime = (date - Date(1, 1, 1)).total!"hnsecs";
659             immutable standardTime = _timezone.tzToUTC(adjustedTime);
660 
661             this(standardTime, _timezone);
662         }
663         catch (Exception e)
664             assert(0, "Date's constructor through when it shouldn't have.");
665     }
666 
667     @safe unittest
668     {
669         static void test(Date d, immutable TimeZone tz, long expected)
670         {
671             auto sysTime = SysTime(d, tz);
672             assert(sysTime._stdTime == expected);
673             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given Date: %s", d));
674         }
675 
676         test(Date.init, UTC(), 0);
677         test(Date(1, 1, 1), UTC(), 0);
678         test(Date(1, 1, 2), UTC(), 864000000000);
679         test(Date(0, 12, 31), UTC(), -864000000000);
680 
681         static void testScope(scope ref Date d) @safe
682         {
683             auto st = SysTime(d);
684         }
685     }
686 
687     /++
688         Note:
689             Whereas the other constructors take in the given date/time, assume
690             that it's in the given time zone, and convert it to hnsecs in UTC
691             since midnight, January 1st, 1 A.D. UTC - i.e. std time - this
692             constructor takes a std time, which is specifically already in UTC,
693             so no conversion takes place. Of course, the various getter
694             properties and functions will use the given time zone's conversion
695             function to convert the results to that time zone, but no conversion
696             of the arguments to this constructor takes place.
697 
698         Params:
699             stdTime = The number of hnsecs since midnight, January 1st, 1 A.D.
700                       UTC.
701             tz      = The $(REF TimeZone,std,datetime,timezone) to use for this
702                       $(LREF SysTime). If null,
703                       $(REF LocalTime,std,datetime,timezone) will be used.
704       +/
705     this(long stdTime, return scope immutable TimeZone tz = null) return scope @safe pure nothrow
706     {
707         _stdTime = stdTime;
708         _timezone = tz is null ? LocalTime() : tz;
709     }
710 
711     @safe unittest
712     {
713         static void test(long stdTime, immutable TimeZone tz)
714         {
715             auto sysTime = SysTime(stdTime, tz);
716             assert(sysTime._stdTime == stdTime);
717             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given stdTime: %s", stdTime));
718         }
719 
720         foreach (stdTime; [-1234567890L, -250, 0, 250, 1235657390L])
721         {
722             foreach (tz; testTZs)
723                 test(stdTime, tz);
724         }
725     }
726 
727 
728     /++
729         Params:
730             rhs = The $(LREF SysTime) to assign to this one.
731 
732         Returns: The `this` of this `SysTime`.
733       +/
734     ref SysTime opAssign()(auto ref const(SysTime) rhs) scope return @safe pure nothrow
735     {
736         _stdTime = rhs._stdTime;
737         _timezone = rhs._timezone;
738         return this;
739     }
740 
741     @safe unittest
742     {
743         SysTime st;
744         st = SysTime(DateTime(2012, 12, 21, 1, 2, 3), UTC());
745         assert(st == SysTime(DateTime(2012, 12, 21, 1, 2, 3), UTC()));
746 
747         const other = SysTime(DateTime(19, 1, 7, 13, 14, 15), LocalTime());
748         st = other;
749         assert(st == other);
750 
751         version (none) // https://issues.dlang.org/show_bug.cgi?id=21175
752         static void testScope(scope ref SysTime left, const scope SysTime right) @safe
753         {
754             left = right;
755         }
756     }
757 
758 
759     /++
760         Checks for equality between this $(LREF SysTime) and the given
761         $(LREF SysTime).
762 
763         Note that the time zone is ignored. Only the internal
764         std times (which are in UTC) are compared.
765      +/
766     bool opEquals()(auto ref const(SysTime) rhs) @safe const pure nothrow scope
767     {
768         return _stdTime == rhs._stdTime;
769     }
770 
771     @safe unittest
772     {
773         import std.range : chain;
774 
775         assert(SysTime(DateTime.init, UTC()) == SysTime(0, UTC()));
776         assert(SysTime(DateTime.init, UTC()) == SysTime(0));
777         assert(SysTime(Date.init, UTC()) == SysTime(0));
778         assert(SysTime(0) == SysTime(0));
779 
780         static void test(DateTime dt, immutable TimeZone tz1, immutable TimeZone tz2)
781         {
782             auto st1 = SysTime(dt);
783             st1.timezone = tz1;
784 
785             auto st2 = SysTime(dt);
786             st2.timezone = tz2;
787 
788             assert(st1 == st2);
789         }
790 
791         foreach (tz1; testTZs)
792         {
793             foreach (tz2; testTZs)
794             {
795                 foreach (dt; chain(testDateTimesBC, testDateTimesAD))
796                     test(dt, tz1, tz2);
797             }
798         }
799 
800         auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
801         const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
802         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
803         assert(st == st);
804         assert(st == cst);
805         assert(st == ist);
806         assert(cst == st);
807         assert(cst == cst);
808         assert(cst == ist);
809         assert(ist == st);
810         assert(ist == cst);
811         assert(ist == ist);
812 
813         static void testScope(scope ref SysTime left, const scope SysTime right) @safe
814         {
815             assert(left == right);
816             assert(right == left);
817         }
818     }
819 
820 
821     /++
822         Compares this $(LREF SysTime) with the given $(LREF SysTime).
823 
824         Time zone is irrelevant when comparing $(LREF SysTime)s.
825 
826         Returns:
827             $(BOOKTABLE,
828             $(TR $(TD this &lt; rhs) $(TD &lt; 0))
829             $(TR $(TD this == rhs) $(TD 0))
830             $(TR $(TD this &gt; rhs) $(TD &gt; 0))
831             )
832      +/
833     int opCmp()(auto ref const(SysTime) rhs) @safe const pure nothrow scope
834     {
835         if (_stdTime < rhs._stdTime)
836             return -1;
837         if (_stdTime > rhs._stdTime)
838             return 1;
839         return 0;
840     }
841 
842     @safe unittest
843     {
844         import std.algorithm.iteration : map;
845         import std.array : array;
846         import std.range : chain;
847 
848         assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0, UTC())) == 0);
849         assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0)) == 0);
850         assert(SysTime(Date.init, UTC()).opCmp(SysTime(0)) == 0);
851         assert(SysTime(0).opCmp(SysTime(0)) == 0);
852 
853         static void testEqual(SysTime st, immutable TimeZone tz1, immutable TimeZone tz2)
854         {
855             auto st1 = st;
856             st1.timezone = tz1;
857 
858             auto st2 = st;
859             st2.timezone = tz2;
860 
861             assert(st1.opCmp(st2) == 0);
862         }
863 
864         auto sts = array(map!SysTime(chain(testDateTimesBC, testDateTimesAD)));
865 
866         foreach (st; sts)
867         {
868             foreach (tz1; testTZs)
869             {
870                 foreach (tz2; testTZs)
871                     testEqual(st, tz1, tz2);
872             }
873         }
874 
875         static void testCmp(SysTime st1, immutable TimeZone tz1, SysTime st2, immutable TimeZone tz2)
876         {
877             st1.timezone = tz1;
878             st2.timezone = tz2;
879             assert(st1.opCmp(st2) < 0);
880             assert(st2.opCmp(st1) > 0);
881         }
882 
883         foreach (si, st1; sts)
884         {
885             foreach (st2; sts[si + 1 .. $])
886             {
887                 foreach (tz1; testTZs)
888                 {
889                     foreach (tz2; testTZs)
890                         testCmp(st1, tz1, st2, tz2);
891                 }
892             }
893         }
894 
895         auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
896         const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
897         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
898         assert(st.opCmp(st) == 0);
899         assert(st.opCmp(cst) == 0);
900         assert(st.opCmp(ist) == 0);
901         assert(cst.opCmp(st) == 0);
902         assert(cst.opCmp(cst) == 0);
903         assert(cst.opCmp(ist) == 0);
904         assert(ist.opCmp(st) == 0);
905         assert(ist.opCmp(cst) == 0);
906         assert(ist.opCmp(ist) == 0);
907 
908         static void testScope(scope ref SysTime left, const scope SysTime right) @safe
909         {
910             assert(left < right);
911             assert(right > left);
912         }
913     }
914 
915 
916     /++
917         Returns: A hash of the $(LREF SysTime).
918      +/
919     size_t toHash() const @nogc pure nothrow @safe scope
920     {
921         static if (is(size_t == ulong))
922             return _stdTime;
923         else
924         {
925             // MurmurHash2
926             enum ulong m = 0xc6a4a7935bd1e995UL;
927             enum ulong n = m * 16;
928             enum uint r = 47;
929 
930             ulong k = _stdTime;
931             k *= m;
932             k ^= k >> r;
933             k *= m;
934 
935             ulong h = n;
936             h ^= k;
937             h *= m;
938 
939             return cast(size_t) h;
940         }
941     }
942 
943     @safe unittest
944     {
945         assert(SysTime(0).toHash == SysTime(0).toHash);
946         assert(SysTime(DateTime(2000, 1, 1)).toHash == SysTime(DateTime(2000, 1, 1)).toHash);
947         assert(SysTime(DateTime(2000, 1, 1)).toHash != SysTime(DateTime(2000, 1, 2)).toHash);
948 
949         // test that timezones aren't taken into account
950         assert(SysTime(0, LocalTime()).toHash == SysTime(0, LocalTime()).toHash);
951         assert(SysTime(0, LocalTime()).toHash == SysTime(0, UTC()).toHash);
952         assert(SysTime(DateTime(2000, 1, 1), LocalTime()).toHash == SysTime(DateTime(2000, 1, 1), LocalTime()).toHash);
953         immutable zone = new SimpleTimeZone(dur!"minutes"(60));
954         assert(SysTime(DateTime(2000, 1, 1, 1), zone).toHash == SysTime(DateTime(2000, 1, 1), UTC()).toHash);
955         assert(SysTime(DateTime(2000, 1, 1), zone).toHash != SysTime(DateTime(2000, 1, 1), UTC()).toHash);
956 
957         static void testScope(scope ref SysTime st) @safe
958         {
959             auto result = st.toHash();
960         }
961     }
962 
963 
964     /++
965         Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
966         are B.C.
967      +/
968     @property short year() @safe const nothrow scope
969     {
970         return (cast(Date) this).year;
971     }
972 
973     @safe unittest
974     {
975         import std.range : chain;
976         static void test(SysTime sysTime, long expected)
977         {
978             assert(sysTime.year == expected, format("Value given: %s", sysTime));
979         }
980 
981         test(SysTime(0, UTC()), 1);
982         test(SysTime(1, UTC()), 1);
983         test(SysTime(-1, UTC()), 0);
984 
985         foreach (year; chain(testYearsBC, testYearsAD))
986         {
987             foreach (md; testMonthDays)
988             {
989                 foreach (tod; testTODs)
990                 {
991                     auto dt = DateTime(Date(year, md.month, md.day), tod);
992                     foreach (tz; testTZs)
993                     {
994                         foreach (fs; testFracSecs)
995                             test(SysTime(dt, fs, tz), year);
996                     }
997                 }
998             }
999         }
1000 
1001         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1002         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1003         assert(cst.year == 1999);
1004         assert(ist.year == 1999);
1005 
1006         static void testScope(scope ref SysTime st) @safe
1007         {
1008             auto result = st.year;
1009         }
1010     }
1011 
1012     /++
1013         Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
1014         are B.C.
1015 
1016         Params:
1017             year = The year to set this $(LREF SysTime)'s year to.
1018 
1019         Throws:
1020             $(REF DateTimeException,std,datetime,date) if the new year is not
1021             a leap year and the resulting date would be on February 29th.
1022      +/
1023     @property void year(int year) @safe scope
1024     {
1025         auto hnsecs = adjTime;
1026         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1027 
1028         if (hnsecs < 0)
1029         {
1030             hnsecs += convert!("hours", "hnsecs")(24);
1031             --days;
1032         }
1033 
1034         auto date = Date(cast(int) days);
1035         date.year = year;
1036 
1037         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1038         adjTime = newDaysHNSecs + hnsecs;
1039     }
1040 
1041     ///
1042     @safe unittest
1043     {
1044         import std.datetime.date : DateTime;
1045 
1046         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).year == 1999);
1047         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).year == 2010);
1048         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).year == -7);
1049     }
1050 
1051     @safe unittest
1052     {
1053         import std.range : chain;
1054 
1055         static void test(SysTime st, int year, SysTime expected)
1056         {
1057             st.year = year;
1058             assert(st == expected);
1059         }
1060 
1061         foreach (st; chain(testSysTimesBC, testSysTimesAD))
1062         {
1063             auto dt = cast(DateTime) st;
1064 
1065             foreach (year; chain(testYearsBC, testYearsAD))
1066             {
1067                 auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
1068                                  st.fracSecs,
1069                                  st.timezone);
1070                 test(st, year, e);
1071             }
1072         }
1073 
1074         foreach (fs; testFracSecs)
1075         {
1076             foreach (tz; testTZs)
1077             {
1078                 foreach (tod; testTODs)
1079                 {
1080                     test(SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz), 2000,
1081                          SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz));
1082                     test(SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz), 1999,
1083                          SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz));
1084                 }
1085 
1086                 foreach (tod; testTODsThrown)
1087                 {
1088                     auto st = SysTime(DateTime(Date(2000, 2, 29), tod), fs, tz);
1089                     assertThrown!DateTimeException(st.year = 1999);
1090                 }
1091             }
1092         }
1093 
1094         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1095         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1096         static assert(!__traits(compiles, cst.year = 7));
1097         static assert(!__traits(compiles, ist.year = 7));
1098 
1099         static void testScope(scope ref SysTime st) @safe
1100         {
1101             st.year = 42;
1102         }
1103     }
1104 
1105     /++
1106         Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
1107 
1108         Throws:
1109             $(REF DateTimeException,std,datetime,date) if `isAD` is true.
1110      +/
1111     @property ushort yearBC() @safe const scope
1112     {
1113         return (cast(Date) this).yearBC;
1114     }
1115 
1116     ///
1117     @safe unittest
1118     {
1119         import std.datetime.date : DateTime;
1120 
1121         assert(SysTime(DateTime(0, 1, 1, 12, 30, 33)).yearBC == 1);
1122         assert(SysTime(DateTime(-1, 1, 1, 10, 7, 2)).yearBC == 2);
1123         assert(SysTime(DateTime(-100, 1, 1, 4, 59, 0)).yearBC == 101);
1124     }
1125 
1126     @safe unittest
1127     {
1128         import std.exception : assertNotThrown;
1129         foreach (st; testSysTimesBC)
1130         {
1131             auto msg = format("SysTime: %s", st);
1132             assertNotThrown!DateTimeException(st.yearBC, msg);
1133             assert(st.yearBC == (st.year * -1) + 1, msg);
1134         }
1135 
1136         foreach (st; [testSysTimesAD[0], testSysTimesAD[$/2], testSysTimesAD[$-1]])
1137             assertThrown!DateTimeException(st.yearBC, format("SysTime: %s", st));
1138 
1139         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1140         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1141         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1142         st.year = 12;
1143         assert(st.year == 12);
1144         static assert(!__traits(compiles, cst.year = 12));
1145         static assert(!__traits(compiles, ist.year = 12));
1146 
1147         static void testScope(scope ref SysTime st) @safe
1148         {
1149             auto result = st.yearBC;
1150         }
1151     }
1152 
1153 
1154     /++
1155         Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
1156 
1157         Params:
1158             year = The year B.C. to set this $(LREF SysTime)'s year to.
1159 
1160         Throws:
1161             $(REF DateTimeException,std,datetime,date) if a non-positive value
1162             is given.
1163      +/
1164     @property void yearBC(int year) @safe scope
1165     {
1166         auto hnsecs = adjTime;
1167         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1168 
1169         if (hnsecs < 0)
1170         {
1171             hnsecs += convert!("hours", "hnsecs")(24);
1172             --days;
1173         }
1174 
1175         auto date = Date(cast(int) days);
1176         date.yearBC = year;
1177 
1178         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1179         adjTime = newDaysHNSecs + hnsecs;
1180     }
1181 
1182     @safe unittest
1183     {
1184         auto st = SysTime(DateTime(2010, 1, 1, 7, 30, 0));
1185         st.yearBC = 1;
1186         assert(st == SysTime(DateTime(0, 1, 1, 7, 30, 0)));
1187 
1188         st.yearBC = 10;
1189         assert(st == SysTime(DateTime(-9, 1, 1, 7, 30, 0)));
1190     }
1191 
1192     @safe unittest
1193     {
1194         import std.range : chain;
1195         static void test(SysTime st, int year, SysTime expected)
1196         {
1197             st.yearBC = year;
1198             assert(st == expected, format("SysTime: %s", st));
1199         }
1200 
1201         foreach (st; chain(testSysTimesBC, testSysTimesAD))
1202         {
1203             auto dt = cast(DateTime) st;
1204 
1205             foreach (year; testYearsBC)
1206             {
1207                 auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
1208                                  st.fracSecs,
1209                                  st.timezone);
1210                 test(st, (year * -1) + 1, e);
1211             }
1212         }
1213 
1214         foreach (st; [testSysTimesBC[0], testSysTimesBC[$ - 1], testSysTimesAD[0], testSysTimesAD[$ - 1]])
1215         {
1216             foreach (year; testYearsBC)
1217                 assertThrown!DateTimeException(st.yearBC = year);
1218         }
1219 
1220         foreach (fs; testFracSecs)
1221         {
1222             foreach (tz; testTZs)
1223             {
1224                 foreach (tod; testTODs)
1225                 {
1226                     test(SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz), 2001,
1227                          SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz));
1228                     test(SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz), 2000,
1229                          SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz));
1230                 }
1231 
1232                 foreach (tod; testTODsThrown)
1233                 {
1234                     auto st = SysTime(DateTime(Date(-2000, 2, 29), tod), fs, tz);
1235                     assertThrown!DateTimeException(st.year = -1999);
1236                 }
1237             }
1238         }
1239 
1240         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1241         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1242         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1243         st.yearBC = 12;
1244         assert(st.yearBC == 12);
1245         static assert(!__traits(compiles, cst.yearBC = 12));
1246         static assert(!__traits(compiles, ist.yearBC = 12));
1247 
1248         static void testScope(scope ref SysTime st) @safe
1249         {
1250             st.yearBC = 42;
1251         }
1252     }
1253 
1254 
1255     /++
1256         Month of a Gregorian Year.
1257      +/
1258     @property Month month() @safe const nothrow scope
1259     {
1260         return (cast(Date) this).month;
1261     }
1262 
1263     ///
1264     @safe unittest
1265     {
1266         import std.datetime.date : DateTime;
1267 
1268         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).month == 7);
1269         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).month == 10);
1270         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).month == 4);
1271     }
1272 
1273     @safe unittest
1274     {
1275         import std.range : chain;
1276 
1277         static void test(SysTime sysTime, Month expected)
1278         {
1279             assert(sysTime.month == expected, format("Value given: %s", sysTime));
1280         }
1281 
1282         test(SysTime(0, UTC()), Month.jan);
1283         test(SysTime(1, UTC()), Month.jan);
1284         test(SysTime(-1, UTC()), Month.dec);
1285 
1286         foreach (year; chain(testYearsBC, testYearsAD))
1287         {
1288             foreach (md; testMonthDays)
1289             {
1290                 foreach (tod; testTODs)
1291                 {
1292                     auto dt = DateTime(Date(year, md.month, md.day), tod);
1293                     foreach (fs; testFracSecs)
1294                     {
1295                         foreach (tz; testTZs)
1296                             test(SysTime(dt, fs, tz), md.month);
1297                     }
1298                 }
1299             }
1300         }
1301 
1302         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1303         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1304         assert(cst.month == 7);
1305         assert(ist.month == 7);
1306 
1307         static void testScope(scope ref SysTime st) @safe
1308         {
1309             auto result = st.month;
1310         }
1311     }
1312 
1313 
1314     /++
1315         Month of a Gregorian Year.
1316 
1317         Params:
1318             month = The month to set this $(LREF SysTime)'s month to.
1319 
1320         Throws:
1321             $(REF DateTimeException,std,datetime,date) if the given month is
1322             not a valid month.
1323      +/
1324     @property void month(Month month) @safe scope
1325     {
1326         auto hnsecs = adjTime;
1327         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1328 
1329         if (hnsecs < 0)
1330         {
1331             hnsecs += convert!("hours", "hnsecs")(24);
1332             --days;
1333         }
1334 
1335         auto date = Date(cast(int) days);
1336         date.month = month;
1337 
1338         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1339         adjTime = newDaysHNSecs + hnsecs;
1340     }
1341 
1342     @safe unittest
1343     {
1344         import std.algorithm.iteration : filter;
1345         import std.range : chain;
1346 
1347         static void test(SysTime st, Month month, SysTime expected)
1348         {
1349             st.month = cast(Month) month;
1350             assert(st == expected);
1351         }
1352 
1353         foreach (st; chain(testSysTimesBC, testSysTimesAD))
1354         {
1355             auto dt = cast(DateTime) st;
1356 
1357             foreach (md; testMonthDays)
1358             {
1359                 if (st.day > maxDay(dt.year, md.month))
1360                     continue;
1361                 auto e = SysTime(DateTime(dt.year, md.month, dt.day, dt.hour, dt.minute, dt.second),
1362                                  st.fracSecs,
1363                                  st.timezone);
1364                 test(st, md.month, e);
1365             }
1366         }
1367 
1368         foreach (fs; testFracSecs)
1369         {
1370             foreach (tz; testTZs)
1371             {
1372                 foreach (tod; testTODs)
1373                 {
1374                     foreach (year; filter!((a){return yearIsLeapYear(a);}) (chain(testYearsBC, testYearsAD)))
1375                     {
1376                         test(SysTime(DateTime(Date(year, 1, 29), tod), fs, tz),
1377                              Month.feb,
1378                              SysTime(DateTime(Date(year, 2, 29), tod), fs, tz));
1379                     }
1380 
1381                     foreach (year; chain(testYearsBC, testYearsAD))
1382                     {
1383                         test(SysTime(DateTime(Date(year, 1, 28), tod), fs, tz),
1384                              Month.feb,
1385                              SysTime(DateTime(Date(year, 2, 28), tod), fs, tz));
1386                         test(SysTime(DateTime(Date(year, 7, 30), tod), fs, tz),
1387                              Month.jun,
1388                              SysTime(DateTime(Date(year, 6, 30), tod), fs, tz));
1389                     }
1390                 }
1391             }
1392         }
1393 
1394         foreach (fs; [testFracSecs[0], testFracSecs[$-1]])
1395         {
1396             foreach (tz; testTZs)
1397             {
1398                 foreach (tod; testTODsThrown)
1399                 {
1400                     foreach (year; [testYearsBC[$-3], testYearsBC[$-2],
1401                                     testYearsBC[$-2], testYearsAD[0],
1402                                     testYearsAD[$-2], testYearsAD[$-1]])
1403                     {
1404                         auto day = yearIsLeapYear(year) ? 30 : 29;
1405                         auto st1 = SysTime(DateTime(Date(year, 1, day), tod), fs, tz);
1406                         assertThrown!DateTimeException(st1.month = Month.feb);
1407 
1408                         auto st2 = SysTime(DateTime(Date(year, 7, 31), tod), fs, tz);
1409                         assertThrown!DateTimeException(st2.month = Month.jun);
1410                     }
1411                 }
1412             }
1413         }
1414 
1415         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1416         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1417         static assert(!__traits(compiles, cst.month = Month.dec));
1418         static assert(!__traits(compiles, ist.month = Month.dec));
1419 
1420         static void testScope(scope ref SysTime st) @safe
1421         {
1422             st.month = Month.dec;
1423         }
1424     }
1425 
1426     /++
1427         Day of a Gregorian Month.
1428      +/
1429     @property ubyte day() @safe const nothrow scope
1430     {
1431         return (cast(Date) this).day;
1432     }
1433 
1434     ///
1435     @safe unittest
1436     {
1437         import std.datetime.date : DateTime;
1438 
1439         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).day == 6);
1440         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).day == 4);
1441         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).day == 5);
1442     }
1443 
1444     @safe unittest
1445     {
1446         import std.range : chain;
1447 
1448         static void test(SysTime sysTime, int expected)
1449         {
1450             assert(sysTime.day == expected, format("Value given: %s", sysTime));
1451         }
1452 
1453         test(SysTime(0, UTC()), 1);
1454         test(SysTime(1, UTC()), 1);
1455         test(SysTime(-1, UTC()), 31);
1456 
1457         foreach (year; chain(testYearsBC, testYearsAD))
1458         {
1459             foreach (md; testMonthDays)
1460             {
1461                 foreach (tod; testTODs)
1462                 {
1463                     auto dt = DateTime(Date(year, md.month, md.day), tod);
1464 
1465                     foreach (tz; testTZs)
1466                     {
1467                         foreach (fs; testFracSecs)
1468                             test(SysTime(dt, fs, tz), md.day);
1469                     }
1470                 }
1471             }
1472         }
1473 
1474         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1475         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1476          assert(cst.day == 6);
1477         assert(ist.day == 6);
1478 
1479         static void testScope(scope ref SysTime st) @safe
1480         {
1481             auto result = st.day;
1482         }
1483     }
1484 
1485 
1486     /++
1487         Day of a Gregorian Month.
1488 
1489         Params:
1490             day = The day of the month to set this $(LREF SysTime)'s day to.
1491 
1492         Throws:
1493             $(REF DateTimeException,std,datetime,date) if the given day is not
1494             a valid day of the current month.
1495      +/
1496     @property void day(int day) @safe scope
1497     {
1498         auto hnsecs = adjTime;
1499         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1500 
1501         if (hnsecs < 0)
1502         {
1503             hnsecs += convert!("hours", "hnsecs")(24);
1504             --days;
1505         }
1506 
1507         auto date = Date(cast(int) days);
1508         date.day = day;
1509 
1510         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1511         adjTime = newDaysHNSecs + hnsecs;
1512     }
1513 
1514     @safe unittest
1515     {
1516         import std.range : chain;
1517         import std.traits : EnumMembers;
1518 
1519         foreach (day; chain(testDays))
1520         {
1521             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1522             {
1523                 auto dt = cast(DateTime) st;
1524 
1525                 if (day > maxDay(dt.year, dt.month))
1526                     continue;
1527                 auto expected = SysTime(DateTime(dt.year, dt.month, day, dt.hour, dt.minute, dt.second),
1528                                         st.fracSecs,
1529                                         st.timezone);
1530                 st.day = day;
1531                 assert(st == expected, format("[%s] [%s]", st, expected));
1532             }
1533         }
1534 
1535         foreach (tz; testTZs)
1536         {
1537             foreach (tod; testTODs)
1538             {
1539                 foreach (fs; testFracSecs)
1540                 {
1541                     foreach (year; chain(testYearsBC, testYearsAD))
1542                     {
1543                         foreach (month; EnumMembers!Month)
1544                         {
1545                             auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz);
1546                             immutable max = maxDay(year, month);
1547                             auto expected = SysTime(DateTime(Date(year, month, max), tod), fs, tz);
1548 
1549                             st.day = max;
1550                             assert(st == expected, format("[%s] [%s]", st, expected));
1551                         }
1552                     }
1553                 }
1554             }
1555         }
1556 
1557         foreach (tz; testTZs)
1558         {
1559             foreach (tod; testTODsThrown)
1560             {
1561                 foreach (fs; [testFracSecs[0], testFracSecs[$-1]])
1562                 {
1563                     foreach (year; [testYearsBC[$-3], testYearsBC[$-2],
1564                                     testYearsBC[$-2], testYearsAD[0],
1565                                     testYearsAD[$-2], testYearsAD[$-1]])
1566                     {
1567                         foreach (month; EnumMembers!Month)
1568                         {
1569                             auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz);
1570                             immutable max = maxDay(year, month);
1571 
1572                             assertThrown!DateTimeException(st.day = max + 1);
1573                         }
1574                     }
1575                 }
1576             }
1577         }
1578 
1579         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1580         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1581         static assert(!__traits(compiles, cst.day = 27));
1582         static assert(!__traits(compiles, ist.day = 27));
1583 
1584         static void testScope(scope ref SysTime st) @safe
1585         {
1586             st.day = 12;
1587         }
1588     }
1589 
1590 
1591     /++
1592         Hours past midnight.
1593      +/
1594     @property ubyte hour() @safe const nothrow scope
1595     {
1596         auto hnsecs = adjTime;
1597         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1598 
1599         if (hnsecs < 0)
1600         {
1601             hnsecs += convert!("hours", "hnsecs")(24);
1602             --days;
1603         }
1604 
1605         return cast(ubyte) getUnitsFromHNSecs!"hours"(hnsecs);
1606     }
1607 
1608     @safe unittest
1609     {
1610         import std.range : chain;
1611 
1612         static void test(SysTime sysTime, int expected)
1613         {
1614             assert(sysTime.hour == expected, format("Value given: %s", sysTime));
1615         }
1616 
1617         test(SysTime(0, UTC()), 0);
1618         test(SysTime(1, UTC()), 0);
1619         test(SysTime(-1, UTC()), 23);
1620 
1621         foreach (tz; testTZs)
1622         {
1623             foreach (year; chain(testYearsBC, testYearsAD))
1624             {
1625                 foreach (md; testMonthDays)
1626                 {
1627                     foreach (hour; testHours)
1628                     {
1629                         foreach (minute; testMinSecs)
1630                         {
1631                             foreach (second; testMinSecs)
1632                             {
1633                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1634                                 foreach (fs; testFracSecs)
1635                                     test(SysTime(dt, fs, tz), hour);
1636                             }
1637                         }
1638                     }
1639                 }
1640             }
1641         }
1642 
1643         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1644         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1645         assert(cst.hour == 12);
1646         assert(ist.hour == 12);
1647 
1648         static void testScope(scope ref SysTime st) @safe
1649         {
1650             auto result = st.hour;
1651         }
1652     }
1653 
1654 
1655     /++
1656         Hours past midnight.
1657 
1658         Params:
1659             hour = The hours to set this $(LREF SysTime)'s hour to.
1660 
1661         Throws:
1662             $(REF DateTimeException,std,datetime,date) if the given hour are
1663             not a valid hour of the day.
1664      +/
1665     @property void hour(int hour) @safe scope
1666     {
1667         enforceValid!"hours"(hour);
1668 
1669         auto hnsecs = adjTime;
1670         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1671         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1672         immutable negative = hnsecs < 0;
1673 
1674         if (negative)
1675             hnsecs += convert!("hours", "hnsecs")(24);
1676 
1677         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1678         hnsecs += convert!("hours", "hnsecs")(hour);
1679 
1680         if (negative)
1681             hnsecs -= convert!("hours", "hnsecs")(24);
1682 
1683         adjTime = daysHNSecs + hnsecs;
1684     }
1685 
1686     @safe unittest
1687     {
1688         import std.range : chain;
1689 
1690         foreach (hour; chain(testHours))
1691         {
1692             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1693             {
1694                 auto dt = cast(DateTime) st;
1695                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, hour, dt.minute, dt.second),
1696                                         st.fracSecs,
1697                                         st.timezone);
1698                 st.hour = hour;
1699                 assert(st == expected, format("[%s] [%s]", st, expected));
1700             }
1701         }
1702 
1703         auto st = testSysTimesAD[0];
1704         assertThrown!DateTimeException(st.hour = -1);
1705         assertThrown!DateTimeException(st.hour = 60);
1706 
1707         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1708         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1709         static assert(!__traits(compiles, cst.hour = 27));
1710         static assert(!__traits(compiles, ist.hour = 27));
1711 
1712         static void testScope(scope ref SysTime st) @safe
1713         {
1714             st.hour = 12;
1715         }
1716     }
1717 
1718 
1719     /++
1720         Minutes past the current hour.
1721      +/
1722     @property ubyte minute() @safe const nothrow scope
1723     {
1724         auto hnsecs = adjTime;
1725         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1726 
1727         if (hnsecs < 0)
1728         {
1729             hnsecs += convert!("hours", "hnsecs")(24);
1730             --days;
1731         }
1732 
1733         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1734 
1735         return cast(ubyte) getUnitsFromHNSecs!"minutes"(hnsecs);
1736     }
1737 
1738     @safe unittest
1739     {
1740         import std.range : chain;
1741 
1742         static void test(SysTime sysTime, int expected)
1743         {
1744             assert(sysTime.minute == expected, format("Value given: %s", sysTime));
1745         }
1746 
1747         test(SysTime(0, UTC()), 0);
1748         test(SysTime(1, UTC()), 0);
1749         test(SysTime(-1, UTC()), 59);
1750 
1751         foreach (tz; testTZs)
1752         {
1753             foreach (year; chain(testYearsBC, testYearsAD))
1754             {
1755                 foreach (md; testMonthDays)
1756                 {
1757                     foreach (hour; testHours)
1758                     {
1759                         foreach (minute; testMinSecs)
1760                         {
1761                             foreach (second; testMinSecs)
1762                             {
1763                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1764                                 foreach (fs; testFracSecs)
1765                                     test(SysTime(dt, fs, tz), minute);
1766                             }
1767                         }
1768                     }
1769                 }
1770             }
1771         }
1772 
1773         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1774         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1775         assert(cst.minute == 30);
1776         assert(ist.minute == 30);
1777 
1778         static void testScope(scope ref SysTime st) @safe
1779         {
1780             auto result = st.minute;
1781         }
1782     }
1783 
1784 
1785     /++
1786         Minutes past the current hour.
1787 
1788         Params:
1789             minute = The minute to set this $(LREF SysTime)'s minute to.
1790 
1791         Throws:
1792             $(REF DateTimeException,std,datetime,date) if the given minute are
1793             not a valid minute of an hour.
1794      +/
1795     @property void minute(int minute) @safe scope
1796     {
1797         enforceValid!"minutes"(minute);
1798 
1799         auto hnsecs = adjTime;
1800         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1801         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1802         immutable negative = hnsecs < 0;
1803 
1804         if (negative)
1805             hnsecs += convert!("hours", "hnsecs")(24);
1806 
1807         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
1808         hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs);
1809 
1810         hnsecs += convert!("hours", "hnsecs")(hour);
1811         hnsecs += convert!("minutes", "hnsecs")(minute);
1812 
1813         if (negative)
1814             hnsecs -= convert!("hours", "hnsecs")(24);
1815 
1816         adjTime = daysHNSecs + hnsecs;
1817     }
1818 
1819     @safe unittest
1820     {
1821         import std.range : chain;
1822 
1823         foreach (minute; testMinSecs)
1824         {
1825             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1826             {
1827                 auto dt = cast(DateTime) st;
1828                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, minute, dt.second),
1829                                         st.fracSecs,
1830                                         st.timezone);
1831                 st.minute = minute;
1832                 assert(st == expected, format("[%s] [%s]", st, expected));
1833             }
1834         }
1835 
1836         auto st = testSysTimesAD[0];
1837         assertThrown!DateTimeException(st.minute = -1);
1838         assertThrown!DateTimeException(st.minute = 60);
1839 
1840         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1841         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1842         static assert(!__traits(compiles, cst.minute = 27));
1843         static assert(!__traits(compiles, ist.minute = 27));
1844 
1845         static void testScope(scope ref SysTime st) @safe
1846         {
1847             st.minute = 12;
1848         }
1849     }
1850 
1851 
1852     /++
1853         Seconds past the current minute.
1854      +/
1855     @property ubyte second() @safe const nothrow scope
1856     {
1857         auto hnsecs = adjTime;
1858         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1859 
1860         if (hnsecs < 0)
1861         {
1862             hnsecs += convert!("hours", "hnsecs")(24);
1863             --days;
1864         }
1865 
1866         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1867         hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs);
1868 
1869         return cast(ubyte) getUnitsFromHNSecs!"seconds"(hnsecs);
1870     }
1871 
1872     @safe unittest
1873     {
1874         import std.range : chain;
1875 
1876         static void test(SysTime sysTime, int expected)
1877         {
1878             assert(sysTime.second == expected, format("Value given: %s", sysTime));
1879         }
1880 
1881         test(SysTime(0, UTC()), 0);
1882         test(SysTime(1, UTC()), 0);
1883         test(SysTime(-1, UTC()), 59);
1884 
1885         foreach (tz; testTZs)
1886         {
1887             foreach (year; chain(testYearsBC, testYearsAD))
1888             {
1889                 foreach (md; testMonthDays)
1890                 {
1891                     foreach (hour; testHours)
1892                     {
1893                         foreach (minute; testMinSecs)
1894                         {
1895                             foreach (second; testMinSecs)
1896                             {
1897                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1898                                 foreach (fs; testFracSecs)
1899                                     test(SysTime(dt, fs, tz), second);
1900                             }
1901                         }
1902                     }
1903                 }
1904             }
1905         }
1906 
1907         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1908         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1909         assert(cst.second == 33);
1910         assert(ist.second == 33);
1911 
1912         static void testScope(scope ref SysTime st) @safe
1913         {
1914             auto result = st.second;
1915         }
1916     }
1917 
1918 
1919     /++
1920         Seconds past the current minute.
1921 
1922         Params:
1923             second = The second to set this $(LREF SysTime)'s second to.
1924 
1925         Throws:
1926             $(REF DateTimeException,std,datetime,date) if the given second are
1927             not a valid second of a minute.
1928      +/
1929     @property void second(int second) @safe scope
1930     {
1931         enforceValid!"seconds"(second);
1932 
1933         auto hnsecs = adjTime;
1934         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1935         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1936         immutable negative = hnsecs < 0;
1937 
1938         if (negative)
1939             hnsecs += convert!("hours", "hnsecs")(24);
1940 
1941         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
1942         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
1943         hnsecs = removeUnitsFromHNSecs!"seconds"(hnsecs);
1944 
1945         hnsecs += convert!("hours", "hnsecs")(hour);
1946         hnsecs += convert!("minutes", "hnsecs")(minute);
1947         hnsecs += convert!("seconds", "hnsecs")(second);
1948 
1949         if (negative)
1950             hnsecs -= convert!("hours", "hnsecs")(24);
1951 
1952         adjTime = daysHNSecs + hnsecs;
1953     }
1954 
1955     @safe unittest
1956     {
1957         import std.range : chain;
1958 
1959         foreach (second; testMinSecs)
1960         {
1961             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1962             {
1963                 auto dt = cast(DateTime) st;
1964                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, second),
1965                                         st.fracSecs,
1966                                         st.timezone);
1967                 st.second = second;
1968                 assert(st == expected, format("[%s] [%s]", st, expected));
1969             }
1970         }
1971 
1972         auto st = testSysTimesAD[0];
1973         assertThrown!DateTimeException(st.second = -1);
1974         assertThrown!DateTimeException(st.second = 60);
1975 
1976         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1977         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1978         static assert(!__traits(compiles, cst.seconds = 27));
1979         static assert(!__traits(compiles, ist.seconds = 27));
1980 
1981         static void testScope(scope ref SysTime st) @safe
1982         {
1983             st.second = 12;
1984         }
1985     }
1986 
1987 
1988     /++
1989         Fractional seconds past the second (i.e. the portion of a
1990         $(LREF SysTime) which is less than a second).
1991      +/
1992     @property Duration fracSecs() @safe const nothrow scope
1993     {
1994         auto hnsecs = removeUnitsFromHNSecs!"days"(adjTime);
1995 
1996         if (hnsecs < 0)
1997             hnsecs += convert!("hours", "hnsecs")(24);
1998 
1999         return dur!"hnsecs"(removeUnitsFromHNSecs!"seconds"(hnsecs));
2000     }
2001 
2002     ///
2003     @safe unittest
2004     {
2005         import core.time : msecs, usecs, hnsecs, nsecs;
2006         import std.datetime.date : DateTime;
2007 
2008         auto dt = DateTime(1982, 4, 1, 20, 59, 22);
2009         assert(SysTime(dt, msecs(213)).fracSecs == msecs(213));
2010         assert(SysTime(dt, usecs(5202)).fracSecs == usecs(5202));
2011         assert(SysTime(dt, hnsecs(1234567)).fracSecs == hnsecs(1234567));
2012 
2013         // SysTime and Duration both have a precision of hnsecs (100 ns),
2014         // so nsecs are going to be truncated.
2015         assert(SysTime(dt, nsecs(123456789)).fracSecs == nsecs(123456700));
2016     }
2017 
2018     @safe unittest
2019     {
2020         import std.range : chain;
2021         import core.time;
2022 
2023         assert(SysTime(0, UTC()).fracSecs == Duration.zero);
2024         assert(SysTime(1, UTC()).fracSecs == hnsecs(1));
2025         assert(SysTime(-1, UTC()).fracSecs == hnsecs(9_999_999));
2026 
2027         foreach (tz; testTZs)
2028         {
2029             foreach (year; chain(testYearsBC, testYearsAD))
2030             {
2031                 foreach (md; testMonthDays)
2032                 {
2033                     foreach (hour; testHours)
2034                     {
2035                         foreach (minute; testMinSecs)
2036                         {
2037                             foreach (second; testMinSecs)
2038                             {
2039                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
2040                                 foreach (fs; testFracSecs)
2041                                     assert(SysTime(dt, fs, tz).fracSecs == fs);
2042                             }
2043                         }
2044                     }
2045                 }
2046             }
2047         }
2048 
2049         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2050         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2051         assert(cst.fracSecs == Duration.zero);
2052         assert(ist.fracSecs == Duration.zero);
2053 
2054         static void testScope(scope ref SysTime st) @safe
2055         {
2056             auto result = st.fracSecs;
2057         }
2058     }
2059 
2060 
2061     /++
2062         Fractional seconds past the second (i.e. the portion of a
2063         $(LREF SysTime) which is less than a second).
2064 
2065         Params:
2066             fracSecs = The duration to set this $(LREF SysTime)'s fractional
2067                        seconds to.
2068 
2069         Throws:
2070             $(REF DateTimeException,std,datetime,date) if the given duration
2071             is negative or if it's greater than or equal to one second.
2072      +/
2073     @property void fracSecs(Duration fracSecs) @safe scope
2074     {
2075         enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
2076         enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
2077 
2078         auto oldHNSecs = adjTime;
2079         auto days = splitUnitsFromHNSecs!"days"(oldHNSecs);
2080         immutable daysHNSecs = convert!("days", "hnsecs")(days);
2081         immutable negative = oldHNSecs < 0;
2082 
2083         if (negative)
2084             oldHNSecs += convert!("hours", "hnsecs")(24);
2085 
2086         immutable seconds = splitUnitsFromHNSecs!"seconds"(oldHNSecs);
2087         immutable secondsHNSecs = convert!("seconds", "hnsecs")(seconds);
2088         auto newHNSecs = fracSecs.total!"hnsecs" + secondsHNSecs;
2089 
2090         if (negative)
2091             newHNSecs -= convert!("hours", "hnsecs")(24);
2092 
2093         adjTime = daysHNSecs + newHNSecs;
2094     }
2095 
2096     ///
2097     @safe unittest
2098     {
2099         import core.time : Duration, msecs, hnsecs, nsecs;
2100         import std.datetime.date : DateTime;
2101 
2102         auto st = SysTime(DateTime(1982, 4, 1, 20, 59, 22));
2103         assert(st.fracSecs == Duration.zero);
2104 
2105         st.fracSecs = msecs(213);
2106         assert(st.fracSecs == msecs(213));
2107 
2108         st.fracSecs = hnsecs(1234567);
2109         assert(st.fracSecs == hnsecs(1234567));
2110 
2111         // SysTime has a precision of hnsecs (100 ns), so nsecs are
2112         // going to be truncated.
2113         st.fracSecs = nsecs(123456789);
2114         assert(st.fracSecs == hnsecs(1234567));
2115     }
2116 
2117     @safe unittest
2118     {
2119         import std.range : chain;
2120         import core.time;
2121 
2122         foreach (fracSec; testFracSecs)
2123         {
2124             foreach (st; chain(testSysTimesBC, testSysTimesAD))
2125             {
2126                 auto dt = cast(DateTime) st;
2127                 auto expected = SysTime(dt, fracSec, st.timezone);
2128                 st.fracSecs = fracSec;
2129                 assert(st == expected, format("[%s] [%s]", st, expected));
2130             }
2131         }
2132 
2133         auto st = testSysTimesAD[0];
2134         assertThrown!DateTimeException(st.fracSecs = hnsecs(-1));
2135         assertThrown!DateTimeException(st.fracSecs = seconds(1));
2136 
2137         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2138         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2139         static assert(!__traits(compiles, cst.fracSecs = msecs(7)));
2140         static assert(!__traits(compiles, ist.fracSecs = msecs(7)));
2141 
2142         static void testScope(scope ref SysTime st) @safe
2143         {
2144             st.fracSecs = Duration.zero;
2145         }
2146     }
2147 
2148 
2149     /++
2150         The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the
2151         internal representation of $(LREF SysTime).
2152      +/
2153     @property long stdTime() @safe const pure nothrow scope @nogc
2154     {
2155         return _stdTime;
2156     }
2157 
2158     @safe unittest
2159     {
2160         import core.time;
2161         assert(SysTime(0).stdTime == 0);
2162         assert(SysTime(1).stdTime == 1);
2163         assert(SysTime(-1).stdTime == -1);
2164         assert(SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC()).stdTime == 330_000_502L);
2165         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC()).stdTime == 621_355_968_000_000_000L);
2166 
2167         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2168         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2169         assert(cst.stdTime > 0);
2170         assert(ist.stdTime > 0);
2171 
2172         static void testScope(scope ref SysTime st) @safe
2173         {
2174             auto result = st.stdTime;
2175         }
2176     }
2177 
2178 
2179     /++
2180         The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the
2181         internal representation of $(LREF SysTime).
2182 
2183         Params:
2184             stdTime = The number of hnsecs since January 1st, 1 A.D. UTC.
2185      +/
2186     @property void stdTime(long stdTime) @safe pure nothrow scope
2187     {
2188         _stdTime = stdTime;
2189     }
2190 
2191     @safe unittest
2192     {
2193         import core.time;
2194         static void test(long stdTime, SysTime expected, size_t line = __LINE__)
2195         {
2196             auto st = SysTime(0, UTC());
2197             st.stdTime = stdTime;
2198             assert(st == expected);
2199         }
2200 
2201         test(0, SysTime(Date(1, 1, 1), UTC()));
2202         test(1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()));
2203         test(-1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()));
2204         test(330_000_502L, SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC()));
2205         test(621_355_968_000_000_000L, SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC()));
2206 
2207         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2208         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2209         static assert(!__traits(compiles, cst.stdTime = 27));
2210         static assert(!__traits(compiles, ist.stdTime = 27));
2211 
2212         static void testScope(scope ref SysTime st) @safe
2213         {
2214             st.stdTime = 42;
2215         }
2216     }
2217 
2218 
2219     /++
2220         The current time zone of this $(LREF SysTime). Its internal time is
2221         always kept in UTC, so there are no conversion issues between time zones
2222         due to DST. Functions which return all or part of the time - such as
2223         hours - adjust the time to this $(LREF SysTime)'s time zone before
2224         returning.
2225       +/
2226     @property immutable(TimeZone) timezone() @safe const pure nothrow return scope
2227     {
2228         return _timezone;
2229     }
2230 
2231     @safe unittest
2232     {
2233         assert(SysTime.init.timezone is InitTimeZone());
2234         assert(SysTime(DateTime.init, UTC()).timezone is UTC());
2235 
2236         static void testScope(scope ref SysTime st) @safe
2237         {
2238             auto result = st.timezone;
2239         }
2240     }
2241 
2242 
2243     /++
2244         The current time zone of this $(LREF SysTime). It's internal time is
2245         always kept in UTC, so there are no conversion issues between time zones
2246         due to DST. Functions which return all or part of the time - such as
2247         hours - adjust the time to this $(LREF SysTime)'s time zone before
2248         returning.
2249 
2250         Params:
2251             timezone = The $(REF _TimeZone,std,datetime,_timezone) to set this
2252                        $(LREF SysTime)'s time zone to.
2253       +/
2254     @property void timezone(immutable TimeZone timezone) @safe pure nothrow scope
2255     {
2256         if (timezone is null)
2257             _timezone = LocalTime();
2258         else
2259             _timezone = timezone;
2260     }
2261 
2262     @safe unittest
2263     {
2264         SysTime st;
2265         st.timezone = null;
2266         assert(st.timezone is LocalTime());
2267         st.timezone = UTC();
2268         assert(st.timezone is UTC());
2269 
2270         static void testScope(scope ref SysTime st) @safe
2271         {
2272             st.timezone = UTC();
2273         }
2274     }
2275 
2276 
2277     /++
2278         Returns whether DST is in effect for this $(LREF SysTime).
2279       +/
2280     @property bool dstInEffect() @safe const nothrow return scope
2281     {
2282         return _timezone.dstInEffect(_stdTime);
2283     }
2284 
2285     // This function's full unit testing is done in the time zone classes, but
2286     // this verifies that SysTime.init works correctly, since historically, it
2287     // has segfaulted due to a null _timezone.
2288     @safe unittest
2289     {
2290         assert(!SysTime.init.dstInEffect);
2291 
2292         static void testScope(scope ref SysTime st) @safe
2293         {
2294             auto result = st.dstInEffect;
2295         }
2296     }
2297 
2298 
2299     /++
2300         Returns what the offset from UTC is for this $(LREF SysTime).
2301         It includes the DST offset in effect at that time (if any).
2302       +/
2303     @property Duration utcOffset() @safe const nothrow return scope
2304     {
2305         return _timezone.utcOffsetAt(_stdTime);
2306     }
2307 
2308     // This function's full unit testing is done in the time zone classes, but
2309     // this verifies that SysTime.init works correctly, since historically, it
2310     // has segfaulted due to a null _timezone.
2311     @safe unittest
2312     {
2313         assert(SysTime.init.utcOffset == Duration.zero);
2314 
2315         static void testScope(scope ref SysTime st) @safe
2316         {
2317             auto result = st.utcOffset;
2318         }
2319     }
2320 
2321 
2322     /++
2323         Returns a $(LREF SysTime) with the same std time as this one, but with
2324         $(REF LocalTime,std,datetime,timezone) as its time zone.
2325       +/
2326     SysTime toLocalTime() @safe const pure nothrow scope
2327     {
2328         return SysTime(_stdTime, LocalTime());
2329     }
2330 
2331     @safe unittest
2332     {
2333         import core.time;
2334         {
2335             auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2336             assert(sysTime == sysTime.toLocalTime());
2337             assert(sysTime._stdTime == sysTime.toLocalTime()._stdTime);
2338             assert(sysTime.toLocalTime().timezone is LocalTime());
2339             assert(sysTime.toLocalTime().timezone is sysTime.timezone);
2340             assert(sysTime.toLocalTime().timezone !is UTC());
2341         }
2342 
2343         {
2344             auto stz = new immutable SimpleTimeZone(dur!"minutes"(-3 * 60));
2345             auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27), stz);
2346             assert(sysTime == sysTime.toLocalTime());
2347             assert(sysTime._stdTime == sysTime.toLocalTime()._stdTime);
2348             assert(sysTime.toLocalTime().timezone is LocalTime());
2349             assert(sysTime.toLocalTime().timezone !is UTC());
2350             assert(sysTime.toLocalTime().timezone !is stz);
2351         }
2352 
2353         static void testScope(scope ref SysTime st) @safe
2354         {
2355             auto result = st.toLocalTime();
2356         }
2357     }
2358 
2359 
2360     /++
2361         Returns a $(LREF SysTime) with the same std time as this one, but with
2362         `UTC` as its time zone.
2363       +/
2364     SysTime toUTC() @safe const pure nothrow scope
2365     {
2366         return SysTime(_stdTime, UTC());
2367     }
2368 
2369     @safe unittest
2370     {
2371         import core.time;
2372         auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2373         assert(sysTime == sysTime.toUTC());
2374         assert(sysTime._stdTime == sysTime.toUTC()._stdTime);
2375         assert(sysTime.toUTC().timezone is UTC());
2376         assert(sysTime.toUTC().timezone !is LocalTime());
2377         assert(sysTime.toUTC().timezone !is sysTime.timezone);
2378 
2379         static void testScope(scope ref SysTime st) @safe
2380         {
2381             auto result = st.toUTC();
2382         }
2383     }
2384 
2385 
2386     /++
2387         Returns a $(LREF SysTime) with the same std time as this one, but with
2388         given time zone as its time zone.
2389       +/
2390     SysTime toOtherTZ(immutable TimeZone tz) @safe const pure nothrow scope
2391     {
2392         if (tz is null)
2393             return SysTime(_stdTime, LocalTime());
2394         else
2395             return SysTime(_stdTime, tz);
2396     }
2397 
2398     @safe unittest
2399     {
2400         import core.time;
2401         auto stz = new immutable SimpleTimeZone(dur!"minutes"(11 * 60));
2402         auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2403         assert(sysTime == sysTime.toOtherTZ(stz));
2404         assert(sysTime._stdTime == sysTime.toOtherTZ(stz)._stdTime);
2405         assert(sysTime.toOtherTZ(stz).timezone is stz);
2406         assert(sysTime.toOtherTZ(stz).timezone !is LocalTime());
2407         assert(sysTime.toOtherTZ(stz).timezone !is UTC());
2408         assert(sysTime.toOtherTZ(null).timezone is LocalTime());
2409 
2410         static void testScope(scope ref SysTime st) @safe
2411         {
2412             auto result = st.toOtherTZ(null);
2413         }
2414     }
2415 
2416 
2417     /++
2418         Converts this $(LREF SysTime) to unix time (i.e. seconds from midnight,
2419         January 1st, 1970 in UTC).
2420 
2421         The C standard does not specify the representation of time_t, so it is
2422         implementation defined. On POSIX systems, unix time is equivalent to
2423         time_t, but that's not necessarily true on other systems (e.g. it is
2424         not true for the Digital Mars C runtime). So, be careful when using unix
2425         time with C functions on non-POSIX systems.
2426 
2427         By default, the return type is time_t (which is normally an alias for
2428         int on 32-bit systems and long on 64-bit systems), but if a different
2429         size is required than either int or long can be passed as a template
2430         argument to get the desired size.
2431 
2432         If the return type is int, and the result can't fit in an int, then the
2433         closest value that can be held in 32 bits will be used (so `int.max`
2434         if it goes over and `int.min` if it goes under). However, no attempt
2435         is made to deal with integer overflow if the return type is long.
2436 
2437         Params:
2438             T = The return type (int or long). It defaults to time_t, which is
2439                 normally 32 bits on a 32-bit system and 64 bits on a 64-bit
2440                 system.
2441 
2442         Returns:
2443             A signed integer representing the unix time which is equivalent to
2444             this SysTime.
2445       +/
2446     T toUnixTime(T = time_t)() @safe const pure nothrow scope
2447     if (is(T == int) || is(T == long))
2448     {
2449         return stdTimeToUnixTime!T(_stdTime);
2450     }
2451 
2452     ///
2453     @safe unittest
2454     {
2455         import core.time : hours;
2456         import std.datetime.date : DateTime;
2457         import std.datetime.timezone : SimpleTimeZone, UTC;
2458 
2459         assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0);
2460 
2461         auto pst = new immutable SimpleTimeZone(hours(-8));
2462         assert(SysTime(DateTime(1970, 1, 1), pst).toUnixTime() == 28800);
2463 
2464         auto utc = SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC());
2465         assert(utc.toUnixTime() == 1_198_311_285);
2466 
2467         auto ca = SysTime(DateTime(2007, 12, 22, 8, 14, 45), pst);
2468         assert(ca.toUnixTime() == 1_198_340_085);
2469 
2470         static void testScope(scope ref SysTime st) @safe
2471         {
2472             auto result = st.toUnixTime();
2473         }
2474     }
2475 
2476     @safe unittest
2477     {
2478         import std.meta : AliasSeq;
2479         import core.time;
2480         assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0);
2481         static foreach (units; ["hnsecs", "usecs", "msecs"])
2482             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), dur!units(1), UTC()).toUnixTime() == 0);
2483         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toUnixTime() == 1);
2484         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toUnixTime() == 0);
2485         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toUnixTime() == 0);
2486         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toUnixTime() == 0);
2487         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toUnixTime() == -1);
2488     }
2489 
2490 
2491     /++
2492         Converts from unix time (i.e. seconds from midnight, January 1st, 1970
2493         in UTC) to a $(LREF SysTime).
2494 
2495         The C standard does not specify the representation of time_t, so it is
2496         implementation defined. On POSIX systems, unix time is equivalent to
2497         time_t, but that's not necessarily true on other systems (e.g. it is
2498         not true for the Digital Mars C runtime). So, be careful when using unix
2499         time with C functions on non-POSIX systems.
2500 
2501         Params:
2502             unixTime = Seconds from midnight, January 1st, 1970 in UTC.
2503             tz = The time zone for the SysTime that's returned.
2504       +/
2505     static SysTime fromUnixTime(long unixTime, immutable TimeZone tz = LocalTime()) @safe pure nothrow
2506     {
2507         return SysTime(unixTimeToStdTime(unixTime), tz);
2508     }
2509 
2510     ///
2511     @safe unittest
2512     {
2513         import core.time : hours;
2514         import std.datetime.date : DateTime;
2515         import std.datetime.timezone : SimpleTimeZone, UTC;
2516 
2517         assert(SysTime.fromUnixTime(0) ==
2518                SysTime(DateTime(1970, 1, 1), UTC()));
2519 
2520         auto pst = new immutable SimpleTimeZone(hours(-8));
2521         assert(SysTime.fromUnixTime(28800) ==
2522                SysTime(DateTime(1970, 1, 1), pst));
2523 
2524         auto st1 = SysTime.fromUnixTime(1_198_311_285, UTC());
2525         assert(st1 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC()));
2526         assert(st1.timezone is UTC());
2527         assert(st1 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst));
2528 
2529         auto st2 = SysTime.fromUnixTime(1_198_311_285, pst);
2530         assert(st2 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC()));
2531         assert(st2.timezone is pst);
2532         assert(st2 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst));
2533     }
2534 
2535     @safe unittest
2536     {
2537         import core.time;
2538         assert(SysTime.fromUnixTime(0) == SysTime(DateTime(1970, 1, 1), UTC()));
2539         assert(SysTime.fromUnixTime(1) == SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()));
2540         assert(SysTime.fromUnixTime(-1) == SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()));
2541 
2542         auto st = SysTime.fromUnixTime(0);
2543         auto dt = cast(DateTime) st;
2544         assert(dt <= DateTime(1970, 2, 1) && dt >= DateTime(1969, 12, 31));
2545         assert(st.timezone is LocalTime());
2546 
2547         auto aest = new immutable SimpleTimeZone(hours(10));
2548         assert(SysTime.fromUnixTime(-36000) == SysTime(DateTime(1970, 1, 1), aest));
2549     }
2550 
2551 
2552     /++
2553         Returns a `timeval` which represents this $(LREF SysTime).
2554 
2555         Note that like all conversions in std.datetime, this is a truncating
2556         conversion.
2557 
2558         If `timeval.tv_sec` is int, and the result can't fit in an int, then
2559         the closest value that can be held in 32 bits will be used for
2560         `tv_sec`. (so `int.max` if it goes over and `int.min` if it
2561         goes under).
2562       +/
2563     timeval toTimeVal() @safe const pure nothrow scope
2564     {
2565         immutable tv_sec = toUnixTime!(typeof(timeval.tv_sec))();
2566         immutable fracHNSecs = removeUnitsFromHNSecs!"seconds"(_stdTime - 621_355_968_000_000_000L);
2567         immutable tv_usec = cast(typeof(timeval.tv_usec))convert!("hnsecs", "usecs")(fracHNSecs);
2568         return timeval(tv_sec, tv_usec);
2569     }
2570 
2571     @safe unittest
2572     {
2573         import core.time;
2574         assert(SysTime(DateTime(1970, 1, 1), UTC()).toTimeVal() == timeval(0, 0));
2575         assert(SysTime(DateTime(1970, 1, 1), hnsecs(9), UTC()).toTimeVal() == timeval(0, 0));
2576         assert(SysTime(DateTime(1970, 1, 1), hnsecs(10), UTC()).toTimeVal() == timeval(0, 1));
2577         assert(SysTime(DateTime(1970, 1, 1), usecs(7), UTC()).toTimeVal() == timeval(0, 7));
2578 
2579         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toTimeVal() == timeval(1, 0));
2580         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(9), UTC()).toTimeVal() == timeval(1, 0));
2581         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(10), UTC()).toTimeVal() == timeval(1, 1));
2582         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), usecs(7), UTC()).toTimeVal() == timeval(1, 7));
2583 
2584         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toTimeVal() == timeval(0, 0));
2585         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_990), UTC()).toTimeVal() == timeval(0, -1));
2586 
2587         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toTimeVal() == timeval(0, -1));
2588         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999), UTC()).toTimeVal() == timeval(0, -999_001));
2589         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toTimeVal() == timeval(0, -1000));
2590         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toTimeVal() == timeval(-1, 0));
2591         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 58), usecs(17), UTC()).toTimeVal() == timeval(-1, -999_983));
2592 
2593         static void testScope(scope ref SysTime st) @safe
2594         {
2595             auto result = st.toTimeVal();
2596         }
2597     }
2598 
2599 
2600     version (StdDdoc)
2601     {
2602         version (Windows) private struct timespec {}
2603         /++
2604             Returns a `timespec` which represents this $(LREF SysTime).
2605 
2606             $(BLUE This function is Posix-Only.)
2607           +/
2608         timespec toTimeSpec() @safe const pure nothrow scope;
2609     }
2610     else version (Posix)
2611     {
2612         timespec toTimeSpec() @safe const pure nothrow scope
2613         {
2614             immutable tv_sec = toUnixTime!(typeof(timespec.tv_sec))();
2615             immutable fracHNSecs = removeUnitsFromHNSecs!"seconds"(_stdTime - 621_355_968_000_000_000L);
2616             immutable tv_nsec = cast(typeof(timespec.tv_nsec))convert!("hnsecs", "nsecs")(fracHNSecs);
2617             return timespec(tv_sec, tv_nsec);
2618         }
2619 
2620         @safe unittest
2621         {
2622             import core.time;
2623             assert(SysTime(DateTime(1970, 1, 1), UTC()).toTimeSpec() == timespec(0, 0));
2624             assert(SysTime(DateTime(1970, 1, 1), hnsecs(9), UTC()).toTimeSpec() == timespec(0, 900));
2625             assert(SysTime(DateTime(1970, 1, 1), hnsecs(10), UTC()).toTimeSpec() == timespec(0, 1000));
2626             assert(SysTime(DateTime(1970, 1, 1), usecs(7), UTC()).toTimeSpec() == timespec(0, 7000));
2627 
2628             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toTimeSpec() == timespec(1, 0));
2629             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(9), UTC()).toTimeSpec() == timespec(1, 900));
2630             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(10), UTC()).toTimeSpec() == timespec(1, 1000));
2631             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), usecs(7), UTC()).toTimeSpec() == timespec(1, 7000));
2632 
2633             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toTimeSpec() ==
2634                    timespec(0, -100));
2635             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_990), UTC()).toTimeSpec() ==
2636                    timespec(0, -1000));
2637 
2638             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toTimeSpec() ==
2639                    timespec(0, -1_000));
2640             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999), UTC()).toTimeSpec() ==
2641                    timespec(0, -999_001_000));
2642             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toTimeSpec() ==
2643                    timespec(0, -1_000_000));
2644             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toTimeSpec() ==
2645                    timespec(-1, 0));
2646             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 58), usecs(17), UTC()).toTimeSpec() ==
2647                    timespec(-1, -999_983_000));
2648 
2649             static void testScope(scope ref SysTime st) @safe
2650             {
2651                 auto result = st.toTimeSpec();
2652             }
2653         }
2654     }
2655 
2656     /++
2657         Returns a `tm` which represents this $(LREF SysTime).
2658       +/
2659     tm toTM() @safe const nothrow scope
2660     {
2661         auto dateTime = cast(DateTime) this;
2662         tm timeInfo;
2663 
2664         timeInfo.tm_sec = dateTime.second;
2665         timeInfo.tm_min = dateTime.minute;
2666         timeInfo.tm_hour = dateTime.hour;
2667         timeInfo.tm_mday = dateTime.day;
2668         timeInfo.tm_mon = dateTime.month - 1;
2669         timeInfo.tm_year = dateTime.year - 1900;
2670         timeInfo.tm_wday = dateTime.dayOfWeek;
2671         timeInfo.tm_yday = dateTime.dayOfYear - 1;
2672         timeInfo.tm_isdst = _timezone.dstInEffect(_stdTime);
2673 
2674         version (Posix)
2675         {
2676             import std.utf : toUTFz;
2677             timeInfo.tm_gmtoff = cast(int) convert!("hnsecs", "seconds")(adjTime - _stdTime);
2678             auto zone = timeInfo.tm_isdst ? _timezone.dstName : _timezone.stdName;
2679             timeInfo.tm_zone = zone.toUTFz!(char*)();
2680         }
2681 
2682         return timeInfo;
2683     }
2684 
2685     @system unittest
2686     {
2687         import std.conv : to;
2688         import core.time;
2689 
2690         version (Posix)
2691         {
2692             import std.datetime.timezone : clearTZEnvVar, setTZEnvVar;
2693             setTZEnvVar("America/Los_Angeles");
2694             scope(exit) clearTZEnvVar();
2695         }
2696 
2697         {
2698             auto timeInfo = SysTime(DateTime(1970, 1, 1)).toTM();
2699 
2700             assert(timeInfo.tm_sec == 0);
2701             assert(timeInfo.tm_min == 0);
2702             assert(timeInfo.tm_hour == 0);
2703             assert(timeInfo.tm_mday == 1);
2704             assert(timeInfo.tm_mon == 0);
2705             assert(timeInfo.tm_year == 70);
2706             assert(timeInfo.tm_wday == 4);
2707             assert(timeInfo.tm_yday == 0);
2708 
2709             version (Posix)
2710                 assert(timeInfo.tm_isdst == 0);
2711             else version (Windows)
2712                 assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
2713 
2714             version (Posix)
2715             {
2716                 assert(timeInfo.tm_gmtoff == -8 * 60 * 60);
2717                 assert(to!string(timeInfo.tm_zone) == "PST");
2718             }
2719         }
2720 
2721         {
2722             auto timeInfo = SysTime(DateTime(2010, 7, 4, 12, 15, 7), hnsecs(15)).toTM();
2723 
2724             assert(timeInfo.tm_sec == 7);
2725             assert(timeInfo.tm_min == 15);
2726             assert(timeInfo.tm_hour == 12);
2727             assert(timeInfo.tm_mday == 4);
2728             assert(timeInfo.tm_mon == 6);
2729             assert(timeInfo.tm_year == 110);
2730             assert(timeInfo.tm_wday == 0);
2731             assert(timeInfo.tm_yday == 184);
2732 
2733             version (Posix)
2734                 assert(timeInfo.tm_isdst == 1);
2735             else version (Windows)
2736                 assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
2737 
2738             version (Posix)
2739             {
2740                 assert(timeInfo.tm_gmtoff == -7 * 60 * 60);
2741                 assert(to!string(timeInfo.tm_zone) == "PDT");
2742             }
2743         }
2744 
2745         // This is more to verify that SysTime.init.toTM() doesn't segfault and
2746         // does something sane rather than that the value is anything
2747         // particularly useful.
2748         {
2749             auto timeInfo = SysTime.init.toTM();
2750 
2751             assert(timeInfo.tm_sec == 0);
2752             assert(timeInfo.tm_min == 0);
2753             assert(timeInfo.tm_hour == 0);
2754             assert(timeInfo.tm_mday == 1);
2755             assert(timeInfo.tm_mon == 0);
2756             assert(timeInfo.tm_year == -1899);
2757             assert(timeInfo.tm_wday == 1);
2758             assert(timeInfo.tm_yday == 0);
2759             assert(timeInfo.tm_isdst == 0);
2760 
2761             version (Posix)
2762             {
2763                 assert(timeInfo.tm_gmtoff == 0);
2764                 assert(to!string(timeInfo.tm_zone) == "SysTime.init's timezone");
2765             }
2766         }
2767 
2768         static void testScope(scope ref SysTime st) @safe
2769         {
2770             auto result = st.toTM();
2771         }
2772     }
2773 
2774 
2775     /++
2776         Adds the given number of years or months to this $(LREF SysTime). A
2777         negative number will subtract.
2778 
2779         Note that if day overflow is allowed, and the date with the adjusted
2780         year/month overflows the number of days in the new month, then the month
2781         will be incremented by one, and the day set to the number of days
2782         overflowed. (e.g. if the day were 31 and the new month were June, then
2783         the month would be incremented to July, and the new day would be 1). If
2784         day overflow is not allowed, then the day will be set to the last valid
2785         day in the month (e.g. June 31st would become June 30th).
2786 
2787         Params:
2788             units         = The type of units to add ("years" or "months").
2789             value         = The number of months or years to add to this
2790                             $(LREF SysTime).
2791             allowOverflow = Whether the days should be allowed to overflow,
2792                             causing the month to increment.
2793       +/
2794     ref SysTime add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow scope
2795     if (units == "years" || units == "months")
2796     {
2797         auto hnsecs = adjTime;
2798         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
2799 
2800         if (hnsecs < 0)
2801         {
2802             hnsecs += convert!("hours", "hnsecs")(24);
2803             --days;
2804         }
2805 
2806         auto date = Date(cast(int) days);
2807         date.add!units(value, allowOverflow);
2808         days = date.dayOfGregorianCal - 1;
2809 
2810         if (days < 0)
2811         {
2812             hnsecs -= convert!("hours", "hnsecs")(24);
2813             ++days;
2814         }
2815 
2816         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
2817 
2818         adjTime = newDaysHNSecs + hnsecs;
2819 
2820         return this;
2821     }
2822 
2823     @safe unittest
2824     {
2825         auto st1 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
2826         st1.add!"months"(11);
2827         assert(st1 == SysTime(DateTime(2010, 12, 1, 12, 30, 33)));
2828 
2829         auto st2 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
2830         st2.add!"months"(-11);
2831         assert(st2 == SysTime(DateTime(2009, 2, 1, 12, 30, 33)));
2832 
2833         auto st3 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
2834         st3.add!"years"(1);
2835         assert(st3 == SysTime(DateTime(2001, 3, 1, 12, 30, 33)));
2836 
2837         auto st4 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
2838         st4.add!"years"(1, AllowDayOverflow.no);
2839         assert(st4 == SysTime(DateTime(2001, 2, 28, 12, 30, 33)));
2840     }
2841 
2842     // Test add!"years"() with AllowDayOverflow.yes
2843     @safe unittest
2844     {
2845         import core.time;
2846         // Test A.D.
2847         {
2848             auto sysTime = SysTime(Date(1999, 7, 6));
2849             sysTime.add!"years"(7);
2850             assert(sysTime == SysTime(Date(2006, 7, 6)));
2851             sysTime.add!"years"(-9);
2852             assert(sysTime == SysTime(Date(1997, 7, 6)));
2853         }
2854 
2855         {
2856             auto sysTime = SysTime(Date(1999, 2, 28));
2857             sysTime.add!"years"(1);
2858             assert(sysTime == SysTime(Date(2000, 2, 28)));
2859         }
2860 
2861         {
2862             auto sysTime = SysTime(Date(2000, 2, 29));
2863             sysTime.add!"years"(-1);
2864             assert(sysTime == SysTime(Date(1999, 3, 1)));
2865         }
2866 
2867         {
2868             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234));
2869             sysTime.add!"years"(7);
2870             assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234)));
2871             sysTime.add!"years"(-9);
2872             assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234)));
2873         }
2874 
2875         {
2876             auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207));
2877             sysTime.add!"years"(1);
2878             assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207)));
2879         }
2880 
2881         {
2882             auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207));
2883             sysTime.add!"years"(-1);
2884             assert(sysTime == SysTime(DateTime(1999, 3, 1, 0, 7, 2), usecs(1207)));
2885         }
2886 
2887         // Test B.C.
2888         {
2889             auto sysTime = SysTime(Date(-1999, 7, 6));
2890             sysTime.add!"years"(-7);
2891             assert(sysTime == SysTime(Date(-2006, 7, 6)));
2892             sysTime.add!"years"(9);
2893             assert(sysTime == SysTime(Date(-1997, 7, 6)));
2894         }
2895 
2896         {
2897             auto sysTime = SysTime(Date(-1999, 2, 28));
2898             sysTime.add!"years"(-1);
2899             assert(sysTime == SysTime(Date(-2000, 2, 28)));
2900         }
2901 
2902         {
2903             auto sysTime = SysTime(Date(-2000, 2, 29));
2904             sysTime.add!"years"(1);
2905             assert(sysTime == SysTime(Date(-1999, 3, 1)));
2906         }
2907 
2908         {
2909             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234));
2910             sysTime.add!"years"(-7);
2911             assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234)));
2912             sysTime.add!"years"(9);
2913             assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234)));
2914         }
2915 
2916         {
2917             auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3));
2918             sysTime.add!"years"(-1);
2919             assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3)));
2920         }
2921 
2922         {
2923             auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3));
2924             sysTime.add!"years"(1);
2925             assert(sysTime == SysTime(DateTime(-1999, 3, 1, 3, 3, 3), hnsecs(3)));
2926         }
2927 
2928         // Test Both
2929         {
2930             auto sysTime = SysTime(Date(4, 7, 6));
2931             sysTime.add!"years"(-5);
2932             assert(sysTime == SysTime(Date(-1, 7, 6)));
2933             sysTime.add!"years"(5);
2934             assert(sysTime == SysTime(Date(4, 7, 6)));
2935         }
2936 
2937         {
2938             auto sysTime = SysTime(Date(-4, 7, 6));
2939             sysTime.add!"years"(5);
2940             assert(sysTime == SysTime(Date(1, 7, 6)));
2941             sysTime.add!"years"(-5);
2942             assert(sysTime == SysTime(Date(-4, 7, 6)));
2943         }
2944 
2945         {
2946             auto sysTime = SysTime(Date(4, 7, 6));
2947             sysTime.add!"years"(-8);
2948             assert(sysTime == SysTime(Date(-4, 7, 6)));
2949             sysTime.add!"years"(8);
2950             assert(sysTime == SysTime(Date(4, 7, 6)));
2951         }
2952 
2953         {
2954             auto sysTime = SysTime(Date(-4, 7, 6));
2955             sysTime.add!"years"(8);
2956             assert(sysTime == SysTime(Date(4, 7, 6)));
2957             sysTime.add!"years"(-8);
2958             assert(sysTime == SysTime(Date(-4, 7, 6)));
2959         }
2960 
2961         {
2962             auto sysTime = SysTime(Date(-4, 2, 29));
2963             sysTime.add!"years"(5);
2964             assert(sysTime == SysTime(Date(1, 3, 1)));
2965         }
2966 
2967         {
2968             auto sysTime = SysTime(Date(4, 2, 29));
2969             sysTime.add!"years"(-5);
2970             assert(sysTime == SysTime(Date(-1, 3, 1)));
2971         }
2972 
2973         {
2974             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
2975             sysTime.add!"years"(-1);
2976             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2977             sysTime.add!"years"(1);
2978             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2979         }
2980 
2981         {
2982             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2983             sysTime.add!"years"(-1);
2984             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2985             sysTime.add!"years"(1);
2986             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2987         }
2988 
2989         {
2990             auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0));
2991             sysTime.add!"years"(1);
2992             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2993             sysTime.add!"years"(-1);
2994             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2995         }
2996 
2997         {
2998             auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2999             sysTime.add!"years"(1);
3000             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3001             sysTime.add!"years"(-1);
3002             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3003         }
3004 
3005         {
3006             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
3007             sysTime.add!"years"(-5);
3008             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
3009             sysTime.add!"years"(5);
3010             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
3011         }
3012 
3013         {
3014             auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329));
3015             sysTime.add!"years"(5);
3016             assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329)));
3017             sysTime.add!"years"(-5);
3018             assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)));
3019         }
3020 
3021         {
3022             auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555));
3023             sysTime.add!"years"(5);
3024             assert(sysTime == SysTime(DateTime(1, 3, 1, 5, 5, 5), msecs(555)));
3025         }
3026 
3027         {
3028             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
3029             sysTime.add!"years"(-5);
3030             assert(sysTime == SysTime(DateTime(-1, 3, 1, 5, 5, 5), msecs(555)));
3031         }
3032 
3033         {
3034             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
3035             sysTime.add!"years"(-5).add!"years"(7);
3036             assert(sysTime == SysTime(DateTime(6, 3, 1, 5, 5, 5), msecs(555)));
3037         }
3038 
3039         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3040         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3041         static assert(!__traits(compiles, cst.add!"years"(4)));
3042         static assert(!__traits(compiles, ist.add!"years"(4)));
3043 
3044         static void testScope(scope ref SysTime st) @safe
3045         {
3046             auto result = st.add!"years"(42);
3047         }
3048     }
3049 
3050     // Test add!"years"() with AllowDayOverflow.no
3051     @safe unittest
3052     {
3053         import core.time;
3054         // Test A.D.
3055         {
3056             auto sysTime = SysTime(Date(1999, 7, 6));
3057             sysTime.add!"years"(7, AllowDayOverflow.no);
3058             assert(sysTime == SysTime(Date(2006, 7, 6)));
3059             sysTime.add!"years"(-9, AllowDayOverflow.no);
3060             assert(sysTime == SysTime(Date(1997, 7, 6)));
3061         }
3062 
3063         {
3064             auto sysTime = SysTime(Date(1999, 2, 28));
3065             sysTime.add!"years"(1, AllowDayOverflow.no);
3066             assert(sysTime == SysTime(Date(2000, 2, 28)));
3067         }
3068 
3069         {
3070             auto sysTime = SysTime(Date(2000, 2, 29));
3071             sysTime.add!"years"(-1, AllowDayOverflow.no);
3072             assert(sysTime == SysTime(Date(1999, 2, 28)));
3073         }
3074 
3075         {
3076             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234));
3077             sysTime.add!"years"(7, AllowDayOverflow.no);
3078             assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234)));
3079             sysTime.add!"years"(-9, AllowDayOverflow.no);
3080             assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234)));
3081         }
3082 
3083         {
3084             auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207));
3085             sysTime.add!"years"(1, AllowDayOverflow.no);
3086             assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207)));
3087         }
3088 
3089         {
3090             auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207));
3091             sysTime.add!"years"(-1, AllowDayOverflow.no);
3092             assert(sysTime == SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207)));
3093         }
3094 
3095         // Test B.C.
3096         {
3097             auto sysTime = SysTime(Date(-1999, 7, 6));
3098             sysTime.add!"years"(-7, AllowDayOverflow.no);
3099             assert(sysTime == SysTime(Date(-2006, 7, 6)));
3100             sysTime.add!"years"(9, AllowDayOverflow.no);
3101             assert(sysTime == SysTime(Date(-1997, 7, 6)));
3102         }
3103 
3104         {
3105             auto sysTime = SysTime(Date(-1999, 2, 28));
3106             sysTime.add!"years"(-1, AllowDayOverflow.no);
3107             assert(sysTime == SysTime(Date(-2000, 2, 28)));
3108         }
3109 
3110         {
3111             auto sysTime = SysTime(Date(-2000, 2, 29));
3112             sysTime.add!"years"(1, AllowDayOverflow.no);
3113             assert(sysTime == SysTime(Date(-1999, 2, 28)));
3114         }
3115 
3116         {
3117             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234));
3118             sysTime.add!"years"(-7, AllowDayOverflow.no);
3119             assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234)));
3120             sysTime.add!"years"(9, AllowDayOverflow.no);
3121             assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234)));
3122         }
3123 
3124         {
3125             auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3));
3126             sysTime.add!"years"(-1, AllowDayOverflow.no);
3127             assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3)));
3128         }
3129 
3130         {
3131             auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3));
3132             sysTime.add!"years"(1, AllowDayOverflow.no);
3133             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3)));
3134         }
3135 
3136         // Test Both
3137         {
3138             auto sysTime = SysTime(Date(4, 7, 6));
3139             sysTime.add!"years"(-5, AllowDayOverflow.no);
3140             assert(sysTime == SysTime(Date(-1, 7, 6)));
3141             sysTime.add!"years"(5, AllowDayOverflow.no);
3142             assert(sysTime == SysTime(Date(4, 7, 6)));
3143         }
3144 
3145         {
3146             auto sysTime = SysTime(Date(-4, 7, 6));
3147             sysTime.add!"years"(5, AllowDayOverflow.no);
3148             assert(sysTime == SysTime(Date(1, 7, 6)));
3149             sysTime.add!"years"(-5, AllowDayOverflow.no);
3150             assert(sysTime == SysTime(Date(-4, 7, 6)));
3151         }
3152 
3153         {
3154             auto sysTime = SysTime(Date(4, 7, 6));
3155             sysTime.add!"years"(-8, AllowDayOverflow.no);
3156             assert(sysTime == SysTime(Date(-4, 7, 6)));
3157             sysTime.add!"years"(8, AllowDayOverflow.no);
3158             assert(sysTime == SysTime(Date(4, 7, 6)));
3159         }
3160 
3161         {
3162             auto sysTime = SysTime(Date(-4, 7, 6));
3163             sysTime.add!"years"(8, AllowDayOverflow.no);
3164             assert(sysTime == SysTime(Date(4, 7, 6)));
3165             sysTime.add!"years"(-8, AllowDayOverflow.no);
3166             assert(sysTime == SysTime(Date(-4, 7, 6)));
3167         }
3168 
3169         {
3170             auto sysTime = SysTime(Date(-4, 2, 29));
3171             sysTime.add!"years"(5, AllowDayOverflow.no);
3172             assert(sysTime == SysTime(Date(1, 2, 28)));
3173         }
3174 
3175         {
3176             auto sysTime = SysTime(Date(4, 2, 29));
3177             sysTime.add!"years"(-5, AllowDayOverflow.no);
3178             assert(sysTime == SysTime(Date(-1, 2, 28)));
3179         }
3180 
3181         {
3182             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3183             sysTime.add!"years"(-1, AllowDayOverflow.no);
3184             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
3185             sysTime.add!"years"(1, AllowDayOverflow.no);
3186             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3187         }
3188 
3189         {
3190             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3191             sysTime.add!"years"(-1, AllowDayOverflow.no);
3192             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3193             sysTime.add!"years"(1, AllowDayOverflow.no);
3194             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3195         }
3196 
3197         {
3198             auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0));
3199             sysTime.add!"years"(1, AllowDayOverflow.no);
3200             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3201             sysTime.add!"years"(-1, AllowDayOverflow.no);
3202             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
3203         }
3204 
3205         {
3206             auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3207             sysTime.add!"years"(1, AllowDayOverflow.no);
3208             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3209             sysTime.add!"years"(-1, AllowDayOverflow.no);
3210             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3211         }
3212 
3213         {
3214             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
3215             sysTime.add!"years"(-5);
3216             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
3217             sysTime.add!"years"(5);
3218             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
3219         }
3220 
3221         {
3222             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
3223             sysTime.add!"years"(-5, AllowDayOverflow.no);
3224             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
3225             sysTime.add!"years"(5, AllowDayOverflow.no);
3226             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
3227         }
3228 
3229         {
3230             auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329));
3231             sysTime.add!"years"(5, AllowDayOverflow.no);
3232             assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329)));
3233             sysTime.add!"years"(-5, AllowDayOverflow.no);
3234             assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)));
3235         }
3236 
3237         {
3238             auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555));
3239             sysTime.add!"years"(5, AllowDayOverflow.no);
3240             assert(sysTime == SysTime(DateTime(1, 2, 28, 5, 5, 5), msecs(555)));
3241         }
3242 
3243         {
3244             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
3245             sysTime.add!"years"(-5, AllowDayOverflow.no);
3246             assert(sysTime == SysTime(DateTime(-1, 2, 28, 5, 5, 5), msecs(555)));
3247         }
3248 
3249         {
3250             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
3251             sysTime.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no);
3252             assert(sysTime == SysTime(DateTime(6, 2, 28, 5, 5, 5), msecs(555)));
3253         }
3254     }
3255 
3256     // Test add!"months"() with AllowDayOverflow.yes
3257     @safe unittest
3258     {
3259         import core.time;
3260         // Test A.D.
3261         {
3262             auto sysTime = SysTime(Date(1999, 7, 6));
3263             sysTime.add!"months"(3);
3264             assert(sysTime == SysTime(Date(1999, 10, 6)));
3265             sysTime.add!"months"(-4);
3266             assert(sysTime == SysTime(Date(1999, 6, 6)));
3267         }
3268 
3269         {
3270             auto sysTime = SysTime(Date(1999, 7, 6));
3271             sysTime.add!"months"(6);
3272             assert(sysTime == SysTime(Date(2000, 1, 6)));
3273             sysTime.add!"months"(-6);
3274             assert(sysTime == SysTime(Date(1999, 7, 6)));
3275         }
3276 
3277         {
3278             auto sysTime = SysTime(Date(1999, 7, 6));
3279             sysTime.add!"months"(27);
3280             assert(sysTime == SysTime(Date(2001, 10, 6)));
3281             sysTime.add!"months"(-28);
3282             assert(sysTime == SysTime(Date(1999, 6, 6)));
3283         }
3284 
3285         {
3286             auto sysTime = SysTime(Date(1999, 5, 31));
3287             sysTime.add!"months"(1);
3288             assert(sysTime == SysTime(Date(1999, 7, 1)));
3289         }
3290 
3291         {
3292             auto sysTime = SysTime(Date(1999, 5, 31));
3293             sysTime.add!"months"(-1);
3294             assert(sysTime == SysTime(Date(1999, 5, 1)));
3295         }
3296 
3297         {
3298             auto sysTime = SysTime(Date(1999, 2, 28));
3299             sysTime.add!"months"(12);
3300             assert(sysTime == SysTime(Date(2000, 2, 28)));
3301         }
3302 
3303         {
3304             auto sysTime = SysTime(Date(2000, 2, 29));
3305             sysTime.add!"months"(12);
3306             assert(sysTime == SysTime(Date(2001, 3, 1)));
3307         }
3308 
3309         {
3310             auto sysTime = SysTime(Date(1999, 7, 31));
3311             sysTime.add!"months"(1);
3312             assert(sysTime == SysTime(Date(1999, 8, 31)));
3313             sysTime.add!"months"(1);
3314             assert(sysTime == SysTime(Date(1999, 10, 1)));
3315         }
3316 
3317         {
3318             auto sysTime = SysTime(Date(1998, 8, 31));
3319             sysTime.add!"months"(13);
3320             assert(sysTime == SysTime(Date(1999, 10, 1)));
3321             sysTime.add!"months"(-13);
3322             assert(sysTime == SysTime(Date(1998, 9, 1)));
3323         }
3324 
3325         {
3326             auto sysTime = SysTime(Date(1997, 12, 31));
3327             sysTime.add!"months"(13);
3328             assert(sysTime == SysTime(Date(1999, 1, 31)));
3329             sysTime.add!"months"(-13);
3330             assert(sysTime == SysTime(Date(1997, 12, 31)));
3331         }
3332 
3333         {
3334             auto sysTime = SysTime(Date(1997, 12, 31));
3335             sysTime.add!"months"(14);
3336             assert(sysTime == SysTime(Date(1999, 3, 3)));
3337             sysTime.add!"months"(-14);
3338             assert(sysTime == SysTime(Date(1998, 1, 3)));
3339         }
3340 
3341         {
3342             auto sysTime = SysTime(Date(1998, 12, 31));
3343             sysTime.add!"months"(14);
3344             assert(sysTime == SysTime(Date(2000, 3, 2)));
3345             sysTime.add!"months"(-14);
3346             assert(sysTime == SysTime(Date(1999, 1, 2)));
3347         }
3348 
3349         {
3350             auto sysTime = SysTime(Date(1999, 12, 31));
3351             sysTime.add!"months"(14);
3352             assert(sysTime == SysTime(Date(2001, 3, 3)));
3353             sysTime.add!"months"(-14);
3354             assert(sysTime == SysTime(Date(2000, 1, 3)));
3355         }
3356 
3357         {
3358             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
3359             sysTime.add!"months"(3);
3360             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
3361             sysTime.add!"months"(-4);
3362             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
3363         }
3364 
3365         {
3366             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
3367             sysTime.add!"months"(14);
3368             assert(sysTime == SysTime(DateTime(2000, 3, 2, 7, 7, 7), hnsecs(422202)));
3369             sysTime.add!"months"(-14);
3370             assert(sysTime == SysTime(DateTime(1999, 1, 2, 7, 7, 7), hnsecs(422202)));
3371         }
3372 
3373         {
3374             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
3375             sysTime.add!"months"(14);
3376             assert(sysTime == SysTime(DateTime(2001, 3, 3, 7, 7, 7), hnsecs(422202)));
3377             sysTime.add!"months"(-14);
3378             assert(sysTime == SysTime(DateTime(2000, 1, 3, 7, 7, 7), hnsecs(422202)));
3379         }
3380 
3381         // Test B.C.
3382         {
3383             auto sysTime = SysTime(Date(-1999, 7, 6));
3384             sysTime.add!"months"(3);
3385             assert(sysTime == SysTime(Date(-1999, 10, 6)));
3386             sysTime.add!"months"(-4);
3387             assert(sysTime == SysTime(Date(-1999, 6, 6)));
3388         }
3389 
3390         {
3391             auto sysTime = SysTime(Date(-1999, 7, 6));
3392             sysTime.add!"months"(6);
3393             assert(sysTime == SysTime(Date(-1998, 1, 6)));
3394             sysTime.add!"months"(-6);
3395             assert(sysTime == SysTime(Date(-1999, 7, 6)));
3396         }
3397 
3398         {
3399             auto sysTime = SysTime(Date(-1999, 7, 6));
3400             sysTime.add!"months"(-27);
3401             assert(sysTime == SysTime(Date(-2001, 4, 6)));
3402             sysTime.add!"months"(28);
3403             assert(sysTime == SysTime(Date(-1999, 8, 6)));
3404         }
3405 
3406         {
3407             auto sysTime = SysTime(Date(-1999, 5, 31));
3408             sysTime.add!"months"(1);
3409             assert(sysTime == SysTime(Date(-1999, 7, 1)));
3410         }
3411 
3412         {
3413             auto sysTime = SysTime(Date(-1999, 5, 31));
3414             sysTime.add!"months"(-1);
3415             assert(sysTime == SysTime(Date(-1999, 5, 1)));
3416         }
3417 
3418         {
3419             auto sysTime = SysTime(Date(-1999, 2, 28));
3420             sysTime.add!"months"(-12);
3421             assert(sysTime == SysTime(Date(-2000, 2, 28)));
3422         }
3423 
3424         {
3425             auto sysTime = SysTime(Date(-2000, 2, 29));
3426             sysTime.add!"months"(-12);
3427             assert(sysTime == SysTime(Date(-2001, 3, 1)));
3428         }
3429 
3430         {
3431             auto sysTime = SysTime(Date(-1999, 7, 31));
3432             sysTime.add!"months"(1);
3433             assert(sysTime == SysTime(Date(-1999, 8, 31)));
3434             sysTime.add!"months"(1);
3435             assert(sysTime == SysTime(Date(-1999, 10, 1)));
3436         }
3437 
3438         {
3439             auto sysTime = SysTime(Date(-1998, 8, 31));
3440             sysTime.add!"months"(13);
3441             assert(sysTime == SysTime(Date(-1997, 10, 1)));
3442             sysTime.add!"months"(-13);
3443             assert(sysTime == SysTime(Date(-1998, 9, 1)));
3444         }
3445 
3446         {
3447             auto sysTime = SysTime(Date(-1997, 12, 31));
3448             sysTime.add!"months"(13);
3449             assert(sysTime == SysTime(Date(-1995, 1, 31)));
3450             sysTime.add!"months"(-13);
3451             assert(sysTime == SysTime(Date(-1997, 12, 31)));
3452         }
3453 
3454         {
3455             auto sysTime = SysTime(Date(-1997, 12, 31));
3456             sysTime.add!"months"(14);
3457             assert(sysTime == SysTime(Date(-1995, 3, 3)));
3458             sysTime.add!"months"(-14);
3459             assert(sysTime == SysTime(Date(-1996, 1, 3)));
3460         }
3461 
3462         {
3463             auto sysTime = SysTime(Date(-2002, 12, 31));
3464             sysTime.add!"months"(14);
3465             assert(sysTime == SysTime(Date(-2000, 3, 2)));
3466             sysTime.add!"months"(-14);
3467             assert(sysTime == SysTime(Date(-2001, 1, 2)));
3468         }
3469 
3470         {
3471             auto sysTime = SysTime(Date(-2001, 12, 31));
3472             sysTime.add!"months"(14);
3473             assert(sysTime == SysTime(Date(-1999, 3, 3)));
3474             sysTime.add!"months"(-14);
3475             assert(sysTime == SysTime(Date(-2000, 1, 3)));
3476         }
3477 
3478         {
3479             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
3480             sysTime.add!"months"(3);
3481             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
3482             sysTime.add!"months"(-4);
3483             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
3484         }
3485 
3486         {
3487             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
3488             sysTime.add!"months"(14);
3489             assert(sysTime == SysTime(DateTime(-2000, 3, 2, 7, 7, 7), hnsecs(422202)));
3490             sysTime.add!"months"(-14);
3491             assert(sysTime == SysTime(DateTime(-2001, 1, 2, 7, 7, 7), hnsecs(422202)));
3492         }
3493 
3494         {
3495             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
3496             sysTime.add!"months"(14);
3497             assert(sysTime == SysTime(DateTime(-1999, 3, 3, 7, 7, 7), hnsecs(422202)));
3498             sysTime.add!"months"(-14);
3499             assert(sysTime == SysTime(DateTime(-2000, 1, 3, 7, 7, 7), hnsecs(422202)));
3500         }
3501 
3502         // Test Both
3503         {
3504             auto sysTime = SysTime(Date(1, 1, 1));
3505             sysTime.add!"months"(-1);
3506             assert(sysTime == SysTime(Date(0, 12, 1)));
3507             sysTime.add!"months"(1);
3508             assert(sysTime == SysTime(Date(1, 1, 1)));
3509         }
3510 
3511         {
3512             auto sysTime = SysTime(Date(4, 1, 1));
3513             sysTime.add!"months"(-48);
3514             assert(sysTime == SysTime(Date(0, 1, 1)));
3515             sysTime.add!"months"(48);
3516             assert(sysTime == SysTime(Date(4, 1, 1)));
3517         }
3518 
3519         {
3520             auto sysTime = SysTime(Date(4, 3, 31));
3521             sysTime.add!"months"(-49);
3522             assert(sysTime == SysTime(Date(0, 3, 2)));
3523             sysTime.add!"months"(49);
3524             assert(sysTime == SysTime(Date(4, 4, 2)));
3525         }
3526 
3527         {
3528             auto sysTime = SysTime(Date(4, 3, 31));
3529             sysTime.add!"months"(-85);
3530             assert(sysTime == SysTime(Date(-3, 3, 3)));
3531             sysTime.add!"months"(85);
3532             assert(sysTime == SysTime(Date(4, 4, 3)));
3533         }
3534 
3535         {
3536             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3537             sysTime.add!"months"(-1);
3538             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3539             sysTime.add!"months"(1);
3540             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3541         }
3542 
3543         {
3544             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3545             sysTime.add!"months"(-1);
3546             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3547             sysTime.add!"months"(1);
3548             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3549         }
3550 
3551         {
3552             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
3553             sysTime.add!"months"(1);
3554             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3555             sysTime.add!"months"(-1);
3556             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3557         }
3558 
3559         {
3560             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
3561             sysTime.add!"months"(1);
3562             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3563             sysTime.add!"months"(-1);
3564             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3565         }
3566 
3567         {
3568             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
3569             sysTime.add!"months"(-1);
3570             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17)));
3571             sysTime.add!"months"(1);
3572             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
3573         }
3574 
3575         {
3576             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
3577             sysTime.add!"months"(-85);
3578             assert(sysTime == SysTime(DateTime(-3, 3, 3, 12, 11, 10), msecs(9)));
3579             sysTime.add!"months"(85);
3580             assert(sysTime == SysTime(DateTime(4, 4, 3, 12, 11, 10), msecs(9)));
3581         }
3582 
3583         {
3584             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3585             sysTime.add!"months"(85);
3586             assert(sysTime == SysTime(DateTime(4, 5, 1, 12, 11, 10), msecs(9)));
3587             sysTime.add!"months"(-85);
3588             assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9)));
3589         }
3590 
3591         {
3592             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3593             sysTime.add!"months"(85).add!"months"(-83);
3594             assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), msecs(9)));
3595         }
3596 
3597         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3598         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3599         static assert(!__traits(compiles, cst.add!"months"(4)));
3600         static assert(!__traits(compiles, ist.add!"months"(4)));
3601 
3602         static void testScope(scope ref SysTime st) @safe
3603         {
3604             auto result = st.add!"months"(42);
3605         }
3606     }
3607 
3608     // Test add!"months"() with AllowDayOverflow.no
3609     @safe unittest
3610     {
3611         import core.time;
3612         // Test A.D.
3613         {
3614             auto sysTime = SysTime(Date(1999, 7, 6));
3615             sysTime.add!"months"(3, AllowDayOverflow.no);
3616             assert(sysTime == SysTime(Date(1999, 10, 6)));
3617             sysTime.add!"months"(-4, AllowDayOverflow.no);
3618             assert(sysTime == SysTime(Date(1999, 6, 6)));
3619         }
3620 
3621         {
3622             auto sysTime = SysTime(Date(1999, 7, 6));
3623             sysTime.add!"months"(6, AllowDayOverflow.no);
3624             assert(sysTime == SysTime(Date(2000, 1, 6)));
3625             sysTime.add!"months"(-6, AllowDayOverflow.no);
3626             assert(sysTime == SysTime(Date(1999, 7, 6)));
3627         }
3628 
3629         {
3630             auto sysTime = SysTime(Date(1999, 7, 6));
3631             sysTime.add!"months"(27, AllowDayOverflow.no);
3632             assert(sysTime == SysTime(Date(2001, 10, 6)));
3633             sysTime.add!"months"(-28, AllowDayOverflow.no);
3634             assert(sysTime == SysTime(Date(1999, 6, 6)));
3635         }
3636 
3637         {
3638             auto sysTime = SysTime(Date(1999, 5, 31));
3639             sysTime.add!"months"(1, AllowDayOverflow.no);
3640             assert(sysTime == SysTime(Date(1999, 6, 30)));
3641         }
3642 
3643         {
3644             auto sysTime = SysTime(Date(1999, 5, 31));
3645             sysTime.add!"months"(-1, AllowDayOverflow.no);
3646             assert(sysTime == SysTime(Date(1999, 4, 30)));
3647         }
3648 
3649         {
3650             auto sysTime = SysTime(Date(1999, 2, 28));
3651             sysTime.add!"months"(12, AllowDayOverflow.no);
3652             assert(sysTime == SysTime(Date(2000, 2, 28)));
3653         }
3654 
3655         {
3656             auto sysTime = SysTime(Date(2000, 2, 29));
3657             sysTime.add!"months"(12, AllowDayOverflow.no);
3658             assert(sysTime == SysTime(Date(2001, 2, 28)));
3659         }
3660 
3661         {
3662             auto sysTime = SysTime(Date(1999, 7, 31));
3663             sysTime.add!"months"(1, AllowDayOverflow.no);
3664             assert(sysTime == SysTime(Date(1999, 8, 31)));
3665             sysTime.add!"months"(1, AllowDayOverflow.no);
3666             assert(sysTime == SysTime(Date(1999, 9, 30)));
3667         }
3668 
3669         {
3670             auto sysTime = SysTime(Date(1998, 8, 31));
3671             sysTime.add!"months"(13, AllowDayOverflow.no);
3672             assert(sysTime == SysTime(Date(1999, 9, 30)));
3673             sysTime.add!"months"(-13, AllowDayOverflow.no);
3674             assert(sysTime == SysTime(Date(1998, 8, 30)));
3675         }
3676 
3677         {
3678             auto sysTime = SysTime(Date(1997, 12, 31));
3679             sysTime.add!"months"(13, AllowDayOverflow.no);
3680             assert(sysTime == SysTime(Date(1999, 1, 31)));
3681             sysTime.add!"months"(-13, AllowDayOverflow.no);
3682             assert(sysTime == SysTime(Date(1997, 12, 31)));
3683         }
3684 
3685         {
3686             auto sysTime = SysTime(Date(1997, 12, 31));
3687             sysTime.add!"months"(14, AllowDayOverflow.no);
3688             assert(sysTime == SysTime(Date(1999, 2, 28)));
3689             sysTime.add!"months"(-14, AllowDayOverflow.no);
3690             assert(sysTime == SysTime(Date(1997, 12, 28)));
3691         }
3692 
3693         {
3694             auto sysTime = SysTime(Date(1998, 12, 31));
3695             sysTime.add!"months"(14, AllowDayOverflow.no);
3696             assert(sysTime == SysTime(Date(2000, 2, 29)));
3697             sysTime.add!"months"(-14, AllowDayOverflow.no);
3698             assert(sysTime == SysTime(Date(1998, 12, 29)));
3699         }
3700 
3701         {
3702             auto sysTime = SysTime(Date(1999, 12, 31));
3703             sysTime.add!"months"(14, AllowDayOverflow.no);
3704             assert(sysTime == SysTime(Date(2001, 2, 28)));
3705             sysTime.add!"months"(-14, AllowDayOverflow.no);
3706             assert(sysTime == SysTime(Date(1999, 12, 28)));
3707         }
3708 
3709         {
3710             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
3711             sysTime.add!"months"(3, AllowDayOverflow.no);
3712             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
3713             sysTime.add!"months"(-4, AllowDayOverflow.no);
3714             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
3715         }
3716 
3717         {
3718             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
3719             sysTime.add!"months"(14, AllowDayOverflow.no);
3720             assert(sysTime == SysTime(DateTime(2000, 2, 29, 7, 7, 7), hnsecs(422202)));
3721             sysTime.add!"months"(-14, AllowDayOverflow.no);
3722             assert(sysTime == SysTime(DateTime(1998, 12, 29, 7, 7, 7), hnsecs(422202)));
3723         }
3724 
3725         {
3726             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
3727             sysTime.add!"months"(14, AllowDayOverflow.no);
3728             assert(sysTime == SysTime(DateTime(2001, 2, 28, 7, 7, 7), hnsecs(422202)));
3729             sysTime.add!"months"(-14, AllowDayOverflow.no);
3730             assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202)));
3731         }
3732 
3733         // Test B.C.
3734         {
3735             auto sysTime = SysTime(Date(-1999, 7, 6));
3736             sysTime.add!"months"(3, AllowDayOverflow.no);
3737             assert(sysTime == SysTime(Date(-1999, 10, 6)));
3738             sysTime.add!"months"(-4, AllowDayOverflow.no);
3739             assert(sysTime == SysTime(Date(-1999, 6, 6)));
3740         }
3741 
3742         {
3743             auto sysTime = SysTime(Date(-1999, 7, 6));
3744             sysTime.add!"months"(6, AllowDayOverflow.no);
3745             assert(sysTime == SysTime(Date(-1998, 1, 6)));
3746             sysTime.add!"months"(-6, AllowDayOverflow.no);
3747             assert(sysTime == SysTime(Date(-1999, 7, 6)));
3748         }
3749 
3750         {
3751             auto sysTime = SysTime(Date(-1999, 7, 6));
3752             sysTime.add!"months"(-27, AllowDayOverflow.no);
3753             assert(sysTime == SysTime(Date(-2001, 4, 6)));
3754             sysTime.add!"months"(28, AllowDayOverflow.no);
3755             assert(sysTime == SysTime(Date(-1999, 8, 6)));
3756         }
3757 
3758         {
3759             auto sysTime = SysTime(Date(-1999, 5, 31));
3760             sysTime.add!"months"(1, AllowDayOverflow.no);
3761             assert(sysTime == SysTime(Date(-1999, 6, 30)));
3762         }
3763 
3764         {
3765             auto sysTime = SysTime(Date(-1999, 5, 31));
3766             sysTime.add!"months"(-1, AllowDayOverflow.no);
3767             assert(sysTime == SysTime(Date(-1999, 4, 30)));
3768         }
3769 
3770         {
3771             auto sysTime = SysTime(Date(-1999, 2, 28));
3772             sysTime.add!"months"(-12, AllowDayOverflow.no);
3773             assert(sysTime == SysTime(Date(-2000, 2, 28)));
3774         }
3775 
3776         {
3777             auto sysTime = SysTime(Date(-2000, 2, 29));
3778             sysTime.add!"months"(-12, AllowDayOverflow.no);
3779             assert(sysTime == SysTime(Date(-2001, 2, 28)));
3780         }
3781 
3782         {
3783             auto sysTime = SysTime(Date(-1999, 7, 31));
3784             sysTime.add!"months"(1, AllowDayOverflow.no);
3785             assert(sysTime == SysTime(Date(-1999, 8, 31)));
3786             sysTime.add!"months"(1, AllowDayOverflow.no);
3787             assert(sysTime == SysTime(Date(-1999, 9, 30)));
3788         }
3789 
3790         {
3791             auto sysTime = SysTime(Date(-1998, 8, 31));
3792             sysTime.add!"months"(13, AllowDayOverflow.no);
3793             assert(sysTime == SysTime(Date(-1997, 9, 30)));
3794             sysTime.add!"months"(-13, AllowDayOverflow.no);
3795             assert(sysTime == SysTime(Date(-1998, 8, 30)));
3796         }
3797 
3798         {
3799             auto sysTime = SysTime(Date(-1997, 12, 31));
3800             sysTime.add!"months"(13, AllowDayOverflow.no);
3801             assert(sysTime == SysTime(Date(-1995, 1, 31)));
3802             sysTime.add!"months"(-13, AllowDayOverflow.no);
3803             assert(sysTime == SysTime(Date(-1997, 12, 31)));
3804         }
3805 
3806         {
3807             auto sysTime = SysTime(Date(-1997, 12, 31));
3808             sysTime.add!"months"(14, AllowDayOverflow.no);
3809             assert(sysTime == SysTime(Date(-1995, 2, 28)));
3810             sysTime.add!"months"(-14, AllowDayOverflow.no);
3811             assert(sysTime == SysTime(Date(-1997, 12, 28)));
3812         }
3813 
3814         {
3815             auto sysTime = SysTime(Date(-2002, 12, 31));
3816             sysTime.add!"months"(14, AllowDayOverflow.no);
3817             assert(sysTime == SysTime(Date(-2000, 2, 29)));
3818             sysTime.add!"months"(-14, AllowDayOverflow.no);
3819             assert(sysTime == SysTime(Date(-2002, 12, 29)));
3820         }
3821 
3822         {
3823             auto sysTime = SysTime(Date(-2001, 12, 31));
3824             sysTime.add!"months"(14, AllowDayOverflow.no);
3825             assert(sysTime == SysTime(Date(-1999, 2, 28)));
3826             sysTime.add!"months"(-14, AllowDayOverflow.no);
3827             assert(sysTime == SysTime(Date(-2001, 12, 28)));
3828         }
3829 
3830         {
3831             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
3832             sysTime.add!"months"(3, AllowDayOverflow.no);
3833             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
3834             sysTime.add!"months"(-4, AllowDayOverflow.no);
3835             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
3836         }
3837 
3838         {
3839             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
3840             sysTime.add!"months"(14, AllowDayOverflow.no);
3841             assert(sysTime == SysTime(DateTime(-2000, 2, 29, 7, 7, 7), hnsecs(422202)));
3842             sysTime.add!"months"(-14, AllowDayOverflow.no);
3843             assert(sysTime == SysTime(DateTime(-2002, 12, 29, 7, 7, 7), hnsecs(422202)));
3844         }
3845 
3846         {
3847             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
3848             sysTime.add!"months"(14, AllowDayOverflow.no);
3849             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 7, 7), hnsecs(422202)));
3850             sysTime.add!"months"(-14, AllowDayOverflow.no);
3851             assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202)));
3852         }
3853 
3854         // Test Both
3855         {
3856             auto sysTime = SysTime(Date(1, 1, 1));
3857             sysTime.add!"months"(-1, AllowDayOverflow.no);
3858             assert(sysTime == SysTime(Date(0, 12, 1)));
3859             sysTime.add!"months"(1, AllowDayOverflow.no);
3860             assert(sysTime == SysTime(Date(1, 1, 1)));
3861         }
3862 
3863         {
3864             auto sysTime = SysTime(Date(4, 1, 1));
3865             sysTime.add!"months"(-48, AllowDayOverflow.no);
3866             assert(sysTime == SysTime(Date(0, 1, 1)));
3867             sysTime.add!"months"(48, AllowDayOverflow.no);
3868             assert(sysTime == SysTime(Date(4, 1, 1)));
3869         }
3870 
3871         {
3872             auto sysTime = SysTime(Date(4, 3, 31));
3873             sysTime.add!"months"(-49, AllowDayOverflow.no);
3874             assert(sysTime == SysTime(Date(0, 2, 29)));
3875             sysTime.add!"months"(49, AllowDayOverflow.no);
3876             assert(sysTime == SysTime(Date(4, 3, 29)));
3877         }
3878 
3879         {
3880             auto sysTime = SysTime(Date(4, 3, 31));
3881             sysTime.add!"months"(-85, AllowDayOverflow.no);
3882             assert(sysTime == SysTime(Date(-3, 2, 28)));
3883             sysTime.add!"months"(85, AllowDayOverflow.no);
3884             assert(sysTime == SysTime(Date(4, 3, 28)));
3885         }
3886 
3887         {
3888             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3889             sysTime.add!"months"(-1, AllowDayOverflow.no);
3890             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3891             sysTime.add!"months"(1, AllowDayOverflow.no);
3892             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3893         }
3894 
3895         {
3896             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3897             sysTime.add!"months"(-1, AllowDayOverflow.no);
3898             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3899             sysTime.add!"months"(1, AllowDayOverflow.no);
3900             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3901         }
3902 
3903         {
3904             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
3905             sysTime.add!"months"(1, AllowDayOverflow.no);
3906             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3907             sysTime.add!"months"(-1, AllowDayOverflow.no);
3908             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3909         }
3910 
3911         {
3912             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
3913             sysTime.add!"months"(1, AllowDayOverflow.no);
3914             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3915             sysTime.add!"months"(-1, AllowDayOverflow.no);
3916             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3917         }
3918 
3919         {
3920             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
3921             sysTime.add!"months"(-1, AllowDayOverflow.no);
3922             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17)));
3923             sysTime.add!"months"(1, AllowDayOverflow.no);
3924             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
3925         }
3926 
3927         {
3928             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
3929             sysTime.add!"months"(-85, AllowDayOverflow.no);
3930             assert(sysTime == SysTime(DateTime(-3, 2, 28, 12, 11, 10), msecs(9)));
3931             sysTime.add!"months"(85, AllowDayOverflow.no);
3932             assert(sysTime == SysTime(DateTime(4, 3, 28, 12, 11, 10), msecs(9)));
3933         }
3934 
3935         {
3936             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3937             sysTime.add!"months"(85, AllowDayOverflow.no);
3938             assert(sysTime == SysTime(DateTime(4, 4, 30, 12, 11, 10), msecs(9)));
3939             sysTime.add!"months"(-85, AllowDayOverflow.no);
3940             assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9)));
3941         }
3942 
3943         {
3944             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3945             sysTime.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no);
3946             assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9)));
3947         }
3948     }
3949 
3950 
3951     /++
3952         Adds the given number of years or months to this $(LREF SysTime). A
3953         negative number will subtract.
3954 
3955         The difference between rolling and adding is that rolling does not
3956         affect larger units. Rolling a $(LREF SysTime) 12 months
3957         gets the exact same $(LREF SysTime). However, the days can still be
3958         affected due to the differing number of days in each month.
3959 
3960         Because there are no units larger than years, there is no difference
3961         between adding and rolling years.
3962 
3963         Params:
3964             units         = The type of units to add ("years" or "months").
3965             value         = The number of months or years to add to this
3966                             $(LREF SysTime).
3967             allowOverflow = Whether the days should be allowed to overflow,
3968                             causing the month to increment.
3969       +/
3970     ref SysTime roll(string units)
3971                     (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow scope
3972     if (units == "years")
3973     {
3974         return add!"years"(value, allowOverflow);
3975     }
3976 
3977     ///
3978     @safe unittest
3979     {
3980         import std.datetime.date : AllowDayOverflow, DateTime;
3981 
3982         auto st1 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
3983         st1.roll!"months"(1);
3984         assert(st1 == SysTime(DateTime(2010, 2, 1, 12, 33, 33)));
3985 
3986         auto st2 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
3987         st2.roll!"months"(-1);
3988         assert(st2 == SysTime(DateTime(2010, 12, 1, 12, 33, 33)));
3989 
3990         auto st3 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
3991         st3.roll!"months"(1);
3992         assert(st3 == SysTime(DateTime(1999, 3, 1, 12, 33, 33)));
3993 
3994         auto st4 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
3995         st4.roll!"months"(1, AllowDayOverflow.no);
3996         assert(st4 == SysTime(DateTime(1999, 2, 28, 12, 33, 33)));
3997 
3998         auto st5 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
3999         st5.roll!"years"(1);
4000         assert(st5 == SysTime(DateTime(2001, 3, 1, 12, 30, 33)));
4001 
4002         auto st6 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
4003         st6.roll!"years"(1, AllowDayOverflow.no);
4004         assert(st6 == SysTime(DateTime(2001, 2, 28, 12, 30, 33)));
4005     }
4006 
4007     @safe unittest
4008     {
4009         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4010         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4011         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4012         st.roll!"years"(4);
4013         static assert(!__traits(compiles, cst.roll!"years"(4)));
4014         static assert(!__traits(compiles, ist.roll!"years"(4)));
4015 
4016         static void testScope(scope ref SysTime st) @safe
4017         {
4018             auto result = st.roll!"years"(42);
4019         }
4020     }
4021 
4022 
4023     // Shares documentation with "years" overload.
4024     ref SysTime roll(string units)
4025                     (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow scope
4026     if (units == "months")
4027     {
4028         auto hnsecs = adjTime;
4029         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
4030 
4031         if (hnsecs < 0)
4032         {
4033             hnsecs += convert!("hours", "hnsecs")(24);
4034             --days;
4035         }
4036 
4037         auto date = Date(cast(int) days);
4038         date.roll!"months"(value, allowOverflow);
4039         days = date.dayOfGregorianCal - 1;
4040 
4041         if (days < 0)
4042         {
4043             hnsecs -= convert!("hours", "hnsecs")(24);
4044             ++days;
4045         }
4046 
4047         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
4048         adjTime = newDaysHNSecs + hnsecs;
4049         return this;
4050     }
4051 
4052     // Test roll!"months"() with AllowDayOverflow.yes
4053     @safe unittest
4054     {
4055         import core.time;
4056         // Test A.D.
4057         {
4058             auto sysTime = SysTime(Date(1999, 7, 6));
4059             sysTime.roll!"months"(3);
4060             assert(sysTime == SysTime(Date(1999, 10, 6)));
4061             sysTime.roll!"months"(-4);
4062             assert(sysTime == SysTime(Date(1999, 6, 6)));
4063         }
4064 
4065         {
4066             auto sysTime = SysTime(Date(1999, 7, 6));
4067             sysTime.roll!"months"(6);
4068             assert(sysTime == SysTime(Date(1999, 1, 6)));
4069             sysTime.roll!"months"(-6);
4070             assert(sysTime == SysTime(Date(1999, 7, 6)));
4071         }
4072 
4073         {
4074             auto sysTime = SysTime(Date(1999, 7, 6));
4075             sysTime.roll!"months"(27);
4076             assert(sysTime == SysTime(Date(1999, 10, 6)));
4077             sysTime.roll!"months"(-28);
4078             assert(sysTime == SysTime(Date(1999, 6, 6)));
4079         }
4080 
4081         {
4082             auto sysTime = SysTime(Date(1999, 5, 31));
4083             sysTime.roll!"months"(1);
4084             assert(sysTime == SysTime(Date(1999, 7, 1)));
4085         }
4086 
4087         {
4088             auto sysTime = SysTime(Date(1999, 5, 31));
4089             sysTime.roll!"months"(-1);
4090             assert(sysTime == SysTime(Date(1999, 5, 1)));
4091         }
4092 
4093         {
4094             auto sysTime = SysTime(Date(1999, 2, 28));
4095             sysTime.roll!"months"(12);
4096             assert(sysTime == SysTime(Date(1999, 2, 28)));
4097         }
4098 
4099         {
4100             auto sysTime = SysTime(Date(2000, 2, 29));
4101             sysTime.roll!"months"(12);
4102             assert(sysTime == SysTime(Date(2000, 2, 29)));
4103         }
4104 
4105         {
4106             auto sysTime = SysTime(Date(1999, 7, 31));
4107             sysTime.roll!"months"(1);
4108             assert(sysTime == SysTime(Date(1999, 8, 31)));
4109             sysTime.roll!"months"(1);
4110             assert(sysTime == SysTime(Date(1999, 10, 1)));
4111         }
4112 
4113         {
4114             auto sysTime = SysTime(Date(1998, 8, 31));
4115             sysTime.roll!"months"(13);
4116             assert(sysTime == SysTime(Date(1998, 10, 1)));
4117             sysTime.roll!"months"(-13);
4118             assert(sysTime == SysTime(Date(1998, 9, 1)));
4119         }
4120 
4121         {
4122             auto sysTime = SysTime(Date(1997, 12, 31));
4123             sysTime.roll!"months"(13);
4124             assert(sysTime == SysTime(Date(1997, 1, 31)));
4125             sysTime.roll!"months"(-13);
4126             assert(sysTime == SysTime(Date(1997, 12, 31)));
4127         }
4128 
4129         {
4130             auto sysTime = SysTime(Date(1997, 12, 31));
4131             sysTime.roll!"months"(14);
4132             assert(sysTime == SysTime(Date(1997, 3, 3)));
4133             sysTime.roll!"months"(-14);
4134             assert(sysTime == SysTime(Date(1997, 1, 3)));
4135         }
4136 
4137         {
4138             auto sysTime = SysTime(Date(1998, 12, 31));
4139             sysTime.roll!"months"(14);
4140             assert(sysTime == SysTime(Date(1998, 3, 3)));
4141             sysTime.roll!"months"(-14);
4142             assert(sysTime == SysTime(Date(1998, 1, 3)));
4143         }
4144 
4145         {
4146             auto sysTime = SysTime(Date(1999, 12, 31));
4147             sysTime.roll!"months"(14);
4148             assert(sysTime == SysTime(Date(1999, 3, 3)));
4149             sysTime.roll!"months"(-14);
4150             assert(sysTime == SysTime(Date(1999, 1, 3)));
4151         }
4152 
4153         {
4154             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
4155             sysTime.roll!"months"(3);
4156             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
4157             sysTime.roll!"months"(-4);
4158             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
4159         }
4160 
4161         {
4162             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
4163             sysTime.roll!"months"(14);
4164             assert(sysTime == SysTime(DateTime(1998, 3, 3, 7, 7, 7), hnsecs(422202)));
4165             sysTime.roll!"months"(-14);
4166             assert(sysTime == SysTime(DateTime(1998, 1, 3, 7, 7, 7), hnsecs(422202)));
4167         }
4168 
4169         {
4170             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
4171             sysTime.roll!"months"(14);
4172             assert(sysTime == SysTime(DateTime(1999, 3, 3, 7, 7, 7), hnsecs(422202)));
4173             sysTime.roll!"months"(-14);
4174             assert(sysTime == SysTime(DateTime(1999, 1, 3, 7, 7, 7), hnsecs(422202)));
4175         }
4176 
4177         // Test B.C.
4178         {
4179             auto sysTime = SysTime(Date(-1999, 7, 6));
4180             sysTime.roll!"months"(3);
4181             assert(sysTime == SysTime(Date(-1999, 10, 6)));
4182             sysTime.roll!"months"(-4);
4183             assert(sysTime == SysTime(Date(-1999, 6, 6)));
4184         }
4185 
4186         {
4187             auto sysTime = SysTime(Date(-1999, 7, 6));
4188             sysTime.roll!"months"(6);
4189             assert(sysTime == SysTime(Date(-1999, 1, 6)));
4190             sysTime.roll!"months"(-6);
4191             assert(sysTime == SysTime(Date(-1999, 7, 6)));
4192         }
4193 
4194         {
4195             auto sysTime = SysTime(Date(-1999, 7, 6));
4196             sysTime.roll!"months"(-27);
4197             assert(sysTime == SysTime(Date(-1999, 4, 6)));
4198             sysTime.roll!"months"(28);
4199             assert(sysTime == SysTime(Date(-1999, 8, 6)));
4200         }
4201 
4202         {
4203             auto sysTime = SysTime(Date(-1999, 5, 31));
4204             sysTime.roll!"months"(1);
4205             assert(sysTime == SysTime(Date(-1999, 7, 1)));
4206         }
4207 
4208         {
4209             auto sysTime = SysTime(Date(-1999, 5, 31));
4210             sysTime.roll!"months"(-1);
4211             assert(sysTime == SysTime(Date(-1999, 5, 1)));
4212         }
4213 
4214         {
4215             auto sysTime = SysTime(Date(-1999, 2, 28));
4216             sysTime.roll!"months"(-12);
4217             assert(sysTime == SysTime(Date(-1999, 2, 28)));
4218         }
4219 
4220         {
4221             auto sysTime = SysTime(Date(-2000, 2, 29));
4222             sysTime.roll!"months"(-12);
4223             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4224         }
4225 
4226         {
4227             auto sysTime = SysTime(Date(-1999, 7, 31));
4228             sysTime.roll!"months"(1);
4229             assert(sysTime == SysTime(Date(-1999, 8, 31)));
4230             sysTime.roll!"months"(1);
4231             assert(sysTime == SysTime(Date(-1999, 10, 1)));
4232         }
4233 
4234         {
4235             auto sysTime = SysTime(Date(-1998, 8, 31));
4236             sysTime.roll!"months"(13);
4237             assert(sysTime == SysTime(Date(-1998, 10, 1)));
4238             sysTime.roll!"months"(-13);
4239             assert(sysTime == SysTime(Date(-1998, 9, 1)));
4240         }
4241 
4242         {
4243             auto sysTime = SysTime(Date(-1997, 12, 31));
4244             sysTime.roll!"months"(13);
4245             assert(sysTime == SysTime(Date(-1997, 1, 31)));
4246             sysTime.roll!"months"(-13);
4247             assert(sysTime == SysTime(Date(-1997, 12, 31)));
4248         }
4249 
4250         {
4251             auto sysTime = SysTime(Date(-1997, 12, 31));
4252             sysTime.roll!"months"(14);
4253             assert(sysTime == SysTime(Date(-1997, 3, 3)));
4254             sysTime.roll!"months"(-14);
4255             assert(sysTime == SysTime(Date(-1997, 1, 3)));
4256         }
4257 
4258         {
4259             auto sysTime = SysTime(Date(-2002, 12, 31));
4260             sysTime.roll!"months"(14);
4261             assert(sysTime == SysTime(Date(-2002, 3, 3)));
4262             sysTime.roll!"months"(-14);
4263             assert(sysTime == SysTime(Date(-2002, 1, 3)));
4264         }
4265 
4266         {
4267             auto sysTime = SysTime(Date(-2001, 12, 31));
4268             sysTime.roll!"months"(14);
4269             assert(sysTime == SysTime(Date(-2001, 3, 3)));
4270             sysTime.roll!"months"(-14);
4271             assert(sysTime == SysTime(Date(-2001, 1, 3)));
4272         }
4273 
4274         {
4275             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
4276             sysTime.roll!"months"(-1);
4277             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0)));
4278             sysTime.roll!"months"(1);
4279             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
4280         }
4281 
4282         {
4283             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
4284             sysTime.roll!"months"(-1);
4285             assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4286             sysTime.roll!"months"(1);
4287             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4288         }
4289 
4290         {
4291             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
4292             sysTime.roll!"months"(1);
4293             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
4294             sysTime.roll!"months"(-1);
4295             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
4296         }
4297 
4298         {
4299             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
4300             sysTime.roll!"months"(1);
4301             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4302             sysTime.roll!"months"(-1);
4303             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4304         }
4305 
4306         {
4307             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), hnsecs(5007));
4308             sysTime.roll!"months"(3);
4309             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), hnsecs(5007)));
4310             sysTime.roll!"months"(-4);
4311             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), hnsecs(5007)));
4312         }
4313 
4314         {
4315             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
4316             sysTime.roll!"months"(14);
4317             assert(sysTime == SysTime(DateTime(-2002, 3, 3, 7, 7, 7), hnsecs(422202)));
4318             sysTime.roll!"months"(-14);
4319             assert(sysTime == SysTime(DateTime(-2002, 1, 3, 7, 7, 7), hnsecs(422202)));
4320         }
4321 
4322         {
4323             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
4324             sysTime.roll!"months"(14);
4325             assert(sysTime == SysTime(DateTime(-2001, 3, 3, 7, 7, 7), hnsecs(422202)));
4326             sysTime.roll!"months"(-14);
4327             assert(sysTime == SysTime(DateTime(-2001, 1, 3, 7, 7, 7), hnsecs(422202)));
4328         }
4329 
4330         // Test Both
4331         {
4332             auto sysTime = SysTime(Date(1, 1, 1));
4333             sysTime.roll!"months"(-1);
4334             assert(sysTime == SysTime(Date(1, 12, 1)));
4335             sysTime.roll!"months"(1);
4336             assert(sysTime == SysTime(Date(1, 1, 1)));
4337         }
4338 
4339         {
4340             auto sysTime = SysTime(Date(4, 1, 1));
4341             sysTime.roll!"months"(-48);
4342             assert(sysTime == SysTime(Date(4, 1, 1)));
4343             sysTime.roll!"months"(48);
4344             assert(sysTime == SysTime(Date(4, 1, 1)));
4345         }
4346 
4347         {
4348             auto sysTime = SysTime(Date(4, 3, 31));
4349             sysTime.roll!"months"(-49);
4350             assert(sysTime == SysTime(Date(4, 3, 2)));
4351             sysTime.roll!"months"(49);
4352             assert(sysTime == SysTime(Date(4, 4, 2)));
4353         }
4354 
4355         {
4356             auto sysTime = SysTime(Date(4, 3, 31));
4357             sysTime.roll!"months"(-85);
4358             assert(sysTime == SysTime(Date(4, 3, 2)));
4359             sysTime.roll!"months"(85);
4360             assert(sysTime == SysTime(Date(4, 4, 2)));
4361         }
4362 
4363         {
4364             auto sysTime = SysTime(Date(-1, 1, 1));
4365             sysTime.roll!"months"(-1);
4366             assert(sysTime == SysTime(Date(-1, 12, 1)));
4367             sysTime.roll!"months"(1);
4368             assert(sysTime == SysTime(Date(-1, 1, 1)));
4369         }
4370 
4371         {
4372             auto sysTime = SysTime(Date(-4, 1, 1));
4373             sysTime.roll!"months"(-48);
4374             assert(sysTime == SysTime(Date(-4, 1, 1)));
4375             sysTime.roll!"months"(48);
4376             assert(sysTime == SysTime(Date(-4, 1, 1)));
4377         }
4378 
4379         {
4380             auto sysTime = SysTime(Date(-4, 3, 31));
4381             sysTime.roll!"months"(-49);
4382             assert(sysTime == SysTime(Date(-4, 3, 2)));
4383             sysTime.roll!"months"(49);
4384             assert(sysTime == SysTime(Date(-4, 4, 2)));
4385         }
4386 
4387         {
4388             auto sysTime = SysTime(Date(-4, 3, 31));
4389             sysTime.roll!"months"(-85);
4390             assert(sysTime == SysTime(Date(-4, 3, 2)));
4391             sysTime.roll!"months"(85);
4392             assert(sysTime == SysTime(Date(-4, 4, 2)));
4393         }
4394 
4395         {
4396             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
4397             sysTime.roll!"months"(-1);
4398             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17)));
4399             sysTime.roll!"months"(1);
4400             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
4401         }
4402 
4403         {
4404             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
4405             sysTime.roll!"months"(-85);
4406             assert(sysTime == SysTime(DateTime(4, 3, 2, 12, 11, 10), msecs(9)));
4407             sysTime.roll!"months"(85);
4408             assert(sysTime == SysTime(DateTime(4, 4, 2, 12, 11, 10), msecs(9)));
4409         }
4410 
4411         {
4412             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4413             sysTime.roll!"months"(85);
4414             assert(sysTime == SysTime(DateTime(-3, 5, 1, 12, 11, 10), msecs(9)));
4415             sysTime.roll!"months"(-85);
4416             assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9)));
4417         }
4418 
4419         {
4420             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4421             sysTime.roll!"months"(85).roll!"months"(-83);
4422             assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), msecs(9)));
4423         }
4424 
4425         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4426         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4427         static assert(!__traits(compiles, cst.roll!"months"(4)));
4428         static assert(!__traits(compiles, ist.roll!"months"(4)));
4429 
4430         static void testScope(scope ref SysTime st) @safe
4431         {
4432             auto result = st.roll!"months"(42);
4433         }
4434     }
4435 
4436     // Test roll!"months"() with AllowDayOverflow.no
4437     @safe unittest
4438     {
4439         import core.time;
4440         // Test A.D.
4441         {
4442             auto sysTime = SysTime(Date(1999, 7, 6));
4443             sysTime.roll!"months"(3, AllowDayOverflow.no);
4444             assert(sysTime == SysTime(Date(1999, 10, 6)));
4445             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4446             assert(sysTime == SysTime(Date(1999, 6, 6)));
4447         }
4448 
4449         {
4450             auto sysTime = SysTime(Date(1999, 7, 6));
4451             sysTime.roll!"months"(6, AllowDayOverflow.no);
4452             assert(sysTime == SysTime(Date(1999, 1, 6)));
4453             sysTime.roll!"months"(-6, AllowDayOverflow.no);
4454             assert(sysTime == SysTime(Date(1999, 7, 6)));
4455         }
4456 
4457         {
4458             auto sysTime = SysTime(Date(1999, 7, 6));
4459             sysTime.roll!"months"(27, AllowDayOverflow.no);
4460             assert(sysTime == SysTime(Date(1999, 10, 6)));
4461             sysTime.roll!"months"(-28, AllowDayOverflow.no);
4462             assert(sysTime == SysTime(Date(1999, 6, 6)));
4463         }
4464 
4465         {
4466             auto sysTime = SysTime(Date(1999, 5, 31));
4467             sysTime.roll!"months"(1, AllowDayOverflow.no);
4468             assert(sysTime == SysTime(Date(1999, 6, 30)));
4469         }
4470 
4471         {
4472             auto sysTime = SysTime(Date(1999, 5, 31));
4473             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4474             assert(sysTime == SysTime(Date(1999, 4, 30)));
4475         }
4476 
4477         {
4478             auto sysTime = SysTime(Date(1999, 2, 28));
4479             sysTime.roll!"months"(12, AllowDayOverflow.no);
4480             assert(sysTime == SysTime(Date(1999, 2, 28)));
4481         }
4482 
4483         {
4484             auto sysTime = SysTime(Date(2000, 2, 29));
4485             sysTime.roll!"months"(12, AllowDayOverflow.no);
4486             assert(sysTime == SysTime(Date(2000, 2, 29)));
4487         }
4488 
4489         {
4490             auto sysTime = SysTime(Date(1999, 7, 31));
4491             sysTime.roll!"months"(1, AllowDayOverflow.no);
4492             assert(sysTime == SysTime(Date(1999, 8, 31)));
4493             sysTime.roll!"months"(1, AllowDayOverflow.no);
4494             assert(sysTime == SysTime(Date(1999, 9, 30)));
4495         }
4496 
4497         {
4498             auto sysTime = SysTime(Date(1998, 8, 31));
4499             sysTime.roll!"months"(13, AllowDayOverflow.no);
4500             assert(sysTime == SysTime(Date(1998, 9, 30)));
4501             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4502             assert(sysTime == SysTime(Date(1998, 8, 30)));
4503         }
4504 
4505         {
4506             auto sysTime = SysTime(Date(1997, 12, 31));
4507             sysTime.roll!"months"(13, AllowDayOverflow.no);
4508             assert(sysTime == SysTime(Date(1997, 1, 31)));
4509             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4510             assert(sysTime == SysTime(Date(1997, 12, 31)));
4511         }
4512 
4513         {
4514             auto sysTime = SysTime(Date(1997, 12, 31));
4515             sysTime.roll!"months"(14, AllowDayOverflow.no);
4516             assert(sysTime == SysTime(Date(1997, 2, 28)));
4517             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4518             assert(sysTime == SysTime(Date(1997, 12, 28)));
4519         }
4520 
4521         {
4522             auto sysTime = SysTime(Date(1998, 12, 31));
4523             sysTime.roll!"months"(14, AllowDayOverflow.no);
4524             assert(sysTime == SysTime(Date(1998, 2, 28)));
4525             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4526             assert(sysTime == SysTime(Date(1998, 12, 28)));
4527         }
4528 
4529         {
4530             auto sysTime = SysTime(Date(1999, 12, 31));
4531             sysTime.roll!"months"(14, AllowDayOverflow.no);
4532             assert(sysTime == SysTime(Date(1999, 2, 28)));
4533             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4534             assert(sysTime == SysTime(Date(1999, 12, 28)));
4535         }
4536 
4537         {
4538             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
4539             sysTime.roll!"months"(3, AllowDayOverflow.no);
4540             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
4541             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4542             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
4543         }
4544 
4545         {
4546             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
4547             sysTime.roll!"months"(14, AllowDayOverflow.no);
4548             assert(sysTime == SysTime(DateTime(1998, 2, 28, 7, 7, 7), hnsecs(422202)));
4549             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4550             assert(sysTime == SysTime(DateTime(1998, 12, 28, 7, 7, 7), hnsecs(422202)));
4551         }
4552 
4553         {
4554             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
4555             sysTime.roll!"months"(14, AllowDayOverflow.no);
4556             assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 7, 7), hnsecs(422202)));
4557             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4558             assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202)));
4559         }
4560 
4561         // Test B.C.
4562         {
4563             auto sysTime = SysTime(Date(-1999, 7, 6));
4564             sysTime.roll!"months"(3, AllowDayOverflow.no);
4565             assert(sysTime == SysTime(Date(-1999, 10, 6)));
4566             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4567             assert(sysTime == SysTime(Date(-1999, 6, 6)));
4568         }
4569 
4570         {
4571             auto sysTime = SysTime(Date(-1999, 7, 6));
4572             sysTime.roll!"months"(6, AllowDayOverflow.no);
4573             assert(sysTime == SysTime(Date(-1999, 1, 6)));
4574             sysTime.roll!"months"(-6, AllowDayOverflow.no);
4575             assert(sysTime == SysTime(Date(-1999, 7, 6)));
4576         }
4577 
4578         {
4579             auto sysTime = SysTime(Date(-1999, 7, 6));
4580             sysTime.roll!"months"(-27, AllowDayOverflow.no);
4581             assert(sysTime == SysTime(Date(-1999, 4, 6)));
4582             sysTime.roll!"months"(28, AllowDayOverflow.no);
4583             assert(sysTime == SysTime(Date(-1999, 8, 6)));
4584         }
4585 
4586         {
4587             auto sysTime = SysTime(Date(-1999, 5, 31));
4588             sysTime.roll!"months"(1, AllowDayOverflow.no);
4589             assert(sysTime == SysTime(Date(-1999, 6, 30)));
4590         }
4591 
4592         {
4593             auto sysTime = SysTime(Date(-1999, 5, 31));
4594             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4595             assert(sysTime == SysTime(Date(-1999, 4, 30)));
4596         }
4597 
4598         {
4599             auto sysTime = SysTime(Date(-1999, 2, 28));
4600             sysTime.roll!"months"(-12, AllowDayOverflow.no);
4601             assert(sysTime == SysTime(Date(-1999, 2, 28)));
4602         }
4603 
4604         {
4605             auto sysTime = SysTime(Date(-2000, 2, 29));
4606             sysTime.roll!"months"(-12, AllowDayOverflow.no);
4607             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4608         }
4609 
4610         {
4611             auto sysTime = SysTime(Date(-1999, 7, 31));
4612             sysTime.roll!"months"(1, AllowDayOverflow.no);
4613             assert(sysTime == SysTime(Date(-1999, 8, 31)));
4614             sysTime.roll!"months"(1, AllowDayOverflow.no);
4615             assert(sysTime == SysTime(Date(-1999, 9, 30)));
4616         }
4617 
4618         {
4619             auto sysTime = SysTime(Date(-1998, 8, 31));
4620             sysTime.roll!"months"(13, AllowDayOverflow.no);
4621             assert(sysTime == SysTime(Date(-1998, 9, 30)));
4622             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4623             assert(sysTime == SysTime(Date(-1998, 8, 30)));
4624         }
4625 
4626         {
4627             auto sysTime = SysTime(Date(-1997, 12, 31));
4628             sysTime.roll!"months"(13, AllowDayOverflow.no);
4629             assert(sysTime == SysTime(Date(-1997, 1, 31)));
4630             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4631             assert(sysTime == SysTime(Date(-1997, 12, 31)));
4632         }
4633 
4634         {
4635             auto sysTime = SysTime(Date(-1997, 12, 31));
4636             sysTime.roll!"months"(14, AllowDayOverflow.no);
4637             assert(sysTime == SysTime(Date(-1997, 2, 28)));
4638             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4639             assert(sysTime == SysTime(Date(-1997, 12, 28)));
4640         }
4641 
4642         {
4643             auto sysTime = SysTime(Date(-2002, 12, 31));
4644             sysTime.roll!"months"(14, AllowDayOverflow.no);
4645             assert(sysTime == SysTime(Date(-2002, 2, 28)));
4646             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4647             assert(sysTime == SysTime(Date(-2002, 12, 28)));
4648         }
4649 
4650         {
4651             auto sysTime = SysTime(Date(-2001, 12, 31));
4652             sysTime.roll!"months"(14, AllowDayOverflow.no);
4653             assert(sysTime == SysTime(Date(-2001, 2, 28)));
4654             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4655             assert(sysTime == SysTime(Date(-2001, 12, 28)));
4656         }
4657 
4658         {
4659             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
4660             sysTime.roll!"months"(3, AllowDayOverflow.no);
4661             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
4662             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4663             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
4664         }
4665 
4666         {
4667             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
4668             sysTime.roll!"months"(14, AllowDayOverflow.no);
4669             assert(sysTime == SysTime(DateTime(-2002, 2, 28, 7, 7, 7), hnsecs(422202)));
4670             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4671             assert(sysTime == SysTime(DateTime(-2002, 12, 28, 7, 7, 7), hnsecs(422202)));
4672         }
4673 
4674         {
4675             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
4676             sysTime.roll!"months"(14, AllowDayOverflow.no);
4677             assert(sysTime == SysTime(DateTime(-2001, 2, 28, 7, 7, 7), hnsecs(422202)));
4678             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4679             assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202)));
4680         }
4681 
4682         // Test Both
4683         {
4684             auto sysTime = SysTime(Date(1, 1, 1));
4685             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4686             assert(sysTime == SysTime(Date(1, 12, 1)));
4687             sysTime.roll!"months"(1, AllowDayOverflow.no);
4688             assert(sysTime == SysTime(Date(1, 1, 1)));
4689         }
4690 
4691         {
4692             auto sysTime = SysTime(Date(4, 1, 1));
4693             sysTime.roll!"months"(-48, AllowDayOverflow.no);
4694             assert(sysTime == SysTime(Date(4, 1, 1)));
4695             sysTime.roll!"months"(48, AllowDayOverflow.no);
4696             assert(sysTime == SysTime(Date(4, 1, 1)));
4697         }
4698 
4699         {
4700             auto sysTime = SysTime(Date(4, 3, 31));
4701             sysTime.roll!"months"(-49, AllowDayOverflow.no);
4702             assert(sysTime == SysTime(Date(4, 2, 29)));
4703             sysTime.roll!"months"(49, AllowDayOverflow.no);
4704             assert(sysTime == SysTime(Date(4, 3, 29)));
4705         }
4706 
4707         {
4708             auto sysTime = SysTime(Date(4, 3, 31));
4709             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4710             assert(sysTime == SysTime(Date(4, 2, 29)));
4711             sysTime.roll!"months"(85, AllowDayOverflow.no);
4712             assert(sysTime == SysTime(Date(4, 3, 29)));
4713         }
4714 
4715         {
4716             auto sysTime = SysTime(Date(-1, 1, 1));
4717             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4718             assert(sysTime == SysTime(Date(-1, 12, 1)));
4719             sysTime.roll!"months"(1, AllowDayOverflow.no);
4720             assert(sysTime == SysTime(Date(-1, 1, 1)));
4721         }
4722 
4723         {
4724             auto sysTime = SysTime(Date(-4, 1, 1));
4725             sysTime.roll!"months"(-48, AllowDayOverflow.no);
4726             assert(sysTime == SysTime(Date(-4, 1, 1)));
4727             sysTime.roll!"months"(48, AllowDayOverflow.no);
4728             assert(sysTime == SysTime(Date(-4, 1, 1)));
4729         }
4730 
4731         {
4732             auto sysTime = SysTime(Date(-4, 3, 31));
4733             sysTime.roll!"months"(-49, AllowDayOverflow.no);
4734             assert(sysTime == SysTime(Date(-4, 2, 29)));
4735             sysTime.roll!"months"(49, AllowDayOverflow.no);
4736             assert(sysTime == SysTime(Date(-4, 3, 29)));
4737         }
4738 
4739         {
4740             auto sysTime = SysTime(Date(-4, 3, 31));
4741             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4742             assert(sysTime == SysTime(Date(-4, 2, 29)));
4743             sysTime.roll!"months"(85, AllowDayOverflow.no);
4744             assert(sysTime == SysTime(Date(-4, 3, 29)));
4745         }
4746 
4747         {
4748             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
4749             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4750             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0)));
4751             sysTime.roll!"months"(1, AllowDayOverflow.no);
4752             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
4753         }
4754 
4755         {
4756             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
4757             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4758             assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4759             sysTime.roll!"months"(1, AllowDayOverflow.no);
4760             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4761         }
4762 
4763         {
4764             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
4765             sysTime.roll!"months"(1, AllowDayOverflow.no);
4766             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
4767             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4768             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
4769         }
4770 
4771         {
4772             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
4773             sysTime.roll!"months"(1, AllowDayOverflow.no);
4774             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4775             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4776             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4777         }
4778 
4779         {
4780             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
4781             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4782             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17)));
4783             sysTime.roll!"months"(1, AllowDayOverflow.no);
4784             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
4785         }
4786 
4787         {
4788             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
4789             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4790             assert(sysTime == SysTime(DateTime(4, 2, 29, 12, 11, 10), msecs(9)));
4791             sysTime.roll!"months"(85, AllowDayOverflow.no);
4792             assert(sysTime == SysTime(DateTime(4, 3, 29, 12, 11, 10), msecs(9)));
4793         }
4794 
4795         {
4796             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4797             sysTime.roll!"months"(85, AllowDayOverflow.no);
4798             assert(sysTime == SysTime(DateTime(-3, 4, 30, 12, 11, 10), msecs(9)));
4799             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4800             assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9)));
4801         }
4802 
4803         {
4804             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4805             sysTime.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no);
4806             assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9)));
4807         }
4808     }
4809 
4810 
4811     /++
4812         Adds the given number of units to this $(LREF SysTime). A negative number
4813         will subtract.
4814 
4815         The difference between rolling and adding is that rolling does not
4816         affect larger units. For instance, rolling a $(LREF SysTime) one
4817         year's worth of days gets the exact same $(LREF SysTime).
4818 
4819         Accepted units are `"days"`, `"minutes"`, `"hours"`,
4820         `"minutes"`, `"seconds"`, `"msecs"`, `"usecs"`, and
4821         `"hnsecs"`.
4822 
4823         Note that when rolling msecs, usecs or hnsecs, they all add up to a
4824         second. So, for example, rolling 1000 msecs is exactly the same as
4825         rolling 100,000 usecs.
4826 
4827         Params:
4828             units = The units to add.
4829             value = The number of $(D_PARAM units) to add to this
4830                     $(LREF SysTime).
4831       +/
4832     ref SysTime roll(string units)(long value) @safe nothrow scope
4833     if (units == "days")
4834     {
4835         auto hnsecs = adjTime;
4836         auto gdays = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
4837 
4838         if (hnsecs < 0)
4839         {
4840             hnsecs += convert!("hours", "hnsecs")(24);
4841             --gdays;
4842         }
4843 
4844         auto date = Date(cast(int) gdays);
4845         date.roll!"days"(value);
4846         gdays = date.dayOfGregorianCal - 1;
4847 
4848         if (gdays < 0)
4849         {
4850             hnsecs -= convert!("hours", "hnsecs")(24);
4851             ++gdays;
4852         }
4853 
4854         immutable newDaysHNSecs = convert!("days", "hnsecs")(gdays);
4855         adjTime = newDaysHNSecs + hnsecs;
4856         return  this;
4857     }
4858 
4859     ///
4860     @safe unittest
4861     {
4862         import core.time : msecs, hnsecs;
4863         import std.datetime.date : DateTime;
4864 
4865         auto st1 = SysTime(DateTime(2010, 1, 1, 11, 23, 12));
4866         st1.roll!"days"(1);
4867         assert(st1 == SysTime(DateTime(2010, 1, 2, 11, 23, 12)));
4868         st1.roll!"days"(365);
4869         assert(st1 == SysTime(DateTime(2010, 1, 26, 11, 23, 12)));
4870         st1.roll!"days"(-32);
4871         assert(st1 == SysTime(DateTime(2010, 1, 25, 11, 23, 12)));
4872 
4873         auto st2 = SysTime(DateTime(2010, 7, 4, 12, 0, 0));
4874         st2.roll!"hours"(1);
4875         assert(st2 == SysTime(DateTime(2010, 7, 4, 13, 0, 0)));
4876 
4877         auto st3 = SysTime(DateTime(2010, 2, 12, 12, 0, 0));
4878         st3.roll!"hours"(-1);
4879         assert(st3 == SysTime(DateTime(2010, 2, 12, 11, 0, 0)));
4880 
4881         auto st4 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
4882         st4.roll!"minutes"(1);
4883         assert(st4 == SysTime(DateTime(2009, 12, 31, 0, 1, 0)));
4884 
4885         auto st5 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
4886         st5.roll!"minutes"(-1);
4887         assert(st5 == SysTime(DateTime(2010, 1, 1, 0, 59, 0)));
4888 
4889         auto st6 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
4890         st6.roll!"seconds"(1);
4891         assert(st6 == SysTime(DateTime(2009, 12, 31, 0, 0, 1)));
4892 
4893         auto st7 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
4894         st7.roll!"seconds"(-1);
4895         assert(st7 == SysTime(DateTime(2010, 1, 1, 0, 0, 59)));
4896 
4897         auto dt = DateTime(2010, 1, 1, 0, 0, 0);
4898         auto st8 = SysTime(dt);
4899         st8.roll!"msecs"(1);
4900         assert(st8 == SysTime(dt, msecs(1)));
4901 
4902         auto st9 = SysTime(dt);
4903         st9.roll!"msecs"(-1);
4904         assert(st9 == SysTime(dt, msecs(999)));
4905 
4906         auto st10 = SysTime(dt);
4907         st10.roll!"hnsecs"(1);
4908         assert(st10 == SysTime(dt, hnsecs(1)));
4909 
4910         auto st11 = SysTime(dt);
4911         st11.roll!"hnsecs"(-1);
4912         assert(st11 == SysTime(dt, hnsecs(9_999_999)));
4913     }
4914 
4915     @safe unittest
4916     {
4917         import core.time;
4918         // Test A.D.
4919         {
4920             auto sysTime = SysTime(Date(1999, 2, 28));
4921             sysTime.roll!"days"(1);
4922             assert(sysTime == SysTime(Date(1999, 2, 1)));
4923             sysTime.roll!"days"(-1);
4924             assert(sysTime == SysTime(Date(1999, 2, 28)));
4925         }
4926 
4927         {
4928             auto sysTime = SysTime(Date(2000, 2, 28));
4929             sysTime.roll!"days"(1);
4930             assert(sysTime == SysTime(Date(2000, 2, 29)));
4931             sysTime.roll!"days"(1);
4932             assert(sysTime == SysTime(Date(2000, 2, 1)));
4933             sysTime.roll!"days"(-1);
4934             assert(sysTime == SysTime(Date(2000, 2, 29)));
4935         }
4936 
4937         {
4938             auto sysTime = SysTime(Date(1999, 6, 30));
4939             sysTime.roll!"days"(1);
4940             assert(sysTime == SysTime(Date(1999, 6, 1)));
4941             sysTime.roll!"days"(-1);
4942             assert(sysTime == SysTime(Date(1999, 6, 30)));
4943         }
4944 
4945         {
4946             auto sysTime = SysTime(Date(1999, 7, 31));
4947             sysTime.roll!"days"(1);
4948             assert(sysTime == SysTime(Date(1999, 7, 1)));
4949             sysTime.roll!"days"(-1);
4950             assert(sysTime == SysTime(Date(1999, 7, 31)));
4951         }
4952 
4953         {
4954             auto sysTime = SysTime(Date(1999, 1, 1));
4955             sysTime.roll!"days"(-1);
4956             assert(sysTime == SysTime(Date(1999, 1, 31)));
4957             sysTime.roll!"days"(1);
4958             assert(sysTime == SysTime(Date(1999, 1, 1)));
4959         }
4960 
4961         {
4962             auto sysTime = SysTime(Date(1999, 7, 6));
4963             sysTime.roll!"days"(9);
4964             assert(sysTime == SysTime(Date(1999, 7, 15)));
4965             sysTime.roll!"days"(-11);
4966             assert(sysTime == SysTime(Date(1999, 7, 4)));
4967             sysTime.roll!"days"(30);
4968             assert(sysTime == SysTime(Date(1999, 7, 3)));
4969             sysTime.roll!"days"(-3);
4970             assert(sysTime == SysTime(Date(1999, 7, 31)));
4971         }
4972 
4973         {
4974             auto sysTime = SysTime(Date(1999, 7, 6));
4975             sysTime.roll!"days"(365);
4976             assert(sysTime == SysTime(Date(1999, 7, 30)));
4977             sysTime.roll!"days"(-365);
4978             assert(sysTime == SysTime(Date(1999, 7, 6)));
4979             sysTime.roll!"days"(366);
4980             assert(sysTime == SysTime(Date(1999, 7, 31)));
4981             sysTime.roll!"days"(730);
4982             assert(sysTime == SysTime(Date(1999, 7, 17)));
4983             sysTime.roll!"days"(-1096);
4984             assert(sysTime == SysTime(Date(1999, 7, 6)));
4985         }
4986 
4987         {
4988             auto sysTime = SysTime(Date(1999, 2, 6));
4989             sysTime.roll!"days"(365);
4990             assert(sysTime == SysTime(Date(1999, 2, 7)));
4991             sysTime.roll!"days"(-365);
4992             assert(sysTime == SysTime(Date(1999, 2, 6)));
4993             sysTime.roll!"days"(366);
4994             assert(sysTime == SysTime(Date(1999, 2, 8)));
4995             sysTime.roll!"days"(730);
4996             assert(sysTime == SysTime(Date(1999, 2, 10)));
4997             sysTime.roll!"days"(-1096);
4998             assert(sysTime == SysTime(Date(1999, 2, 6)));
4999         }
5000 
5001         {
5002             auto sysTime = SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578));
5003             sysTime.roll!"days"(1);
5004             assert(sysTime == SysTime(DateTime(1999, 2, 1, 7, 9, 2), usecs(234578)));
5005             sysTime.roll!"days"(-1);
5006             assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578)));
5007         }
5008 
5009         {
5010             auto sysTime = SysTime(DateTime(1999, 7, 6, 7, 9, 2), usecs(234578));
5011             sysTime.roll!"days"(9);
5012             assert(sysTime == SysTime(DateTime(1999, 7, 15, 7, 9, 2), usecs(234578)));
5013             sysTime.roll!"days"(-11);
5014             assert(sysTime == SysTime(DateTime(1999, 7, 4, 7, 9, 2), usecs(234578)));
5015             sysTime.roll!"days"(30);
5016             assert(sysTime == SysTime(DateTime(1999, 7, 3, 7, 9, 2), usecs(234578)));
5017             sysTime.roll!"days"(-3);
5018             assert(sysTime == SysTime(DateTime(1999, 7, 31, 7, 9, 2), usecs(234578)));
5019         }
5020 
5021         // Test B.C.
5022         {
5023             auto sysTime = SysTime(Date(-1999, 2, 28));
5024             sysTime.roll!"days"(1);
5025             assert(sysTime == SysTime(Date(-1999, 2, 1)));
5026             sysTime.roll!"days"(-1);
5027             assert(sysTime == SysTime(Date(-1999, 2, 28)));
5028         }
5029 
5030         {
5031             auto sysTime = SysTime(Date(-2000, 2, 28));
5032             sysTime.roll!"days"(1);
5033             assert(sysTime == SysTime(Date(-2000, 2, 29)));
5034             sysTime.roll!"days"(1);
5035             assert(sysTime == SysTime(Date(-2000, 2, 1)));
5036             sysTime.roll!"days"(-1);
5037             assert(sysTime == SysTime(Date(-2000, 2, 29)));
5038         }
5039 
5040         {
5041             auto sysTime = SysTime(Date(-1999, 6, 30));
5042             sysTime.roll!"days"(1);
5043             assert(sysTime == SysTime(Date(-1999, 6, 1)));
5044             sysTime.roll!"days"(-1);
5045             assert(sysTime == SysTime(Date(-1999, 6, 30)));
5046         }
5047 
5048         {
5049             auto sysTime = SysTime(Date(-1999, 7, 31));
5050             sysTime.roll!"days"(1);
5051             assert(sysTime == SysTime(Date(-1999, 7, 1)));
5052             sysTime.roll!"days"(-1);
5053             assert(sysTime == SysTime(Date(-1999, 7, 31)));
5054         }
5055 
5056         {
5057             auto sysTime = SysTime(Date(-1999, 1, 1));
5058             sysTime.roll!"days"(-1);
5059             assert(sysTime == SysTime(Date(-1999, 1, 31)));
5060             sysTime.roll!"days"(1);
5061             assert(sysTime == SysTime(Date(-1999, 1, 1)));
5062         }
5063 
5064         {
5065             auto sysTime = SysTime(Date(-1999, 7, 6));
5066             sysTime.roll!"days"(9);
5067             assert(sysTime == SysTime(Date(-1999, 7, 15)));
5068             sysTime.roll!"days"(-11);
5069             assert(sysTime == SysTime(Date(-1999, 7, 4)));
5070             sysTime.roll!"days"(30);
5071             assert(sysTime == SysTime(Date(-1999, 7, 3)));
5072             sysTime.roll!"days"(-3);
5073             assert(sysTime == SysTime(Date(-1999, 7, 31)));
5074         }
5075 
5076         {
5077             auto sysTime = SysTime(Date(-1999, 7, 6));
5078             sysTime.roll!"days"(365);
5079             assert(sysTime == SysTime(Date(-1999, 7, 30)));
5080             sysTime.roll!"days"(-365);
5081             assert(sysTime == SysTime(Date(-1999, 7, 6)));
5082             sysTime.roll!"days"(366);
5083             assert(sysTime == SysTime(Date(-1999, 7, 31)));
5084             sysTime.roll!"days"(730);
5085             assert(sysTime == SysTime(Date(-1999, 7, 17)));
5086             sysTime.roll!"days"(-1096);
5087             assert(sysTime == SysTime(Date(-1999, 7, 6)));
5088         }
5089 
5090         {
5091             auto sysTime = SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578));
5092             sysTime.roll!"days"(1);
5093             assert(sysTime == SysTime(DateTime(-1999, 2, 1, 7, 9, 2), usecs(234578)));
5094             sysTime.roll!"days"(-1);
5095             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578)));
5096         }
5097 
5098         {
5099             auto sysTime = SysTime(DateTime(-1999, 7, 6, 7, 9, 2), usecs(234578));
5100             sysTime.roll!"days"(9);
5101             assert(sysTime == SysTime(DateTime(-1999, 7, 15, 7, 9, 2), usecs(234578)));
5102             sysTime.roll!"days"(-11);
5103             assert(sysTime == SysTime(DateTime(-1999, 7, 4, 7, 9, 2), usecs(234578)));
5104             sysTime.roll!"days"(30);
5105             assert(sysTime == SysTime(DateTime(-1999, 7, 3, 7, 9, 2), usecs(234578)));
5106             sysTime.roll!"days"(-3);
5107         }
5108 
5109         // Test Both
5110         {
5111             auto sysTime = SysTime(Date(1, 7, 6));
5112             sysTime.roll!"days"(-365);
5113             assert(sysTime == SysTime(Date(1, 7, 13)));
5114             sysTime.roll!"days"(365);
5115             assert(sysTime == SysTime(Date(1, 7, 6)));
5116             sysTime.roll!"days"(-731);
5117             assert(sysTime == SysTime(Date(1, 7, 19)));
5118             sysTime.roll!"days"(730);
5119             assert(sysTime == SysTime(Date(1, 7, 5)));
5120         }
5121 
5122         {
5123             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5124             sysTime.roll!"days"(-1);
5125             assert(sysTime == SysTime(DateTime(1, 1, 31, 0, 0, 0)));
5126             sysTime.roll!"days"(1);
5127             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5128         }
5129 
5130         {
5131             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
5132             sysTime.roll!"days"(-1);
5133             assert(sysTime == SysTime(DateTime(1, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
5134             sysTime.roll!"days"(1);
5135             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
5136         }
5137 
5138         {
5139             auto sysTime = SysTime(DateTime(0, 12, 31, 0, 0, 0));
5140             sysTime.roll!"days"(1);
5141             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
5142             sysTime.roll!"days"(-1);
5143             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0)));
5144         }
5145 
5146         {
5147             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5148             sysTime.roll!"days"(1);
5149             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
5150             sysTime.roll!"days"(-1);
5151             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5152         }
5153 
5154         {
5155             auto sysTime = SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22));
5156             sysTime.roll!"days"(-365);
5157             assert(sysTime == SysTime(DateTime(1, 7, 13, 13, 13, 9), msecs(22)));
5158             sysTime.roll!"days"(365);
5159             assert(sysTime == SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22)));
5160             sysTime.roll!"days"(-731);
5161             assert(sysTime == SysTime(DateTime(1, 7, 19, 13, 13, 9), msecs(22)));
5162             sysTime.roll!"days"(730);
5163             assert(sysTime == SysTime(DateTime(1, 7, 5, 13, 13, 9), msecs(22)));
5164         }
5165 
5166         {
5167             auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22));
5168             sysTime.roll!"days"(-365);
5169             assert(sysTime == SysTime(DateTime(0, 7, 13, 13, 13, 9), msecs(22)));
5170             sysTime.roll!"days"(365);
5171             assert(sysTime == SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22)));
5172             sysTime.roll!"days"(-731);
5173             assert(sysTime == SysTime(DateTime(0, 7, 19, 13, 13, 9), msecs(22)));
5174             sysTime.roll!"days"(730);
5175             assert(sysTime == SysTime(DateTime(0, 7, 5, 13, 13, 9), msecs(22)));
5176         }
5177 
5178         {
5179             auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22));
5180             sysTime.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730);
5181             assert(sysTime == SysTime(DateTime(0, 7, 8, 13, 13, 9), msecs(22)));
5182         }
5183 
5184         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5185         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5186         static assert(!__traits(compiles, cst.roll!"days"(4)));
5187         static assert(!__traits(compiles, ist.roll!"days"(4)));
5188 
5189         static void testScope(scope ref SysTime st) @safe
5190         {
5191             auto result = st.roll!"days"(42);
5192         }
5193     }
5194 
5195 
5196     // Shares documentation with "days" version.
5197     ref SysTime roll(string units)(long value) @safe nothrow scope
5198     if (units == "hours" || units == "minutes" || units == "seconds")
5199     {
5200         try
5201         {
5202             auto hnsecs = adjTime;
5203             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
5204 
5205             if (hnsecs < 0)
5206             {
5207                 hnsecs += convert!("hours", "hnsecs")(24);
5208                 --days;
5209             }
5210 
5211             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
5212             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
5213             immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
5214 
5215             auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
5216                                           cast(int) minute, cast(int) second));
5217             dateTime.roll!units(value);
5218             --days;
5219 
5220             hnsecs += convert!("hours", "hnsecs")(dateTime.hour);
5221             hnsecs += convert!("minutes", "hnsecs")(dateTime.minute);
5222             hnsecs += convert!("seconds", "hnsecs")(dateTime.second);
5223 
5224             if (days < 0)
5225             {
5226                 hnsecs -= convert!("hours", "hnsecs")(24);
5227                 ++days;
5228             }
5229 
5230             immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
5231             adjTime = newDaysHNSecs + hnsecs;
5232             return this;
5233         }
5234         catch (Exception e)
5235             assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw.");
5236     }
5237 
5238     // Test roll!"hours"().
5239     @safe unittest
5240     {
5241         import core.time;
5242         static void testST(SysTime orig, int hours, SysTime expected, size_t line = __LINE__) @safe
5243         {
5244             orig.roll!"hours"(hours);
5245             if (orig != expected)
5246                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5247         }
5248 
5249         // Test A.D.
5250         immutable d = msecs(45);
5251         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
5252         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5253         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
5254         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
5255         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d));
5256         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d));
5257         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d));
5258         testST(beforeAD, 6, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d));
5259         testST(beforeAD, 7, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d));
5260         testST(beforeAD, 8, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
5261         testST(beforeAD, 9, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d));
5262         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
5263         testST(beforeAD, 11, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5264         testST(beforeAD, 12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5265         testST(beforeAD, 13, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
5266         testST(beforeAD, 14, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d));
5267         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d));
5268         testST(beforeAD, 16, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
5269         testST(beforeAD, 17, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d));
5270         testST(beforeAD, 18, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d));
5271         testST(beforeAD, 19, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d));
5272         testST(beforeAD, 20, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d));
5273         testST(beforeAD, 21, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d));
5274         testST(beforeAD, 22, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
5275         testST(beforeAD, 23, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
5276         testST(beforeAD, 24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5277         testST(beforeAD, 25, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
5278         testST(beforeAD, 50, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
5279         testST(beforeAD, 10_000, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
5280 
5281         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
5282         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
5283         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d));
5284         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d));
5285         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d));
5286         testST(beforeAD, -6, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d));
5287         testST(beforeAD, -7, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d));
5288         testST(beforeAD, -8, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
5289         testST(beforeAD, -9, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d));
5290         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d));
5291         testST(beforeAD, -11, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
5292         testST(beforeAD, -12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5293         testST(beforeAD, -13, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5294         testST(beforeAD, -14, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
5295         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d));
5296         testST(beforeAD, -16, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
5297         testST(beforeAD, -17, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d));
5298         testST(beforeAD, -18, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d));
5299         testST(beforeAD, -19, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d));
5300         testST(beforeAD, -20, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d));
5301         testST(beforeAD, -21, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d));
5302         testST(beforeAD, -22, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
5303         testST(beforeAD, -23, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
5304         testST(beforeAD, -24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5305         testST(beforeAD, -25, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
5306         testST(beforeAD, -50, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
5307         testST(beforeAD, -10_000, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
5308 
5309         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
5310         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5311         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5312 
5313         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5314         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5315         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
5316 
5317         testST(SysTime(DateTime(1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 31, 0, 30, 33), d));
5318         testST(SysTime(DateTime(1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(1999, 8, 1, 23, 30, 33), d));
5319 
5320         testST(SysTime(DateTime(1999, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 12, 31, 0, 30, 33), d));
5321         testST(SysTime(DateTime(2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(2000, 1, 1, 23, 30, 33), d));
5322 
5323         testST(SysTime(DateTime(1999, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(1999, 2, 28, 0, 30, 33), d));
5324         testST(SysTime(DateTime(1999, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(1999, 3, 2, 23, 30, 33), d));
5325 
5326         testST(SysTime(DateTime(2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(2000, 2, 28, 0, 30, 33), d));
5327         testST(SysTime(DateTime(2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(2000, 3, 1, 23, 30, 33), d));
5328 
5329         // Test B.C.
5330         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5331         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5332         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
5333         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
5334         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d));
5335         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d));
5336         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d));
5337         testST(beforeBC, 6, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d));
5338         testST(beforeBC, 7, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d));
5339         testST(beforeBC, 8, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
5340         testST(beforeBC, 9, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d));
5341         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
5342         testST(beforeBC, 11, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5343         testST(beforeBC, 12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5344         testST(beforeBC, 13, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
5345         testST(beforeBC, 14, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d));
5346         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d));
5347         testST(beforeBC, 16, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
5348         testST(beforeBC, 17, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d));
5349         testST(beforeBC, 18, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d));
5350         testST(beforeBC, 19, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d));
5351         testST(beforeBC, 20, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d));
5352         testST(beforeBC, 21, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d));
5353         testST(beforeBC, 22, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
5354         testST(beforeBC, 23, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
5355         testST(beforeBC, 24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5356         testST(beforeBC, 25, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
5357         testST(beforeBC, 50, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
5358         testST(beforeBC, 10_000, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
5359 
5360         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
5361         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
5362         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d));
5363         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d));
5364         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d));
5365         testST(beforeBC, -6, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d));
5366         testST(beforeBC, -7, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d));
5367         testST(beforeBC, -8, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
5368         testST(beforeBC, -9, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d));
5369         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d));
5370         testST(beforeBC, -11, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
5371         testST(beforeBC, -12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5372         testST(beforeBC, -13, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5373         testST(beforeBC, -14, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
5374         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d));
5375         testST(beforeBC, -16, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
5376         testST(beforeBC, -17, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d));
5377         testST(beforeBC, -18, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d));
5378         testST(beforeBC, -19, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d));
5379         testST(beforeBC, -20, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d));
5380         testST(beforeBC, -21, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d));
5381         testST(beforeBC, -22, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
5382         testST(beforeBC, -23, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
5383         testST(beforeBC, -24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5384         testST(beforeBC, -25, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
5385         testST(beforeBC, -50, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
5386         testST(beforeBC, -10_000, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
5387 
5388         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
5389         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5390         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5391 
5392         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5393         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5394         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
5395 
5396         testST(SysTime(DateTime(-1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 31, 0, 30, 33), d));
5397         testST(SysTime(DateTime(-1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 8, 1, 23, 30, 33), d));
5398 
5399         testST(SysTime(DateTime(-2001, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(-2001, 12, 31, 0, 30, 33), d));
5400         testST(SysTime(DateTime(-2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(-2000, 1, 1, 23, 30, 33), d));
5401 
5402         testST(SysTime(DateTime(-2001, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2001, 2, 28, 0, 30, 33), d));
5403         testST(SysTime(DateTime(-2001, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(-2001, 3, 2, 23, 30, 33), d));
5404 
5405         testST(SysTime(DateTime(-2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2000, 2, 28, 0, 30, 33), d));
5406         testST(SysTime(DateTime(-2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(-2000, 3, 1, 23, 30, 33), d));
5407 
5408         // Test Both
5409         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 17_546, SysTime(DateTime(-1, 1, 1, 13, 30, 33), d));
5410         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -17_546, SysTime(DateTime(1, 1, 1, 11, 30, 33), d));
5411 
5412         {
5413             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5414             sysTime.roll!"hours"(-1);
5415             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 0, 0)));
5416             sysTime.roll!"hours"(1);
5417             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5418         }
5419 
5420         {
5421             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999));
5422             sysTime.roll!"hours"(-1);
5423             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
5424             sysTime.roll!"hours"(1);
5425             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999)));
5426         }
5427 
5428         {
5429             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 0, 0));
5430             sysTime.roll!"hours"(1);
5431             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0)));
5432             sysTime.roll!"hours"(-1);
5433             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5434         }
5435 
5436         {
5437             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5438             sysTime.roll!"hours"(1);
5439             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 59, 59), hnsecs(9_999_999)));
5440             sysTime.roll!"hours"(-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!"hours"(1).roll!"hours"(-67);
5447             assert(sysTime == SysTime(DateTime(0, 12, 31, 5, 59, 59), 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!"hours"(4)));
5453         static assert(!__traits(compiles, ist.roll!"hours"(4)));
5454 
5455         static void testScope(scope ref SysTime st) @safe
5456         {
5457             auto result = st.roll!"hours"(42);
5458         }
5459     }
5460 
5461     // Test roll!"minutes"().
5462     @safe unittest
5463     {
5464         import core.time;
5465         static void testST(SysTime orig, int minutes, SysTime expected, size_t line = __LINE__) @safe
5466         {
5467             orig.roll!"minutes"(minutes);
5468             if (orig != expected)
5469                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5470         }
5471 
5472         // Test A.D.
5473         immutable d = usecs(7203);
5474         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
5475         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5476         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5477         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 32, 33), d));
5478         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 33, 33), d));
5479         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 34, 33), d));
5480         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 35, 33), d));
5481         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 40, 33), d));
5482         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5483         testST(beforeAD, 29, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5484         testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5485         testST(beforeAD, 45, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5486         testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5487         testST(beforeAD, 75, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5488         testST(beforeAD, 90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5489         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 10, 33), d));
5490 
5491         testST(beforeAD, 689, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5492         testST(beforeAD, 690, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5493         testST(beforeAD, 691, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5494         testST(beforeAD, 960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5495         testST(beforeAD, 1439, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5496         testST(beforeAD, 1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5497         testST(beforeAD, 1441, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5498         testST(beforeAD, 2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5499 
5500         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5501         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 28, 33), d));
5502         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 27, 33), d));
5503         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 26, 33), d));
5504         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 25, 33), d));
5505         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 20, 33), d));
5506         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5507         testST(beforeAD, -29, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5508         testST(beforeAD, -30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5509         testST(beforeAD, -45, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5510         testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5511         testST(beforeAD, -75, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5512         testST(beforeAD, -90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5513         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 50, 33), d));
5514 
5515         testST(beforeAD, -749, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5516         testST(beforeAD, -750, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5517         testST(beforeAD, -751, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5518         testST(beforeAD, -960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5519         testST(beforeAD, -1439, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5520         testST(beforeAD, -1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5521         testST(beforeAD, -1441, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5522         testST(beforeAD, -2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5523 
5524         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5525         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5526         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5527 
5528         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(1999, 7, 6, 11, 0, 33), d));
5529         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(1999, 7, 6, 11, 59, 33), d));
5530         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(1999, 7, 6, 11, 58, 33), d));
5531 
5532         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 1, 33), d));
5533         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 33), d));
5534         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 0, 59, 33), d));
5535 
5536         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(1999, 7, 5, 23, 0, 33), d));
5537         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 33), d));
5538         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(1999, 7, 5, 23, 58, 33), d));
5539 
5540         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(1998, 12, 31, 23, 0, 33), d));
5541         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 33), d));
5542         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(1998, 12, 31, 23, 58, 33), d));
5543 
5544         // Test B.C.
5545         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5546         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5547         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5548         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 32, 33), d));
5549         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 33, 33), d));
5550         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 34, 33), d));
5551         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 35, 33), d));
5552         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 40, 33), d));
5553         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5554         testST(beforeBC, 29, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5555         testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5556         testST(beforeBC, 45, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5557         testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5558         testST(beforeBC, 75, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5559         testST(beforeBC, 90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5560         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 10, 33), d));
5561 
5562         testST(beforeBC, 689, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5563         testST(beforeBC, 690, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5564         testST(beforeBC, 691, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5565         testST(beforeBC, 960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5566         testST(beforeBC, 1439, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5567         testST(beforeBC, 1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5568         testST(beforeBC, 1441, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5569         testST(beforeBC, 2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5570 
5571         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5572         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 28, 33), d));
5573         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 27, 33), d));
5574         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 26, 33), d));
5575         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 25, 33), d));
5576         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 20, 33), d));
5577         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5578         testST(beforeBC, -29, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5579         testST(beforeBC, -30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5580         testST(beforeBC, -45, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5581         testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5582         testST(beforeBC, -75, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5583         testST(beforeBC, -90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5584         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 50, 33), d));
5585 
5586         testST(beforeBC, -749, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5587         testST(beforeBC, -750, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5588         testST(beforeBC, -751, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5589         testST(beforeBC, -960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5590         testST(beforeBC, -1439, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5591         testST(beforeBC, -1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5592         testST(beforeBC, -1441, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5593         testST(beforeBC, -2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5594 
5595         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5596         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5597         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5598 
5599         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 11, 0, 33), d));
5600         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d));
5601         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 11, 58, 33), d));
5602 
5603         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 1, 33), d));
5604         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d));
5605         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 59, 33), d));
5606 
5607         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 0, 33), d));
5608         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d));
5609         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 58, 33), d));
5610 
5611         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 0, 33), d));
5612         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d));
5613         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 58, 33), d));
5614 
5615         // Test Both
5616         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(1, 1, 1, 0, 59, 0)));
5617         testST(SysTime(DateTime(0, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5618 
5619         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(0, 1, 1, 0, 59, 0)));
5620         testST(SysTime(DateTime(-1, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(-1, 12, 31, 23, 0, 0)));
5621 
5622         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 1_052_760, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d));
5623         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -1_052_760, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5624 
5625         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 1_052_782, SysTime(DateTime(-1, 1, 1, 11, 52, 33), d));
5626         testST(SysTime(DateTime(1, 1, 1, 13, 52, 33), d), -1_052_782, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5627 
5628         {
5629             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5630             sysTime.roll!"minutes"(-1);
5631             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 0)));
5632             sysTime.roll!"minutes"(1);
5633             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5634         }
5635 
5636         {
5637             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999));
5638             sysTime.roll!"minutes"(-1);
5639             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999)));
5640             sysTime.roll!"minutes"(1);
5641             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999)));
5642         }
5643 
5644         {
5645             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 0));
5646             sysTime.roll!"minutes"(1);
5647             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5648             sysTime.roll!"minutes"(-1);
5649             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0)));
5650         }
5651 
5652         {
5653             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5654             sysTime.roll!"minutes"(1);
5655             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 59), hnsecs(9_999_999)));
5656             sysTime.roll!"minutes"(-1);
5657             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5658         }
5659 
5660         {
5661             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5662             sysTime.roll!"minutes"(1).roll!"minutes"(-79);
5663             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 41, 59), hnsecs(9_999_999)));
5664         }
5665 
5666         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5667         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5668         static assert(!__traits(compiles, cst.roll!"minutes"(4)));
5669         static assert(!__traits(compiles, ist.roll!"minutes"(4)));
5670 
5671         static void testScope(scope ref SysTime st) @safe
5672         {
5673             auto result = st.roll!"minutes"(42);
5674         }
5675     }
5676 
5677     // Test roll!"seconds"().
5678     @safe unittest
5679     {
5680         import core.time;
5681         static void testST(SysTime orig, int seconds, SysTime expected, size_t line = __LINE__) @safe
5682         {
5683             orig.roll!"seconds"(seconds);
5684             if (orig != expected)
5685                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5686         }
5687 
5688         // Test A.D.
5689         immutable d = msecs(274);
5690         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
5691         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5692         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5693         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 35), d));
5694         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 30, 36), d));
5695         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 30, 37), d));
5696         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 30, 38), d));
5697         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 43), d));
5698         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 30, 48), d));
5699         testST(beforeAD, 26, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5700         testST(beforeAD, 27, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5701         testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 30, 3), d));
5702         testST(beforeAD, 59, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5703         testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5704         testST(beforeAD, 61, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5705 
5706         testST(beforeAD, 1766, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5707         testST(beforeAD, 1767, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5708         testST(beforeAD, 1768, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d));
5709         testST(beforeAD, 2007, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5710         testST(beforeAD, 3599, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5711         testST(beforeAD, 3600, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5712         testST(beforeAD, 3601, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5713         testST(beforeAD, 7200, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5714 
5715         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5716         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 31), d));
5717         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 30, 30), d));
5718         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 30, 29), d));
5719         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 30, 28), d));
5720         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 23), d));
5721         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 30, 18), d));
5722         testST(beforeAD, -33, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5723         testST(beforeAD, -34, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5724         testST(beforeAD, -35, SysTime(DateTime(1999, 7, 6, 12, 30, 58), d));
5725         testST(beforeAD, -59, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5726         testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5727         testST(beforeAD, -61, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5728 
5729         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d));
5730         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5731         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5732 
5733         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 0, 1), d));
5734         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 0), d));
5735         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 0, 59), d));
5736 
5737         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 0, 0, 1), d));
5738         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 0), d));
5739         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 0, 0, 59), d));
5740 
5741         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(1999, 7, 5, 23, 59, 0), d));
5742         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 59), d));
5743         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(1999, 7, 5, 23, 59, 58), d));
5744 
5745         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(1998, 12, 31, 23, 59, 0), d));
5746         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 59), d));
5747         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(1998, 12, 31, 23, 59, 58), d));
5748 
5749         // Test B.C.
5750         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5751         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5752         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5753         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 35), d));
5754         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 30, 36), d));
5755         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 30, 37), d));
5756         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 30, 38), d));
5757         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 43), d));
5758         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 30, 48), d));
5759         testST(beforeBC, 26, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5760         testST(beforeBC, 27, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5761         testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 30, 3), d));
5762         testST(beforeBC, 59, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5763         testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5764         testST(beforeBC, 61, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5765 
5766         testST(beforeBC, 1766, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5767         testST(beforeBC, 1767, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5768         testST(beforeBC, 1768, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d));
5769         testST(beforeBC, 2007, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5770         testST(beforeBC, 3599, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5771         testST(beforeBC, 3600, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5772         testST(beforeBC, 3601, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5773         testST(beforeBC, 7200, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5774 
5775         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5776         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 31), d));
5777         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 30, 30), d));
5778         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 30, 29), d));
5779         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 30, 28), d));
5780         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 23), d));
5781         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 30, 18), d));
5782         testST(beforeBC, -33, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5783         testST(beforeBC, -34, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5784         testST(beforeBC, -35, SysTime(DateTime(-1999, 7, 6, 12, 30, 58), d));
5785         testST(beforeBC, -59, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5786         testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5787         testST(beforeBC, -61, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5788 
5789         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d));
5790         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5791         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5792 
5793         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 0, 1), d));
5794         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d));
5795         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 0, 59), d));
5796 
5797         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 0, 1), d));
5798         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d));
5799         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 0, 59), d));
5800 
5801         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 59, 0), d));
5802         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d));
5803         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 59, 58), d));
5804 
5805         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 59, 0), d));
5806         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d));
5807         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 59, 58), d));
5808 
5809         // Test Both
5810         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(1, 1, 1, 0, 0, 59), d));
5811         testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(0, 12, 31, 23, 59, 0), d));
5812 
5813         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(0, 1, 1, 0, 0, 59), d));
5814         testST(SysTime(DateTime(-1, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-1, 12, 31, 23, 59, 0), d));
5815 
5816         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_600L, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d));
5817         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -63_165_600L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5818 
5819         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_617L, SysTime(DateTime(-1, 1, 1, 11, 30, 50), d));
5820         testST(SysTime(DateTime(1, 1, 1, 13, 30, 50), d), -63_165_617L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5821 
5822         {
5823             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5824             sysTime.roll!"seconds"(-1);
5825             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59)));
5826             sysTime.roll!"seconds"(1);
5827             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5828         }
5829 
5830         {
5831             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999));
5832             sysTime.roll!"seconds"(-1);
5833             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999)));
5834             sysTime.roll!"seconds"(1);
5835             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
5836         }
5837 
5838         {
5839             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59));
5840             sysTime.roll!"seconds"(1);
5841             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0)));
5842             sysTime.roll!"seconds"(-1);
5843             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59)));
5844         }
5845 
5846         {
5847             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5848             sysTime.roll!"seconds"(1);
5849             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0), hnsecs(9_999_999)));
5850             sysTime.roll!"seconds"(-1);
5851             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5852         }
5853 
5854         {
5855             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5856             sysTime.roll!"seconds"(1).roll!"seconds"(-102);
5857             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 18), hnsecs(9_999_999)));
5858         }
5859 
5860         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5861         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5862         static assert(!__traits(compiles, cst.roll!"seconds"(4)));
5863         static assert(!__traits(compiles, ist.roll!"seconds"(4)));
5864 
5865         static void testScope(scope ref SysTime st) @safe
5866         {
5867             auto result = st.roll!"seconds"(42);
5868         }
5869     }
5870 
5871 
5872     // Shares documentation with "days" version.
5873     ref SysTime roll(string units)(long value) @safe nothrow scope
5874     if (units == "msecs" || units == "usecs" || units == "hnsecs")
5875     {
5876         auto hnsecs = adjTime;
5877         immutable days = splitUnitsFromHNSecs!"days"(hnsecs);
5878         immutable negative = hnsecs < 0;
5879 
5880         if (negative)
5881             hnsecs += convert!("hours", "hnsecs")(24);
5882 
5883         immutable seconds = splitUnitsFromHNSecs!"seconds"(hnsecs);
5884         hnsecs += convert!(units, "hnsecs")(value);
5885         hnsecs %= convert!("seconds", "hnsecs")(1);
5886 
5887         if (hnsecs < 0)
5888             hnsecs += convert!("seconds", "hnsecs")(1);
5889         hnsecs += convert!("seconds", "hnsecs")(seconds);
5890 
5891         if (negative)
5892             hnsecs -= convert!("hours", "hnsecs")(24);
5893 
5894         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
5895         adjTime = newDaysHNSecs + hnsecs;
5896         return this;
5897     }
5898 
5899 
5900     // Test roll!"msecs"().
5901     @safe unittest
5902     {
5903         import core.time;
5904         static void testST(SysTime orig, int milliseconds, SysTime expected, size_t line = __LINE__) @safe
5905         {
5906             orig.roll!"msecs"(milliseconds);
5907             if (orig != expected)
5908                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5909         }
5910 
5911         // Test A.D.
5912         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274));
5913         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5914         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275)));
5915         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(276)));
5916         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(284)));
5917         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(374)));
5918         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5919         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5920         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5921         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275)));
5922         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5923         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5924         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5925         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(1)));
5926         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5927         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5928 
5929         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273)));
5930         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(272)));
5931         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(264)));
5932         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(174)));
5933         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5934         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5935         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5936         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273)));
5937         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5938         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5939         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5940         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5941         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5942 
5943         // Test B.C.
5944         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274));
5945         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5946         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275)));
5947         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(276)));
5948         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(284)));
5949         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(374)));
5950         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5951         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5952         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5953         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275)));
5954         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5955         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5956         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5957         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(1)));
5958         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5959         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5960 
5961         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273)));
5962         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(272)));
5963         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(264)));
5964         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(174)));
5965         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5966         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5967         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5968         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273)));
5969         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5970         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5971         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5972         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5973         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5974 
5975         // Test Both
5976         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5977         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(1)));
5978         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5979         testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(999)));
5980         testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(998)));
5981         testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5982         testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5983         testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(445)));
5984 
5985         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5986         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_989_999)));
5987         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5988         testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999)));
5989         testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999)));
5990         testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5991         testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5992         testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(5_549_999)));
5993 
5994         {
5995             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5996             st.roll!"msecs"(1202).roll!"msecs"(-703);
5997             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(4_989_999)));
5998         }
5999 
6000         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6001         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6002         static assert(!__traits(compiles, cst.roll!"msecs"(4)));
6003         static assert(!__traits(compiles, ist.roll!"msecs"(4)));
6004 
6005         static void testScope(scope ref SysTime st) @safe
6006         {
6007             auto result = st.roll!"msecs"(42);
6008         }
6009     }
6010 
6011     // Test roll!"usecs"().
6012     @safe unittest
6013     {
6014         import core.time;
6015         static void testST(SysTime orig, long microseconds, SysTime expected, size_t line = __LINE__) @safe
6016         {
6017             orig.roll!"usecs"(microseconds);
6018             if (orig != expected)
6019                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
6020         }
6021 
6022         // Test A.D.
6023         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274));
6024         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6025         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(275)));
6026         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(276)));
6027         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(284)));
6028         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(374)));
6029         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999)));
6030         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1000)));
6031         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1274)));
6032         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1275)));
6033         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(2274)));
6034         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(26_999)));
6035         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_000)));
6036         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_001)));
6037         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(766_999)));
6038         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(767_000)));
6039         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6040         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6041         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6042 
6043         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(273)));
6044         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(272)));
6045         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(264)));
6046         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(174)));
6047         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
6048         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_999)));
6049         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_274)));
6050         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_273)));
6051         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(998_274)));
6052         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(967_000)));
6053         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(966_999)));
6054         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(167_000)));
6055         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(166_999)));
6056         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6057         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6058         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6059 
6060         // Test B.C.
6061         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274));
6062         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6063         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(275)));
6064         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(276)));
6065         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(284)));
6066         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(374)));
6067         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999)));
6068         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1000)));
6069         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1274)));
6070         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1275)));
6071         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(2274)));
6072         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(26_999)));
6073         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_000)));
6074         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_001)));
6075         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(766_999)));
6076         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(767_000)));
6077         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6078         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6079         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6080 
6081         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(273)));
6082         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(272)));
6083         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(264)));
6084         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(174)));
6085         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6086         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_999)));
6087         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_274)));
6088         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_273)));
6089         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(998_274)));
6090         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(967_000)));
6091         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(966_999)));
6092         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(167_000)));
6093         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(166_999)));
6094         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6095         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6096         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6097 
6098         // Test Both
6099         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6100         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(1)));
6101         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6102         testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_999)));
6103         testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_998)));
6104         testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_000)));
6105         testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(998_000)));
6106         testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(997_445)));
6107         testST(beforeBoth1, -1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6108         testST(beforeBoth1, -2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6109         testST(beforeBoth1, -2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(666_667)));
6110 
6111         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6112         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_989)));
6113         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6114         testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9)));
6115         testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19)));
6116         testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999)));
6117         testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999)));
6118         testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(25_549)));
6119         testST(beforeBoth2, 1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6120         testST(beforeBoth2, 2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6121         testST(beforeBoth2, 2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(3_333_329)));
6122 
6123         {
6124             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6125             st.roll!"usecs"(9_020_027);
6126             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(200_269)));
6127         }
6128 
6129         {
6130             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6131             st.roll!"usecs"(9_020_027).roll!"usecs"(-70_034);
6132             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_499_929)));
6133         }
6134 
6135         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6136         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6137         static assert(!__traits(compiles, cst.roll!"usecs"(4)));
6138         static assert(!__traits(compiles, ist.roll!"usecs"(4)));
6139 
6140         static void testScope(scope ref SysTime st) @safe
6141         {
6142             auto result = st.roll!"usecs"(42);
6143         }
6144     }
6145 
6146     // Test roll!"hnsecs"().
6147     @safe unittest
6148     {
6149         import core.time;
6150         static void testST(SysTime orig, long hnsecs, SysTime expected, size_t line = __LINE__) @safe
6151         {
6152             orig.roll!"hnsecs"(hnsecs);
6153             if (orig != expected)
6154                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
6155         }
6156 
6157         // Test A.D.
6158         auto dtAD = DateTime(1999, 7, 6, 12, 30, 33);
6159         auto beforeAD = SysTime(dtAD, hnsecs(274));
6160         testST(beforeAD, 0, SysTime(dtAD, hnsecs(274)));
6161         testST(beforeAD, 1, SysTime(dtAD, hnsecs(275)));
6162         testST(beforeAD, 2, SysTime(dtAD, hnsecs(276)));
6163         testST(beforeAD, 10, SysTime(dtAD, hnsecs(284)));
6164         testST(beforeAD, 100, SysTime(dtAD, hnsecs(374)));
6165         testST(beforeAD, 725, SysTime(dtAD, hnsecs(999)));
6166         testST(beforeAD, 726, SysTime(dtAD, hnsecs(1000)));
6167         testST(beforeAD, 1000, SysTime(dtAD, hnsecs(1274)));
6168         testST(beforeAD, 1001, SysTime(dtAD, hnsecs(1275)));
6169         testST(beforeAD, 2000, SysTime(dtAD, hnsecs(2274)));
6170         testST(beforeAD, 26_725, SysTime(dtAD, hnsecs(26_999)));
6171         testST(beforeAD, 26_726, SysTime(dtAD, hnsecs(27_000)));
6172         testST(beforeAD, 26_727, SysTime(dtAD, hnsecs(27_001)));
6173         testST(beforeAD, 1_766_725, SysTime(dtAD, hnsecs(1_766_999)));
6174         testST(beforeAD, 1_766_726, SysTime(dtAD, hnsecs(1_767_000)));
6175         testST(beforeAD, 1_000_000, SysTime(dtAD, hnsecs(1_000_274)));
6176         testST(beforeAD, 60_000_000L, SysTime(dtAD, hnsecs(274)));
6177         testST(beforeAD, 3_600_000_000L, SysTime(dtAD, hnsecs(274)));
6178         testST(beforeAD, 600_000_000L, SysTime(dtAD, hnsecs(274)));
6179         testST(beforeAD, 36_000_000_000L, SysTime(dtAD, hnsecs(274)));
6180 
6181         testST(beforeAD, -1, SysTime(dtAD, hnsecs(273)));
6182         testST(beforeAD, -2, SysTime(dtAD, hnsecs(272)));
6183         testST(beforeAD, -10, SysTime(dtAD, hnsecs(264)));
6184         testST(beforeAD, -100, SysTime(dtAD, hnsecs(174)));
6185         testST(beforeAD, -274, SysTime(dtAD));
6186         testST(beforeAD, -275, SysTime(dtAD, hnsecs(9_999_999)));
6187         testST(beforeAD, -1000, SysTime(dtAD, hnsecs(9_999_274)));
6188         testST(beforeAD, -1001, SysTime(dtAD, hnsecs(9_999_273)));
6189         testST(beforeAD, -2000, SysTime(dtAD, hnsecs(9_998_274)));
6190         testST(beforeAD, -33_274, SysTime(dtAD, hnsecs(9_967_000)));
6191         testST(beforeAD, -33_275, SysTime(dtAD, hnsecs(9_966_999)));
6192         testST(beforeAD, -1_833_274, SysTime(dtAD, hnsecs(8_167_000)));
6193         testST(beforeAD, -1_833_275, SysTime(dtAD, hnsecs(8_166_999)));
6194         testST(beforeAD, -1_000_000, SysTime(dtAD, hnsecs(9_000_274)));
6195         testST(beforeAD, -60_000_000L, SysTime(dtAD, hnsecs(274)));
6196         testST(beforeAD, -3_600_000_000L, SysTime(dtAD, hnsecs(274)));
6197         testST(beforeAD, -600_000_000L, SysTime(dtAD, hnsecs(274)));
6198         testST(beforeAD, -36_000_000_000L, SysTime(dtAD, hnsecs(274)));
6199 
6200         // Test B.C.
6201         auto dtBC = DateTime(-1999, 7, 6, 12, 30, 33);
6202         auto beforeBC = SysTime(dtBC, hnsecs(274));
6203         testST(beforeBC, 0, SysTime(dtBC, hnsecs(274)));
6204         testST(beforeBC, 1, SysTime(dtBC, hnsecs(275)));
6205         testST(beforeBC, 2, SysTime(dtBC, hnsecs(276)));
6206         testST(beforeBC, 10, SysTime(dtBC, hnsecs(284)));
6207         testST(beforeBC, 100, SysTime(dtBC, hnsecs(374)));
6208         testST(beforeBC, 725, SysTime(dtBC, hnsecs(999)));
6209         testST(beforeBC, 726, SysTime(dtBC, hnsecs(1000)));
6210         testST(beforeBC, 1000, SysTime(dtBC, hnsecs(1274)));
6211         testST(beforeBC, 1001, SysTime(dtBC, hnsecs(1275)));
6212         testST(beforeBC, 2000, SysTime(dtBC, hnsecs(2274)));
6213         testST(beforeBC, 26_725, SysTime(dtBC, hnsecs(26_999)));
6214         testST(beforeBC, 26_726, SysTime(dtBC, hnsecs(27_000)));
6215         testST(beforeBC, 26_727, SysTime(dtBC, hnsecs(27_001)));
6216         testST(beforeBC, 1_766_725, SysTime(dtBC, hnsecs(1_766_999)));
6217         testST(beforeBC, 1_766_726, SysTime(dtBC, hnsecs(1_767_000)));
6218         testST(beforeBC, 1_000_000, SysTime(dtBC, hnsecs(1_000_274)));
6219         testST(beforeBC, 60_000_000L, SysTime(dtBC, hnsecs(274)));
6220         testST(beforeBC, 3_600_000_000L, SysTime(dtBC, hnsecs(274)));
6221         testST(beforeBC, 600_000_000L, SysTime(dtBC, hnsecs(274)));
6222         testST(beforeBC, 36_000_000_000L, SysTime(dtBC, hnsecs(274)));
6223 
6224         testST(beforeBC, -1, SysTime(dtBC, hnsecs(273)));
6225         testST(beforeBC, -2, SysTime(dtBC, hnsecs(272)));
6226         testST(beforeBC, -10, SysTime(dtBC, hnsecs(264)));
6227         testST(beforeBC, -100, SysTime(dtBC, hnsecs(174)));
6228         testST(beforeBC, -274, SysTime(dtBC));
6229         testST(beforeBC, -275, SysTime(dtBC, hnsecs(9_999_999)));
6230         testST(beforeBC, -1000, SysTime(dtBC, hnsecs(9_999_274)));
6231         testST(beforeBC, -1001, SysTime(dtBC, hnsecs(9_999_273)));
6232         testST(beforeBC, -2000, SysTime(dtBC, hnsecs(9_998_274)));
6233         testST(beforeBC, -33_274, SysTime(dtBC, hnsecs(9_967_000)));
6234         testST(beforeBC, -33_275, SysTime(dtBC, hnsecs(9_966_999)));
6235         testST(beforeBC, -1_833_274, SysTime(dtBC, hnsecs(8_167_000)));
6236         testST(beforeBC, -1_833_275, SysTime(dtBC, hnsecs(8_166_999)));
6237         testST(beforeBC, -1_000_000, SysTime(dtBC, hnsecs(9_000_274)));
6238         testST(beforeBC, -60_000_000L, SysTime(dtBC, hnsecs(274)));
6239         testST(beforeBC, -3_600_000_000L, SysTime(dtBC, hnsecs(274)));
6240         testST(beforeBC, -600_000_000L, SysTime(dtBC, hnsecs(274)));
6241         testST(beforeBC, -36_000_000_000L, SysTime(dtBC, hnsecs(274)));
6242 
6243         // Test Both
6244         auto dtBoth1 = DateTime(1, 1, 1, 0, 0, 0);
6245         auto beforeBoth1 = SysTime(dtBoth1);
6246         testST(beforeBoth1, 1, SysTime(dtBoth1, hnsecs(1)));
6247         testST(beforeBoth1, 0, SysTime(dtBoth1));
6248         testST(beforeBoth1, -1, SysTime(dtBoth1, hnsecs(9_999_999)));
6249         testST(beforeBoth1, -2, SysTime(dtBoth1, hnsecs(9_999_998)));
6250         testST(beforeBoth1, -1000, SysTime(dtBoth1, hnsecs(9_999_000)));
6251         testST(beforeBoth1, -2000, SysTime(dtBoth1, hnsecs(9_998_000)));
6252         testST(beforeBoth1, -2555, SysTime(dtBoth1, hnsecs(9_997_445)));
6253         testST(beforeBoth1, -1_000_000, SysTime(dtBoth1, hnsecs(9_000_000)));
6254         testST(beforeBoth1, -2_000_000, SysTime(dtBoth1, hnsecs(8_000_000)));
6255         testST(beforeBoth1, -2_333_333, SysTime(dtBoth1, hnsecs(7_666_667)));
6256         testST(beforeBoth1, -10_000_000, SysTime(dtBoth1));
6257         testST(beforeBoth1, -20_000_000, SysTime(dtBoth1));
6258         testST(beforeBoth1, -20_888_888, SysTime(dtBoth1, hnsecs(9_111_112)));
6259 
6260         auto dtBoth2 = DateTime(0, 12, 31, 23, 59, 59);
6261         auto beforeBoth2 = SysTime(dtBoth2, hnsecs(9_999_999));
6262         testST(beforeBoth2, -1, SysTime(dtBoth2, hnsecs(9_999_998)));
6263         testST(beforeBoth2, 0, SysTime(dtBoth2, hnsecs(9_999_999)));
6264         testST(beforeBoth2, 1, SysTime(dtBoth2));
6265         testST(beforeBoth2, 2, SysTime(dtBoth2, hnsecs(1)));
6266         testST(beforeBoth2, 1000, SysTime(dtBoth2, hnsecs(999)));
6267         testST(beforeBoth2, 2000, SysTime(dtBoth2, hnsecs(1999)));
6268         testST(beforeBoth2, 2555, SysTime(dtBoth2, hnsecs(2554)));
6269         testST(beforeBoth2, 1_000_000, SysTime(dtBoth2, hnsecs(999_999)));
6270         testST(beforeBoth2, 2_000_000, SysTime(dtBoth2, hnsecs(1_999_999)));
6271         testST(beforeBoth2, 2_333_333, SysTime(dtBoth2, hnsecs(2_333_332)));
6272         testST(beforeBoth2, 10_000_000, SysTime(dtBoth2, hnsecs(9_999_999)));
6273         testST(beforeBoth2, 20_000_000, SysTime(dtBoth2, hnsecs(9_999_999)));
6274         testST(beforeBoth2, 20_888_888, SysTime(dtBoth2, hnsecs(888_887)));
6275 
6276         {
6277             auto st = SysTime(dtBoth2, hnsecs(9_999_999));
6278             st.roll!"hnsecs"(70_777_222).roll!"hnsecs"(-222_555_292);
6279             assert(st == SysTime(dtBoth2, hnsecs(8_221_929)));
6280         }
6281 
6282         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6283         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6284         static assert(!__traits(compiles, cst.roll!"hnsecs"(4)));
6285         static assert(!__traits(compiles, ist.roll!"hnsecs"(4)));
6286 
6287         static void testScope(scope ref SysTime st) @safe
6288         {
6289             auto result = st.roll!"hnsecs"(42);
6290         }
6291     }
6292 
6293 
6294     /++
6295         Gives the result of adding or subtracting a $(REF Duration, core,time)
6296         from this $(LREF SysTime).
6297 
6298         The legal types of arithmetic for $(LREF SysTime) using this operator
6299         are
6300 
6301         $(BOOKTABLE,
6302         $(TR $(TD SysTime) $(TD +) $(TD Duration) $(TD -->) $(TD SysTime))
6303         $(TR $(TD SysTime) $(TD -) $(TD Duration) $(TD -->) $(TD SysTime))
6304         $(TR $(TD Duration) $(TD +) $(TD SysTime) $(TD -->) $(TD SysTime))
6305         )
6306 
6307         Params:
6308             duration = The $(REF Duration, core,time) to add to or subtract from
6309                        this $(LREF SysTime).
6310       +/
6311     SysTime opBinary(string op)(Duration duration) @safe const pure nothrow return scope
6312     if (op == "+" || op == "-")
6313     {
6314         SysTime retval = SysTime(this._stdTime, this._timezone);
6315         immutable hnsecs = duration.total!"hnsecs";
6316         mixin("retval._stdTime " ~ op ~ "= hnsecs;");
6317         return retval;
6318     }
6319 
6320     /// ditto
6321     SysTime opBinaryRight(string op)(Duration duration) const @safe pure nothrow
6322     if (op == "+")
6323     {
6324         return this + duration;
6325     }
6326 
6327     ///
6328     @safe unittest
6329     {
6330         import core.time : hours, seconds;
6331         import std.datetime.date : DateTime;
6332 
6333         assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + seconds(1) ==
6334                SysTime(DateTime(2016, 1, 1, 0, 0, 0)));
6335 
6336         assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + hours(1) ==
6337                SysTime(DateTime(2016, 1, 1, 0, 59, 59)));
6338 
6339         assert(SysTime(DateTime(2016, 1, 1, 0, 0, 0)) - seconds(1) ==
6340                SysTime(DateTime(2015, 12, 31, 23, 59, 59)));
6341 
6342         assert(SysTime(DateTime(2016, 1, 1, 0, 59, 59)) - hours(1) ==
6343                SysTime(DateTime(2015, 12, 31, 23, 59, 59)));
6344 
6345         assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + seconds(1) ==
6346                seconds(1) + SysTime(DateTime(2015, 12, 31, 23, 59, 59)));
6347     }
6348 
6349     @safe unittest
6350     {
6351         import core.time;
6352         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_678));
6353 
6354         assert(st + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
6355         assert(st + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
6356         assert(st + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
6357         assert(st + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
6358         assert(st + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
6359         assert(st + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
6360         assert(st + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
6361         assert(st + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
6362         assert(st + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
6363         assert(st + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
6364         assert(st + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
6365         assert(st + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
6366         assert(st + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
6367         assert(st + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
6368         assert(st + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
6369         assert(st + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671)));
6370 
6371         assert(st - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
6372         assert(st - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
6373         assert(st - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
6374         assert(st - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
6375         assert(st - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
6376         assert(st - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
6377         assert(st - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
6378         assert(st - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
6379         assert(st - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
6380         assert(st - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
6381         assert(st - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
6382         assert(st - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
6383         assert(st - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
6384         assert(st - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
6385         assert(st - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
6386         assert(st - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671)));
6387 
6388         static void testST(SysTime orig, long hnsecs, SysTime expected, size_t line = __LINE__) @safe
6389         {
6390             auto result = orig + dur!"hnsecs"(hnsecs);
6391             if (result != expected)
6392                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", result, expected), __FILE__, line);
6393         }
6394 
6395         // Test A.D.
6396         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
6397         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
6398         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
6399         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
6400         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
6401         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
6402         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
6403         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6404         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6405         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6406         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6407         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6408         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6409         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6410         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6411         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6412         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6413         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
6414         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
6415         testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
6416         testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
6417 
6418         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
6419         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
6420         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
6421         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
6422         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
6423         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6424         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6425         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6426         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6427         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6428         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6429         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6430         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6431         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6432         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
6433         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
6434         testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
6435         testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
6436 
6437         // Test B.C.
6438         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
6439         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
6440         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
6441         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
6442         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
6443         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
6444         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
6445         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6446         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6447         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6448         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6449         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6450         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6451         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6452         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6453         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6454         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6455         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
6456         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
6457         testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
6458         testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
6459 
6460         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
6461         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
6462         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
6463         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
6464         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6465         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6466         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6467         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6468         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6469         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6470         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6471         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6472         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6473         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6474         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
6475         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
6476         testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
6477         testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
6478 
6479         // Test Both
6480         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6481         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6482         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6483         testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6484         testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6485         testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
6486         testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
6487         testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
6488         testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
6489         testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
6490         testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
6491         testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6492         testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
6493         testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
6494 
6495         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6496         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6497         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6498         testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6499         testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6500         testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
6501         testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
6502         testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
6503         testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
6504         testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
6505         testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
6506         testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6507         testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
6508         testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887)));
6509 
6510         auto duration = dur!"seconds"(12);
6511         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6512         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6513         assert(cst + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45)));
6514         assert(ist + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45)));
6515         assert(cst - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21)));
6516         assert(ist - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21)));
6517 
6518         static void testScope(scope ref SysTime st, scope ref Duration d) @safe
6519         {
6520             auto result = st + d;
6521         }
6522     }
6523 
6524 
6525     /++
6526         Gives the result of adding or subtracting a $(REF Duration, core,time) from
6527         this $(LREF SysTime), as well as assigning the result to this
6528         $(LREF SysTime).
6529 
6530         The legal types of arithmetic for $(LREF SysTime) using this operator are
6531 
6532         $(BOOKTABLE,
6533         $(TR $(TD SysTime) $(TD +) $(TD Duration) $(TD -->) $(TD SysTime))
6534         $(TR $(TD SysTime) $(TD -) $(TD Duration) $(TD -->) $(TD SysTime))
6535         )
6536 
6537         Params:
6538             duration = The $(REF Duration, core,time) to add to or subtract from
6539                        this $(LREF SysTime).
6540       +/
6541     ref SysTime opOpAssign(string op)(Duration duration) @safe pure nothrow scope
6542     if (op == "+" || op == "-")
6543     {
6544         immutable hnsecs = duration.total!"hnsecs";
6545         mixin("_stdTime " ~ op ~ "= hnsecs;");
6546         return this;
6547     }
6548 
6549     @safe unittest
6550     {
6551         import core.time;
6552         auto before = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6553         assert(before + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
6554         assert(before + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
6555         assert(before + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
6556         assert(before + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
6557 
6558         assert(before + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
6559         assert(before + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
6560         assert(before + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
6561         assert(before + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
6562         assert(before + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
6563         assert(before + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
6564         assert(before + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
6565         assert(before + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
6566         assert(before + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
6567         assert(before + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
6568         assert(before + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
6569         assert(before + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
6570 
6571         assert(before - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
6572         assert(before - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
6573         assert(before - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
6574         assert(before - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
6575 
6576         assert(before - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
6577         assert(before - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
6578         assert(before - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
6579         assert(before - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
6580         assert(before - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
6581         assert(before - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
6582         assert(before - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
6583         assert(before - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
6584         assert(before - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
6585         assert(before - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
6586         assert(before - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
6587         assert(before - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
6588 
6589         static void testST(SysTime orig, long hnsecs, SysTime expected, size_t line = __LINE__) @safe
6590         {
6591             auto r = orig += dur!"hnsecs"(hnsecs);
6592             if (orig != expected)
6593                 throw new AssertError(format("Failed 1. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
6594             if (r != expected)
6595                 throw new AssertError(format("Failed 2. actual [%s] != expected [%s]", r, expected), __FILE__, line);
6596         }
6597 
6598         // Test A.D.
6599         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
6600         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
6601         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
6602         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
6603         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
6604         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
6605         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
6606         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6607         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6608         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6609         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6610         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6611         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6612         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6613         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6614         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6615         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6616         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
6617         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
6618         testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
6619         testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
6620 
6621         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
6622         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
6623         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
6624         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
6625         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
6626         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6627         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6628         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6629         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6630         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6631         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6632         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6633         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6634         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6635         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
6636         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
6637         testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
6638         testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
6639 
6640         // Test B.C.
6641         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
6642         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
6643         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
6644         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
6645         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
6646         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
6647         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
6648         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6649         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6650         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6651         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6652         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6653         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6654         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6655         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6656         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6657         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6658         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
6659         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
6660         testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
6661         testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
6662 
6663         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
6664         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
6665         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
6666         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
6667         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6668         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6669         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6670         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6671         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6672         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6673         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6674         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6675         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6676         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6677         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
6678         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
6679         testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
6680         testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
6681 
6682         // Test Both
6683         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6684         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6685         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6686         testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6687         testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6688         testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
6689         testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
6690         testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
6691         testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
6692         testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
6693         testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
6694         testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6695         testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
6696         testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
6697 
6698         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6699         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6700         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6701         testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6702         testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6703         testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
6704         testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
6705         testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
6706         testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
6707         testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
6708         testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
6709         testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6710         testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
6711         testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887)));
6712 
6713         {
6714             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6715             (st += dur!"hnsecs"(52)) += dur!"seconds"(-907);
6716             assert(st == SysTime(DateTime(0, 12, 31, 23, 44, 53), hnsecs(51)));
6717         }
6718 
6719         auto duration = dur!"seconds"(12);
6720         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6721         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6722         static assert(!__traits(compiles, cst += duration));
6723         static assert(!__traits(compiles, ist += duration));
6724         static assert(!__traits(compiles, cst -= duration));
6725         static assert(!__traits(compiles, ist -= duration));
6726 
6727         static void testScope(scope ref SysTime st, scope ref Duration d) @safe
6728         {
6729             auto result1 = st += d;
6730             auto result2 = st -= d;
6731         }
6732     }
6733 
6734 
6735     /++
6736         Gives the difference between two $(LREF SysTime)s.
6737 
6738         The legal types of arithmetic for $(LREF SysTime) using this operator
6739         are
6740 
6741         $(BOOKTABLE,
6742         $(TR $(TD SysTime) $(TD -) $(TD SysTime) $(TD -->) $(TD duration))
6743         )
6744       +/
6745     Duration opBinary(string op)(SysTime rhs) @safe const pure nothrow scope
6746     if (op == "-")
6747     {
6748         return dur!"hnsecs"(_stdTime - rhs._stdTime);
6749     }
6750 
6751     @safe unittest
6752     {
6753         import core.time;
6754         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1998, 7, 6, 12, 30, 33)) ==
6755                dur!"seconds"(31_536_000));
6756         assert(SysTime(DateTime(1998, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6757                dur!"seconds"(-31_536_000));
6758 
6759         assert(SysTime(DateTime(1999, 8, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6760                dur!"seconds"(26_78_400));
6761         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 8, 6, 12, 30, 33)) ==
6762                dur!"seconds"(-26_78_400));
6763 
6764         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 5, 12, 30, 33)) ==
6765                dur!"seconds"(86_400));
6766         assert(SysTime(DateTime(1999, 7, 5, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6767                dur!"seconds"(-86_400));
6768 
6769         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 11, 30, 33)) ==
6770                dur!"seconds"(3600));
6771         assert(SysTime(DateTime(1999, 7, 6, 11, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6772                dur!"seconds"(-3600));
6773 
6774         assert(SysTime(DateTime(1999, 7, 6, 12, 31, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6775                dur!"seconds"(60));
6776         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 31, 33)) ==
6777                dur!"seconds"(-60));
6778 
6779         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 34)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6780                dur!"seconds"(1));
6781         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 34)) ==
6782                dur!"seconds"(-1));
6783 
6784         {
6785             auto dt = DateTime(1999, 7, 6, 12, 30, 33);
6786             assert(SysTime(dt, msecs(532)) - SysTime(dt) == msecs(532));
6787             assert(SysTime(dt) - SysTime(dt, msecs(532)) == msecs(-532));
6788 
6789             assert(SysTime(dt, usecs(333_347)) - SysTime(dt) == usecs(333_347));
6790             assert(SysTime(dt) - SysTime(dt, usecs(333_347)) == usecs(-333_347));
6791 
6792             assert(SysTime(dt, hnsecs(1_234_567)) - SysTime(dt) == hnsecs(1_234_567));
6793             assert(SysTime(dt) - SysTime(dt, hnsecs(1_234_567)) == hnsecs(-1_234_567));
6794         }
6795 
6796         assert(SysTime(DateTime(1, 1, 1, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(45033));
6797         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(1, 1, 1, 12, 30, 33)) == dur!"seconds"(-45033));
6798         assert(SysTime(DateTime(0, 12, 31, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(-41367));
6799         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 12, 30, 33)) == dur!"seconds"(41367));
6800 
6801         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) ==
6802                dur!"hnsecs"(1));
6803         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) ==
6804                dur!"hnsecs"(-1));
6805 
6806         version (Posix)
6807         {
6808             import std.datetime.timezone : PosixTimeZone;
6809             immutable tz = PosixTimeZone.getTimeZone("America/Los_Angeles");
6810         }
6811         else version (Windows)
6812         {
6813             import std.datetime.timezone : WindowsTimeZone;
6814             immutable tz = WindowsTimeZone.getTimeZone("Pacific Standard Time");
6815         }
6816 
6817         {
6818             auto dt = DateTime(2011, 1, 13, 8, 17, 2);
6819             auto d = msecs(296);
6820             assert(SysTime(dt, d, tz) - SysTime(dt, d, tz) == Duration.zero);
6821             assert(SysTime(dt, d, tz) - SysTime(dt, d, UTC()) == hours(8));
6822             assert(SysTime(dt, d, UTC()) - SysTime(dt, d, tz) == hours(-8));
6823         }
6824 
6825         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6826         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6827         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6828         assert(st - st == Duration.zero);
6829         assert(cst - st == Duration.zero);
6830         assert(ist - st == Duration.zero);
6831 
6832         assert(st - cst == Duration.zero);
6833         assert(cst - cst == Duration.zero);
6834         assert(ist - cst == Duration.zero);
6835 
6836         assert(st - ist == Duration.zero);
6837         assert(cst - ist == Duration.zero);
6838         assert(ist - ist == Duration.zero);
6839 
6840         static void testScope(scope ref SysTime left, scope ref SysTime right) @safe
6841         {
6842             auto result = left - right;
6843         }
6844     }
6845 
6846 
6847     /++
6848         Returns the difference between the two $(LREF SysTime)s in months.
6849 
6850         To get the difference in years, subtract the year property
6851         of two $(LREF SysTime)s. To get the difference in days or weeks,
6852         subtract the $(LREF SysTime)s themselves and use the
6853         $(REF Duration, core,time) that results. Because converting between
6854         months and smaller units requires a specific date (which
6855         $(REF Duration, core,time)s don't have), getting the difference in
6856         months requires some math using both the year and month properties, so
6857         this is a convenience function for getting the difference in months.
6858 
6859         Note that the number of days in the months or how far into the month
6860         either date is is irrelevant. It is the difference in the month property
6861         combined with the difference in years * 12. So, for instance,
6862         December 31st and January 1st are one month apart just as December 1st
6863         and January 31st are one month apart.
6864 
6865         Params:
6866             rhs = The $(LREF SysTime) to subtract from this one.
6867       +/
6868     int diffMonths(scope SysTime rhs) @safe const nothrow scope
6869     {
6870         return (cast(Date) this).diffMonths(cast(Date) rhs);
6871     }
6872 
6873     ///
6874     @safe unittest
6875     {
6876         import core.time;
6877         import std.datetime.date : Date;
6878 
6879         assert(SysTime(Date(1999, 2, 1)).diffMonths(
6880                    SysTime(Date(1999, 1, 31))) == 1);
6881 
6882         assert(SysTime(Date(1999, 1, 31)).diffMonths(
6883                    SysTime(Date(1999, 2, 1))) == -1);
6884 
6885         assert(SysTime(Date(1999, 3, 1)).diffMonths(
6886                    SysTime(Date(1999, 1, 1))) == 2);
6887 
6888         assert(SysTime(Date(1999, 1, 1)).diffMonths(
6889                    SysTime(Date(1999, 3, 31))) == -2);
6890     }
6891 
6892     @safe unittest
6893     {
6894         import core.time;
6895         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6896         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6897         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6898         assert(st.diffMonths(st) == 0);
6899         assert(cst.diffMonths(st) == 0);
6900         assert(ist.diffMonths(st) == 0);
6901 
6902         assert(st.diffMonths(cst) == 0);
6903         assert(cst.diffMonths(cst) == 0);
6904         assert(ist.diffMonths(cst) == 0);
6905 
6906         assert(st.diffMonths(ist) == 0);
6907         assert(cst.diffMonths(ist) == 0);
6908         assert(ist.diffMonths(ist) == 0);
6909 
6910         static void testScope(scope ref SysTime left, scope ref SysTime right) @safe
6911         {
6912             auto result = left.diffMonths(right);
6913         }
6914     }
6915 
6916 
6917     /++
6918         Whether this $(LREF SysTime) is in a leap year.
6919      +/
6920     @property bool isLeapYear() @safe const nothrow scope
6921     {
6922         return (cast(Date) this).isLeapYear;
6923     }
6924 
6925     @safe unittest
6926     {
6927         import core.time;
6928         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6929         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6930         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6931         assert(!st.isLeapYear);
6932         assert(!cst.isLeapYear);
6933         assert(!ist.isLeapYear);
6934 
6935         static void testScope(scope ref SysTime st) @safe
6936         {
6937             auto result = st.isLeapYear;
6938         }
6939     }
6940 
6941 
6942     /++
6943         Day of the week this $(LREF SysTime) is on.
6944       +/
6945     @property DayOfWeek dayOfWeek() @safe const nothrow scope
6946     {
6947         return getDayOfWeek(dayOfGregorianCal);
6948     }
6949 
6950     @safe unittest
6951     {
6952         import core.time;
6953         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6954         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6955         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6956         assert(st.dayOfWeek == DayOfWeek.tue);
6957         assert(cst.dayOfWeek == DayOfWeek.tue);
6958         assert(ist.dayOfWeek == DayOfWeek.tue);
6959 
6960         static void testScope(scope ref SysTime st) @safe
6961         {
6962             auto result = st.dayOfWeek;
6963         }
6964     }
6965 
6966 
6967     /++
6968         Day of the year this $(LREF SysTime) is on.
6969       +/
6970     @property ushort dayOfYear() @safe const nothrow scope
6971     {
6972         return (cast(Date) this).dayOfYear;
6973     }
6974 
6975     ///
6976     @safe unittest
6977     {
6978         import core.time;
6979         import std.datetime.date : DateTime;
6980 
6981         assert(SysTime(DateTime(1999, 1, 1, 12, 22, 7)).dayOfYear == 1);
6982         assert(SysTime(DateTime(1999, 12, 31, 7, 2, 59)).dayOfYear == 365);
6983         assert(SysTime(DateTime(2000, 12, 31, 21, 20, 0)).dayOfYear == 366);
6984     }
6985 
6986     @safe unittest
6987     {
6988         import core.time;
6989         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6990         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6991         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6992         assert(st.dayOfYear == 187);
6993         assert(cst.dayOfYear == 187);
6994         assert(ist.dayOfYear == 187);
6995 
6996         static void testScope(scope ref SysTime st) @safe
6997         {
6998             auto result = st.dayOfYear;
6999         }
7000     }
7001 
7002 
7003     /++
7004         Day of the year.
7005 
7006         Params:
7007             day = The day of the year to set which day of the year this
7008                   $(LREF SysTime) is on.
7009       +/
7010     @property void dayOfYear(int day) @safe scope
7011     {
7012         immutable hnsecs = adjTime;
7013         immutable days = convert!("hnsecs", "days")(hnsecs);
7014         immutable theRest = hnsecs - convert!("days", "hnsecs")(days);
7015 
7016         auto date = Date(cast(int) days);
7017         date.dayOfYear = day;
7018 
7019         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
7020 
7021         adjTime = newDaysHNSecs + theRest;
7022     }
7023 
7024     @safe unittest
7025     {
7026         import core.time;
7027         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7028         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7029         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7030         st.dayOfYear = 12;
7031         assert(st.dayOfYear == 12);
7032         static assert(!__traits(compiles, cst.dayOfYear = 12));
7033         static assert(!__traits(compiles, ist.dayOfYear = 12));
7034 
7035         static void testScope(scope ref SysTime st) @safe
7036         {
7037             st.dayOfYear = 42;
7038         }
7039     }
7040 
7041 
7042     /++
7043         The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on.
7044      +/
7045     @property int dayOfGregorianCal() @safe const nothrow scope
7046     {
7047         immutable adjustedTime = adjTime;
7048 
7049         // We have to add one because 0 would be midnight, January 1st, 1 A.D.,
7050         // which would be the 1st day of the Gregorian Calendar, not the 0th. So,
7051         // simply casting to days is one day off.
7052         if (adjustedTime > 0)
7053             return cast(int) getUnitsFromHNSecs!"days"(adjustedTime) + 1;
7054 
7055         long hnsecs = adjustedTime;
7056         immutable days = cast(int) splitUnitsFromHNSecs!"days"(hnsecs);
7057 
7058         return hnsecs == 0 ? days + 1 : days;
7059     }
7060 
7061     ///
7062     @safe unittest
7063     {
7064         import core.time;
7065         import std.datetime.date : DateTime;
7066 
7067         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
7068         assert(SysTime(DateTime(1, 12, 31, 23, 59, 59)).dayOfGregorianCal == 365);
7069         assert(SysTime(DateTime(2, 1, 1, 2, 2, 2)).dayOfGregorianCal == 366);
7070 
7071         assert(SysTime(DateTime(0, 12, 31, 7, 7, 7)).dayOfGregorianCal == 0);
7072         assert(SysTime(DateTime(0, 1, 1, 19, 30, 0)).dayOfGregorianCal == -365);
7073         assert(SysTime(DateTime(-1, 12, 31, 4, 7, 0)).dayOfGregorianCal == -366);
7074 
7075         assert(SysTime(DateTime(2000, 1, 1, 9, 30, 20)).dayOfGregorianCal == 730_120);
7076         assert(SysTime(DateTime(2010, 12, 31, 15, 45, 50)).dayOfGregorianCal == 734_137);
7077     }
7078 
7079     @safe unittest
7080     {
7081         import core.time;
7082         // Test A.D.
7083         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
7084         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 1);
7085         assert(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 1);
7086 
7087         assert(SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1);
7088         assert(SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)).dayOfGregorianCal == 2);
7089         assert(SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 32);
7090         assert(SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 366);
7091         assert(SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 731);
7092         assert(SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1096);
7093         assert(SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1462);
7094         assert(SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 17_898);
7095         assert(SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 35_065);
7096         assert(SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_160);
7097         assert(SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_525);
7098         assert(SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 37_986);
7099         assert(SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 72_684);
7100         assert(SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 73_049);
7101         assert(SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_208);
7102         assert(SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_573);
7103         assert(SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 145_732);
7104         assert(SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 146_098);
7105         assert(SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_257);
7106         assert(SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_622);
7107         assert(SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 364_878);
7108         assert(SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 365_243);
7109         assert(SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_023);
7110         assert(SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_389);
7111         assert(SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_596);
7112         assert(SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_961);
7113         assert(SysTime(DateTime(1945, 11, 12, 12, 2, 9), msecs(212)).dayOfGregorianCal == 710_347);
7114         assert(SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 729_755);
7115         assert(SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_120);
7116         assert(SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_486);
7117 
7118         assert(SysTime(DateTime(2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_773);
7119         assert(SysTime(DateTime(2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_803);
7120         assert(SysTime(DateTime(2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_804);
7121         assert(SysTime(DateTime(2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_831);
7122         assert(SysTime(DateTime(2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_832);
7123         assert(SysTime(DateTime(2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_862);
7124         assert(SysTime(DateTime(2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_863);
7125         assert(SysTime(DateTime(2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_892);
7126         assert(SysTime(DateTime(2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_893);
7127         assert(SysTime(DateTime(2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_923);
7128         assert(SysTime(DateTime(2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_924);
7129         assert(SysTime(DateTime(2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_953);
7130         assert(SysTime(DateTime(2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_954);
7131         assert(SysTime(DateTime(2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_984);
7132         assert(SysTime(DateTime(2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_985);
7133         assert(SysTime(DateTime(2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_015);
7134         assert(SysTime(DateTime(2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_016);
7135         assert(SysTime(DateTime(2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_045);
7136         assert(SysTime(DateTime(2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_046);
7137         assert(SysTime(DateTime(2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_076);
7138         assert(SysTime(DateTime(2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_077);
7139         assert(SysTime(DateTime(2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_106);
7140         assert(SysTime(DateTime(2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_107);
7141         assert(SysTime(DateTime(2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_137);
7142 
7143         assert(SysTime(DateTime(2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == 734_534);
7144         assert(SysTime(DateTime(2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == 734_561);
7145         assert(SysTime(DateTime(2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == 734_562);
7146         assert(SysTime(DateTime(2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == 734_563);
7147 
7148         // Test B.C.
7149         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 0);
7150         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == 0);
7151         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59)).dayOfGregorianCal == 0);
7152         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 0);
7153         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).dayOfGregorianCal == 0);
7154 
7155         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == -366);
7156         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == -366);
7157         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59)).dayOfGregorianCal == -366);
7158         assert(SysTime(DateTime(-1, 12, 31, 0, 0, 0)).dayOfGregorianCal == -366);
7159 
7160         assert(SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == 0);
7161         assert(SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1);
7162         assert(SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -30);
7163         assert(SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -31);
7164 
7165         assert(SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -366);
7166         assert(SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -367);
7167         assert(SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730);
7168         assert(SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731);
7169         assert(SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1095);
7170         assert(SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1096);
7171         assert(SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1460);
7172         assert(SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1461);
7173         assert(SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1826);
7174         assert(SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1827);
7175         assert(SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -2191);
7176         assert(SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -3652);
7177 
7178         assert(SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_262);
7179         assert(SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_627);
7180         assert(SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -35_794);
7181         assert(SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_160);
7182         assert(SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_524);
7183         assert(SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_889);
7184         assert(SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -37_254);
7185         assert(SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -38_715);
7186         assert(SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_413);
7187         assert(SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_778);
7188         assert(SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -109_937);
7189         assert(SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -110_302);
7190         assert(SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_097);
7191         assert(SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_462);
7192         assert(SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_827);
7193         assert(SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_621);
7194         assert(SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_986);
7195         assert(SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -183_351);
7196         assert(SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_607);
7197         assert(SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_972);
7198         assert(SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_387);
7199         assert(SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_388);
7200         assert(SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_753);
7201         assert(SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -585_118);
7202         assert(SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_325);
7203         assert(SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_690);
7204         assert(SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_484);
7205         assert(SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_485);
7206         assert(SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_850);
7207         assert(SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731_215);
7208 
7209         assert(SysTime(DateTime(-2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_502);
7210         assert(SysTime(DateTime(-2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_472);
7211         assert(SysTime(DateTime(-2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_471);
7212         assert(SysTime(DateTime(-2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_444);
7213         assert(SysTime(DateTime(-2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_443);
7214         assert(SysTime(DateTime(-2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_413);
7215         assert(SysTime(DateTime(-2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_412);
7216         assert(SysTime(DateTime(-2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_383);
7217         assert(SysTime(DateTime(-2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_382);
7218         assert(SysTime(DateTime(-2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_352);
7219         assert(SysTime(DateTime(-2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_351);
7220         assert(SysTime(DateTime(-2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_322);
7221         assert(SysTime(DateTime(-2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_321);
7222         assert(SysTime(DateTime(-2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_291);
7223         assert(SysTime(DateTime(-2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_290);
7224         assert(SysTime(DateTime(-2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_260);
7225         assert(SysTime(DateTime(-2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_259);
7226         assert(SysTime(DateTime(-2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_230);
7227         assert(SysTime(DateTime(-2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_229);
7228         assert(SysTime(DateTime(-2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_199);
7229         assert(SysTime(DateTime(-2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_198);
7230         assert(SysTime(DateTime(-2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_169);
7231         assert(SysTime(DateTime(-2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_168);
7232         assert(SysTime(DateTime(-2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_138);
7233 
7234         assert(SysTime(DateTime(-2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == -735_202);
7235         assert(SysTime(DateTime(-2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == -735_175);
7236         assert(SysTime(DateTime(-2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == -735_174);
7237         assert(SysTime(DateTime(-2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == -735_173);
7238 
7239         // Start of Hebrew Calendar
7240         assert(SysTime(DateTime(-3760, 9, 7, 0, 0, 0)).dayOfGregorianCal == -1_373_427);
7241 
7242         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7243         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7244         assert(cst.dayOfGregorianCal == 729_941);
7245         assert(ist.dayOfGregorianCal == 729_941);
7246 
7247         static void testScope(scope ref SysTime st) @safe
7248         {
7249             auto result = st.dayOfGregorianCal;
7250         }
7251     }
7252 
7253 
7254     // Test that the logic for the day of the Gregorian Calendar is consistent
7255     // between Date and SysTime.
7256     @safe unittest
7257     {
7258         import core.time;
7259         void test(Date date, SysTime st, size_t line = __LINE__)
7260         {
7261             if (date.dayOfGregorianCal != st.dayOfGregorianCal)
7262             {
7263                 throw new AssertError(format("Date [%s] SysTime [%s]", date.dayOfGregorianCal, st.dayOfGregorianCal),
7264                                       __FILE__, line);
7265             }
7266         }
7267 
7268         // Test A.D.
7269         test(Date(1, 1, 1), SysTime(DateTime(1, 1, 1, 0, 0, 0)));
7270         test(Date(1, 1, 2), SysTime(DateTime(1, 1, 2, 0, 0, 0), hnsecs(500)));
7271         test(Date(1, 2, 1), SysTime(DateTime(1, 2, 1, 0, 0, 0), hnsecs(50_000)));
7272         test(Date(2, 1, 1), SysTime(DateTime(2, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7273         test(Date(3, 1, 1), SysTime(DateTime(3, 1, 1, 12, 13, 14)));
7274         test(Date(4, 1, 1), SysTime(DateTime(4, 1, 1, 12, 13, 14), hnsecs(500)));
7275         test(Date(5, 1, 1), SysTime(DateTime(5, 1, 1, 12, 13, 14), hnsecs(50_000)));
7276         test(Date(50, 1, 1), SysTime(DateTime(50, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7277         test(Date(97, 1, 1), SysTime(DateTime(97, 1, 1, 23, 59, 59)));
7278         test(Date(100, 1, 1), SysTime(DateTime(100, 1, 1, 23, 59, 59), hnsecs(500)));
7279         test(Date(101, 1, 1), SysTime(DateTime(101, 1, 1, 23, 59, 59), hnsecs(50_000)));
7280         test(Date(105, 1, 1), SysTime(DateTime(105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7281         test(Date(200, 1, 1), SysTime(DateTime(200, 1, 1, 0, 0, 0)));
7282         test(Date(201, 1, 1), SysTime(DateTime(201, 1, 1, 0, 0, 0), hnsecs(500)));
7283         test(Date(300, 1, 1), SysTime(DateTime(300, 1, 1, 0, 0, 0), hnsecs(50_000)));
7284         test(Date(301, 1, 1), SysTime(DateTime(301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7285         test(Date(400, 1, 1), SysTime(DateTime(400, 1, 1, 12, 13, 14)));
7286         test(Date(401, 1, 1), SysTime(DateTime(401, 1, 1, 12, 13, 14), hnsecs(500)));
7287         test(Date(500, 1, 1), SysTime(DateTime(500, 1, 1, 12, 13, 14), hnsecs(50_000)));
7288         test(Date(501, 1, 1), SysTime(DateTime(501, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7289         test(Date(1000, 1, 1), SysTime(DateTime(1000, 1, 1, 23, 59, 59)));
7290         test(Date(1001, 1, 1), SysTime(DateTime(1001, 1, 1, 23, 59, 59), hnsecs(500)));
7291         test(Date(1600, 1, 1), SysTime(DateTime(1600, 1, 1, 23, 59, 59), hnsecs(50_000)));
7292         test(Date(1601, 1, 1), SysTime(DateTime(1601, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7293         test(Date(1900, 1, 1), SysTime(DateTime(1900, 1, 1, 0, 0, 0)));
7294         test(Date(1901, 1, 1), SysTime(DateTime(1901, 1, 1, 0, 0, 0), hnsecs(500)));
7295         test(Date(1945, 11, 12), SysTime(DateTime(1945, 11, 12, 0, 0, 0), hnsecs(50_000)));
7296         test(Date(1999, 1, 1), SysTime(DateTime(1999, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7297         test(Date(1999, 7, 6), SysTime(DateTime(1999, 7, 6, 12, 13, 14)));
7298         test(Date(2000, 1, 1), SysTime(DateTime(2000, 1, 1, 12, 13, 14), hnsecs(500)));
7299         test(Date(2001, 1, 1), SysTime(DateTime(2001, 1, 1, 12, 13, 14), hnsecs(50_000)));
7300 
7301         test(Date(2010, 1, 1), SysTime(DateTime(2010, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7302         test(Date(2010, 1, 31), SysTime(DateTime(2010, 1, 31, 23, 0, 0)));
7303         test(Date(2010, 2, 1), SysTime(DateTime(2010, 2, 1, 23, 59, 59), hnsecs(500)));
7304         test(Date(2010, 2, 28), SysTime(DateTime(2010, 2, 28, 23, 59, 59), hnsecs(50_000)));
7305         test(Date(2010, 3, 1), SysTime(DateTime(2010, 3, 1, 23, 59, 59), hnsecs(9_999_999)));
7306         test(Date(2010, 3, 31), SysTime(DateTime(2010, 3, 31, 0, 0, 0)));
7307         test(Date(2010, 4, 1), SysTime(DateTime(2010, 4, 1, 0, 0, 0), hnsecs(500)));
7308         test(Date(2010, 4, 30), SysTime(DateTime(2010, 4, 30, 0, 0, 0), hnsecs(50_000)));
7309         test(Date(2010, 5, 1), SysTime(DateTime(2010, 5, 1, 0, 0, 0), hnsecs(9_999_999)));
7310         test(Date(2010, 5, 31), SysTime(DateTime(2010, 5, 31, 12, 13, 14)));
7311         test(Date(2010, 6, 1), SysTime(DateTime(2010, 6, 1, 12, 13, 14), hnsecs(500)));
7312         test(Date(2010, 6, 30), SysTime(DateTime(2010, 6, 30, 12, 13, 14), hnsecs(50_000)));
7313         test(Date(2010, 7, 1), SysTime(DateTime(2010, 7, 1, 12, 13, 14), hnsecs(9_999_999)));
7314         test(Date(2010, 7, 31), SysTime(DateTime(2010, 7, 31, 23, 59, 59)));
7315         test(Date(2010, 8, 1), SysTime(DateTime(2010, 8, 1, 23, 59, 59), hnsecs(500)));
7316         test(Date(2010, 8, 31), SysTime(DateTime(2010, 8, 31, 23, 59, 59), hnsecs(50_000)));
7317         test(Date(2010, 9, 1), SysTime(DateTime(2010, 9, 1, 23, 59, 59), hnsecs(9_999_999)));
7318         test(Date(2010, 9, 30), SysTime(DateTime(2010, 9, 30, 12, 0, 0)));
7319         test(Date(2010, 10, 1), SysTime(DateTime(2010, 10, 1, 0, 12, 0), hnsecs(500)));
7320         test(Date(2010, 10, 31), SysTime(DateTime(2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
7321         test(Date(2010, 11, 1), SysTime(DateTime(2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
7322         test(Date(2010, 11, 30), SysTime(DateTime(2010, 11, 30, 0, 59, 0)));
7323         test(Date(2010, 12, 1), SysTime(DateTime(2010, 12, 1, 0, 0, 59), hnsecs(500)));
7324         test(Date(2010, 12, 31), SysTime(DateTime(2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
7325 
7326         test(Date(2012, 2, 1), SysTime(DateTime(2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
7327         test(Date(2012, 2, 28), SysTime(DateTime(2012, 2, 28, 23, 59, 0)));
7328         test(Date(2012, 2, 29), SysTime(DateTime(2012, 2, 29, 7, 7, 7), hnsecs(7)));
7329         test(Date(2012, 3, 1), SysTime(DateTime(2012, 3, 1, 7, 7, 7), hnsecs(7)));
7330 
7331         // Test B.C.
7332         test(Date(0, 12, 31), SysTime(DateTime(0, 12, 31, 0, 0, 0)));
7333         test(Date(0, 12, 30), SysTime(DateTime(0, 12, 30, 0, 0, 0), hnsecs(500)));
7334         test(Date(0, 12, 1), SysTime(DateTime(0, 12, 1, 0, 0, 0), hnsecs(50_000)));
7335         test(Date(0, 11, 30), SysTime(DateTime(0, 11, 30, 0, 0, 0), hnsecs(9_999_999)));
7336 
7337         test(Date(-1, 12, 31), SysTime(DateTime(-1, 12, 31, 12, 13, 14)));
7338         test(Date(-1, 12, 30), SysTime(DateTime(-1, 12, 30, 12, 13, 14), hnsecs(500)));
7339         test(Date(-1, 1, 1), SysTime(DateTime(-1, 1, 1, 12, 13, 14), hnsecs(50_000)));
7340         test(Date(-2, 12, 31), SysTime(DateTime(-2, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
7341         test(Date(-2, 1, 1), SysTime(DateTime(-2, 1, 1, 23, 59, 59)));
7342         test(Date(-3, 12, 31), SysTime(DateTime(-3, 12, 31, 23, 59, 59), hnsecs(500)));
7343         test(Date(-3, 1, 1), SysTime(DateTime(-3, 1, 1, 23, 59, 59), hnsecs(50_000)));
7344         test(Date(-4, 12, 31), SysTime(DateTime(-4, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7345         test(Date(-4, 1, 1), SysTime(DateTime(-4, 1, 1, 0, 0, 0)));
7346         test(Date(-5, 12, 31), SysTime(DateTime(-5, 12, 31, 0, 0, 0), hnsecs(500)));
7347         test(Date(-5, 1, 1), SysTime(DateTime(-5, 1, 1, 0, 0, 0), hnsecs(50_000)));
7348         test(Date(-9, 1, 1), SysTime(DateTime(-9, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7349 
7350         test(Date(-49, 1, 1), SysTime(DateTime(-49, 1, 1, 12, 13, 14)));
7351         test(Date(-50, 1, 1), SysTime(DateTime(-50, 1, 1, 12, 13, 14), hnsecs(500)));
7352         test(Date(-97, 1, 1), SysTime(DateTime(-97, 1, 1, 12, 13, 14), hnsecs(50_000)));
7353         test(Date(-99, 12, 31), SysTime(DateTime(-99, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
7354         test(Date(-99, 1, 1), SysTime(DateTime(-99, 1, 1, 23, 59, 59)));
7355         test(Date(-100, 1, 1), SysTime(DateTime(-100, 1, 1, 23, 59, 59), hnsecs(500)));
7356         test(Date(-101, 1, 1), SysTime(DateTime(-101, 1, 1, 23, 59, 59), hnsecs(50_000)));
7357         test(Date(-105, 1, 1), SysTime(DateTime(-105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7358         test(Date(-200, 1, 1), SysTime(DateTime(-200, 1, 1, 0, 0, 0)));
7359         test(Date(-201, 1, 1), SysTime(DateTime(-201, 1, 1, 0, 0, 0), hnsecs(500)));
7360         test(Date(-300, 1, 1), SysTime(DateTime(-300, 1, 1, 0, 0, 0), hnsecs(50_000)));
7361         test(Date(-301, 1, 1), SysTime(DateTime(-301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7362         test(Date(-400, 12, 31), SysTime(DateTime(-400, 12, 31, 12, 13, 14)));
7363         test(Date(-400, 1, 1), SysTime(DateTime(-400, 1, 1, 12, 13, 14), hnsecs(500)));
7364         test(Date(-401, 1, 1), SysTime(DateTime(-401, 1, 1, 12, 13, 14), hnsecs(50_000)));
7365         test(Date(-499, 1, 1), SysTime(DateTime(-499, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7366         test(Date(-500, 1, 1), SysTime(DateTime(-500, 1, 1, 23, 59, 59)));
7367         test(Date(-501, 1, 1), SysTime(DateTime(-501, 1, 1, 23, 59, 59), hnsecs(500)));
7368         test(Date(-1000, 1, 1), SysTime(DateTime(-1000, 1, 1, 23, 59, 59), hnsecs(50_000)));
7369         test(Date(-1001, 1, 1), SysTime(DateTime(-1001, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7370         test(Date(-1599, 1, 1), SysTime(DateTime(-1599, 1, 1, 0, 0, 0)));
7371         test(Date(-1600, 12, 31), SysTime(DateTime(-1600, 12, 31, 0, 0, 0), hnsecs(500)));
7372         test(Date(-1600, 1, 1), SysTime(DateTime(-1600, 1, 1, 0, 0, 0), hnsecs(50_000)));
7373         test(Date(-1601, 1, 1), SysTime(DateTime(-1601, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7374         test(Date(-1900, 1, 1), SysTime(DateTime(-1900, 1, 1, 12, 13, 14)));
7375         test(Date(-1901, 1, 1), SysTime(DateTime(-1901, 1, 1, 12, 13, 14), hnsecs(500)));
7376         test(Date(-1999, 1, 1), SysTime(DateTime(-1999, 1, 1, 12, 13, 14), hnsecs(50_000)));
7377         test(Date(-1999, 7, 6), SysTime(DateTime(-1999, 7, 6, 12, 13, 14), hnsecs(9_999_999)));
7378         test(Date(-2000, 12, 31), SysTime(DateTime(-2000, 12, 31, 23, 59, 59)));
7379         test(Date(-2000, 1, 1), SysTime(DateTime(-2000, 1, 1, 23, 59, 59), hnsecs(500)));
7380         test(Date(-2001, 1, 1), SysTime(DateTime(-2001, 1, 1, 23, 59, 59), hnsecs(50_000)));
7381 
7382         test(Date(-2010, 1, 1), SysTime(DateTime(-2010, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7383         test(Date(-2010, 1, 31), SysTime(DateTime(-2010, 1, 31, 0, 0, 0)));
7384         test(Date(-2010, 2, 1), SysTime(DateTime(-2010, 2, 1, 0, 0, 0), hnsecs(500)));
7385         test(Date(-2010, 2, 28), SysTime(DateTime(-2010, 2, 28, 0, 0, 0), hnsecs(50_000)));
7386         test(Date(-2010, 3, 1), SysTime(DateTime(-2010, 3, 1, 0, 0, 0), hnsecs(9_999_999)));
7387         test(Date(-2010, 3, 31), SysTime(DateTime(-2010, 3, 31, 12, 13, 14)));
7388         test(Date(-2010, 4, 1), SysTime(DateTime(-2010, 4, 1, 12, 13, 14), hnsecs(500)));
7389         test(Date(-2010, 4, 30), SysTime(DateTime(-2010, 4, 30, 12, 13, 14), hnsecs(50_000)));
7390         test(Date(-2010, 5, 1), SysTime(DateTime(-2010, 5, 1, 12, 13, 14), hnsecs(9_999_999)));
7391         test(Date(-2010, 5, 31), SysTime(DateTime(-2010, 5, 31, 23, 59, 59)));
7392         test(Date(-2010, 6, 1), SysTime(DateTime(-2010, 6, 1, 23, 59, 59), hnsecs(500)));
7393         test(Date(-2010, 6, 30), SysTime(DateTime(-2010, 6, 30, 23, 59, 59), hnsecs(50_000)));
7394         test(Date(-2010, 7, 1), SysTime(DateTime(-2010, 7, 1, 23, 59, 59), hnsecs(9_999_999)));
7395         test(Date(-2010, 7, 31), SysTime(DateTime(-2010, 7, 31, 0, 0, 0)));
7396         test(Date(-2010, 8, 1), SysTime(DateTime(-2010, 8, 1, 0, 0, 0), hnsecs(500)));
7397         test(Date(-2010, 8, 31), SysTime(DateTime(-2010, 8, 31, 0, 0, 0), hnsecs(50_000)));
7398         test(Date(-2010, 9, 1), SysTime(DateTime(-2010, 9, 1, 0, 0, 0), hnsecs(9_999_999)));
7399         test(Date(-2010, 9, 30), SysTime(DateTime(-2010, 9, 30, 12, 0, 0)));
7400         test(Date(-2010, 10, 1), SysTime(DateTime(-2010, 10, 1, 0, 12, 0), hnsecs(500)));
7401         test(Date(-2010, 10, 31), SysTime(DateTime(-2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
7402         test(Date(-2010, 11, 1), SysTime(DateTime(-2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
7403         test(Date(-2010, 11, 30), SysTime(DateTime(-2010, 11, 30, 0, 59, 0)));
7404         test(Date(-2010, 12, 1), SysTime(DateTime(-2010, 12, 1, 0, 0, 59), hnsecs(500)));
7405         test(Date(-2010, 12, 31), SysTime(DateTime(-2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
7406 
7407         test(Date(-2012, 2, 1), SysTime(DateTime(-2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
7408         test(Date(-2012, 2, 28), SysTime(DateTime(-2012, 2, 28, 23, 59, 0)));
7409         test(Date(-2012, 2, 29), SysTime(DateTime(-2012, 2, 29, 7, 7, 7), hnsecs(7)));
7410         test(Date(-2012, 3, 1), SysTime(DateTime(-2012, 3, 1, 7, 7, 7), hnsecs(7)));
7411 
7412         test(Date(-3760, 9, 7), SysTime(DateTime(-3760, 9, 7, 0, 0, 0)));
7413     }
7414 
7415 
7416     /++
7417         The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on.
7418         Setting this property does not affect the time portion of $(LREF SysTime).
7419 
7420         Params:
7421             days = The day of the Gregorian Calendar to set this $(LREF SysTime)
7422                    to.
7423      +/
7424     @property void dayOfGregorianCal(int days) @safe nothrow scope
7425     {
7426         auto hnsecs = adjTime;
7427         hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
7428 
7429         if (hnsecs < 0)
7430             hnsecs += convert!("hours", "hnsecs")(24);
7431 
7432         if (--days < 0)
7433         {
7434             hnsecs -= convert!("hours", "hnsecs")(24);
7435             ++days;
7436         }
7437 
7438         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
7439 
7440         adjTime = newDaysHNSecs + hnsecs;
7441     }
7442 
7443     ///
7444     @safe unittest
7445     {
7446         import core.time;
7447         import std.datetime.date : DateTime;
7448 
7449         auto st = SysTime(DateTime(0, 1, 1, 12, 0, 0));
7450         st.dayOfGregorianCal = 1;
7451         assert(st == SysTime(DateTime(1, 1, 1, 12, 0, 0)));
7452 
7453         st.dayOfGregorianCal = 365;
7454         assert(st == SysTime(DateTime(1, 12, 31, 12, 0, 0)));
7455 
7456         st.dayOfGregorianCal = 366;
7457         assert(st == SysTime(DateTime(2, 1, 1, 12, 0, 0)));
7458 
7459         st.dayOfGregorianCal = 0;
7460         assert(st == SysTime(DateTime(0, 12, 31, 12, 0, 0)));
7461 
7462         st.dayOfGregorianCal = -365;
7463         assert(st == SysTime(DateTime(-0, 1, 1, 12, 0, 0)));
7464 
7465         st.dayOfGregorianCal = -366;
7466         assert(st == SysTime(DateTime(-1, 12, 31, 12, 0, 0)));
7467 
7468         st.dayOfGregorianCal = 730_120;
7469         assert(st == SysTime(DateTime(2000, 1, 1, 12, 0, 0)));
7470 
7471         st.dayOfGregorianCal = 734_137;
7472         assert(st == SysTime(DateTime(2010, 12, 31, 12, 0, 0)));
7473     }
7474 
7475     @safe unittest
7476     {
7477         import core.time;
7478         void testST(SysTime orig, int day, SysTime expected, size_t line = __LINE__) @safe
7479         {
7480             orig.dayOfGregorianCal = day;
7481             if (orig != expected)
7482                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
7483         }
7484 
7485         // Test A.D.
7486         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
7487         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
7488         testST(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 1,
7489                SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7490 
7491         // Test B.C.
7492         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
7493         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 0,
7494                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7495         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(1)), 0,
7496                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
7497         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
7498 
7499         // Test Both.
7500         testST(SysTime(DateTime(-512, 7, 20, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
7501         testST(SysTime(DateTime(-513, 6, 6, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
7502         testST(SysTime(DateTime(-511, 5, 7, 23, 59, 59), hnsecs(9_999_999)), 1,
7503                SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7504 
7505         testST(SysTime(DateTime(1607, 4, 8, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
7506         testST(SysTime(DateTime(1500, 3, 9, 23, 59, 59), hnsecs(9_999_999)), 0,
7507                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7508         testST(SysTime(DateTime(999, 2, 10, 23, 59, 59), hnsecs(1)), 0,
7509                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
7510         testST(SysTime(DateTime(2007, 12, 11, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
7511 
7512 
7513         auto st = SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212));
7514 
7515         void testST2(int day, SysTime expected, size_t line = __LINE__) @safe
7516         {
7517             st.dayOfGregorianCal = day;
7518             if (st != expected)
7519                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", st, expected), __FILE__, line);
7520         }
7521 
7522         // Test A.D.
7523         testST2(1, SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)));
7524         testST2(2, SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)));
7525         testST2(32, SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)));
7526         testST2(366, SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)));
7527         testST2(731, SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)));
7528         testST2(1096, SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)));
7529         testST2(1462, SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)));
7530         testST2(17_898, SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)));
7531         testST2(35_065, SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)));
7532         testST2(36_160, SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)));
7533         testST2(36_525, SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)));
7534         testST2(37_986, SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)));
7535         testST2(72_684, SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)));
7536         testST2(73_049, SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)));
7537         testST2(109_208, SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)));
7538         testST2(109_573, SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)));
7539         testST2(145_732, SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)));
7540         testST2(146_098, SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)));
7541         testST2(182_257, SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)));
7542         testST2(182_622, SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)));
7543         testST2(364_878, SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)));
7544         testST2(365_243, SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)));
7545         testST2(584_023, SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)));
7546         testST2(584_389, SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)));
7547         testST2(693_596, SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)));
7548         testST2(693_961, SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)));
7549         testST2(729_755, SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)));
7550         testST2(730_120, SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)));
7551         testST2(730_486, SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)));
7552 
7553         testST2(733_773, SysTime(DateTime(2010, 1, 1, 12, 2, 9), msecs(212)));
7554         testST2(733_803, SysTime(DateTime(2010, 1, 31, 12, 2, 9), msecs(212)));
7555         testST2(733_804, SysTime(DateTime(2010, 2, 1, 12, 2, 9), msecs(212)));
7556         testST2(733_831, SysTime(DateTime(2010, 2, 28, 12, 2, 9), msecs(212)));
7557         testST2(733_832, SysTime(DateTime(2010, 3, 1, 12, 2, 9), msecs(212)));
7558         testST2(733_862, SysTime(DateTime(2010, 3, 31, 12, 2, 9), msecs(212)));
7559         testST2(733_863, SysTime(DateTime(2010, 4, 1, 12, 2, 9), msecs(212)));
7560         testST2(733_892, SysTime(DateTime(2010, 4, 30, 12, 2, 9), msecs(212)));
7561         testST2(733_893, SysTime(DateTime(2010, 5, 1, 12, 2, 9), msecs(212)));
7562         testST2(733_923, SysTime(DateTime(2010, 5, 31, 12, 2, 9), msecs(212)));
7563         testST2(733_924, SysTime(DateTime(2010, 6, 1, 12, 2, 9), msecs(212)));
7564         testST2(733_953, SysTime(DateTime(2010, 6, 30, 12, 2, 9), msecs(212)));
7565         testST2(733_954, SysTime(DateTime(2010, 7, 1, 12, 2, 9), msecs(212)));
7566         testST2(733_984, SysTime(DateTime(2010, 7, 31, 12, 2, 9), msecs(212)));
7567         testST2(733_985, SysTime(DateTime(2010, 8, 1, 12, 2, 9), msecs(212)));
7568         testST2(734_015, SysTime(DateTime(2010, 8, 31, 12, 2, 9), msecs(212)));
7569         testST2(734_016, SysTime(DateTime(2010, 9, 1, 12, 2, 9), msecs(212)));
7570         testST2(734_045, SysTime(DateTime(2010, 9, 30, 12, 2, 9), msecs(212)));
7571         testST2(734_046, SysTime(DateTime(2010, 10, 1, 12, 2, 9), msecs(212)));
7572         testST2(734_076, SysTime(DateTime(2010, 10, 31, 12, 2, 9), msecs(212)));
7573         testST2(734_077, SysTime(DateTime(2010, 11, 1, 12, 2, 9), msecs(212)));
7574         testST2(734_106, SysTime(DateTime(2010, 11, 30, 12, 2, 9), msecs(212)));
7575         testST2(734_107, SysTime(DateTime(2010, 12, 1, 12, 2, 9), msecs(212)));
7576         testST2(734_137, SysTime(DateTime(2010, 12, 31, 12, 2, 9), msecs(212)));
7577 
7578         testST2(734_534, SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
7579         testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
7580         testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
7581         testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
7582 
7583         testST2(734_534,  SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
7584 
7585         testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
7586         testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
7587         testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
7588 
7589         // Test B.C.
7590         testST2(0, SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)));
7591         testST2(-1, SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)));
7592         testST2(-30, SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)));
7593         testST2(-31, SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)));
7594 
7595         testST2(-366, SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)));
7596         testST2(-367, SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)));
7597         testST2(-730, SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)));
7598         testST2(-731, SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)));
7599         testST2(-1095, SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)));
7600         testST2(-1096, SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)));
7601         testST2(-1460, SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)));
7602         testST2(-1461, SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)));
7603         testST2(-1826, SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)));
7604         testST2(-1827, SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)));
7605         testST2(-2191, SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)));
7606         testST2(-3652, SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)));
7607 
7608         testST2(-18_262, SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)));
7609         testST2(-18_627, SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)));
7610         testST2(-35_794, SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)));
7611         testST2(-36_160, SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)));
7612         testST2(-36_524, SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)));
7613         testST2(-36_889, SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)));
7614         testST2(-37_254, SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)));
7615         testST2(-38_715, SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)));
7616         testST2(-73_413, SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)));
7617         testST2(-73_778, SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)));
7618         testST2(-109_937, SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)));
7619         testST2(-110_302, SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)));
7620         testST2(-146_097, SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)));
7621         testST2(-146_462, SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)));
7622         testST2(-146_827, SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)));
7623         testST2(-182_621, SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)));
7624         testST2(-182_986, SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)));
7625         testST2(-183_351, SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)));
7626         testST2(-365_607, SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)));
7627         testST2(-365_972, SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)));
7628         testST2(-584_387, SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)));
7629         testST2(-584_388, SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)));
7630         testST2(-584_753, SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)));
7631         testST2(-585_118, SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)));
7632         testST2(-694_325, SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)));
7633         testST2(-694_690, SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)));
7634         testST2(-730_484, SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)));
7635         testST2(-730_485, SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)));
7636         testST2(-730_850, SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)));
7637         testST2(-731_215, SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)));
7638 
7639         testST2(-734_502, SysTime(DateTime(-2010, 1, 1, 12, 2, 9), msecs(212)));
7640         testST2(-734_472, SysTime(DateTime(-2010, 1, 31, 12, 2, 9), msecs(212)));
7641         testST2(-734_471, SysTime(DateTime(-2010, 2, 1, 12, 2, 9), msecs(212)));
7642         testST2(-734_444, SysTime(DateTime(-2010, 2, 28, 12, 2, 9), msecs(212)));
7643         testST2(-734_443, SysTime(DateTime(-2010, 3, 1, 12, 2, 9), msecs(212)));
7644         testST2(-734_413, SysTime(DateTime(-2010, 3, 31, 12, 2, 9), msecs(212)));
7645         testST2(-734_412, SysTime(DateTime(-2010, 4, 1, 12, 2, 9), msecs(212)));
7646         testST2(-734_383, SysTime(DateTime(-2010, 4, 30, 12, 2, 9), msecs(212)));
7647         testST2(-734_382, SysTime(DateTime(-2010, 5, 1, 12, 2, 9), msecs(212)));
7648         testST2(-734_352, SysTime(DateTime(-2010, 5, 31, 12, 2, 9), msecs(212)));
7649         testST2(-734_351, SysTime(DateTime(-2010, 6, 1, 12, 2, 9), msecs(212)));
7650         testST2(-734_322, SysTime(DateTime(-2010, 6, 30, 12, 2, 9), msecs(212)));
7651         testST2(-734_321, SysTime(DateTime(-2010, 7, 1, 12, 2, 9), msecs(212)));
7652         testST2(-734_291, SysTime(DateTime(-2010, 7, 31, 12, 2, 9), msecs(212)));
7653         testST2(-734_290, SysTime(DateTime(-2010, 8, 1, 12, 2, 9), msecs(212)));
7654         testST2(-734_260, SysTime(DateTime(-2010, 8, 31, 12, 2, 9), msecs(212)));
7655         testST2(-734_259, SysTime(DateTime(-2010, 9, 1, 12, 2, 9), msecs(212)));
7656         testST2(-734_230, SysTime(DateTime(-2010, 9, 30, 12, 2, 9), msecs(212)));
7657         testST2(-734_229, SysTime(DateTime(-2010, 10, 1, 12, 2, 9), msecs(212)));
7658         testST2(-734_199, SysTime(DateTime(-2010, 10, 31, 12, 2, 9), msecs(212)));
7659         testST2(-734_198, SysTime(DateTime(-2010, 11, 1, 12, 2, 9), msecs(212)));
7660         testST2(-734_169, SysTime(DateTime(-2010, 11, 30, 12, 2, 9), msecs(212)));
7661         testST2(-734_168, SysTime(DateTime(-2010, 12, 1, 12, 2, 9), msecs(212)));
7662         testST2(-734_138, SysTime(DateTime(-2010, 12, 31, 12, 2, 9), msecs(212)));
7663 
7664         testST2(-735_202, SysTime(DateTime(-2012, 2, 1, 12, 2, 9), msecs(212)));
7665         testST2(-735_175, SysTime(DateTime(-2012, 2, 28, 12, 2, 9), msecs(212)));
7666         testST2(-735_174, SysTime(DateTime(-2012, 2, 29, 12, 2, 9), msecs(212)));
7667         testST2(-735_173, SysTime(DateTime(-2012, 3, 1, 12, 2, 9), msecs(212)));
7668 
7669         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7670         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7671         static assert(!__traits(compiles, cst.dayOfGregorianCal = 7));
7672         static assert(!__traits(compiles, ist.dayOfGregorianCal = 7));
7673 
7674         static void testScope(scope ref SysTime st) @safe
7675         {
7676             st.dayOfGregorianCal = 42;
7677         }
7678     }
7679 
7680 
7681     /++
7682         The ISO 8601 week of the year that this $(LREF SysTime) is in.
7683 
7684         See_Also:
7685             $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date).
7686       +/
7687     @property ubyte isoWeek() @safe const nothrow scope
7688     {
7689         return (cast(Date) this).isoWeek;
7690     }
7691 
7692     ///
7693     @safe unittest
7694     {
7695         import core.time;
7696         import std.datetime.date : Date;
7697 
7698         auto st = SysTime(Date(1999, 7, 6));
7699         const cst = SysTime(Date(2010, 5, 1));
7700         immutable ist = SysTime(Date(2015, 10, 10));
7701 
7702         assert(st.isoWeek == 27);
7703         assert(cst.isoWeek == 17);
7704         assert(ist.isoWeek == 41);
7705     }
7706 
7707     @safe unittest
7708     {
7709         static void testScope(scope ref SysTime st) @safe
7710         {
7711             auto result = st.isoWeek;
7712         }
7713     }
7714 
7715 
7716     /++
7717         $(LREF SysTime) for the last day in the month that this Date is in.
7718         The time portion of endOfMonth is always 23:59:59.9999999.
7719       +/
7720     @property SysTime endOfMonth() @safe const nothrow return scope
7721     {
7722         immutable hnsecs = adjTime;
7723         immutable days = getUnitsFromHNSecs!"days"(hnsecs);
7724 
7725         auto date = Date(cast(int) days + 1).endOfMonth;
7726         auto newDays = date.dayOfGregorianCal - 1;
7727         long theTimeHNSecs;
7728 
7729         if (newDays < 0)
7730         {
7731             theTimeHNSecs = -1;
7732             ++newDays;
7733         }
7734         else
7735             theTimeHNSecs = convert!("days", "hnsecs")(1) - 1;
7736 
7737         immutable newDaysHNSecs = convert!("days", "hnsecs")(newDays);
7738 
7739         auto retval = SysTime(this._stdTime, this._timezone);
7740         retval.adjTime = newDaysHNSecs + theTimeHNSecs;
7741 
7742         return retval;
7743     }
7744 
7745     ///
7746     @safe unittest
7747     {
7748         import core.time : msecs, usecs, hnsecs;
7749         import std.datetime.date : DateTime;
7750 
7751         assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonth ==
7752                SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7753 
7754         assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0), msecs(24)).endOfMonth ==
7755                SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7756 
7757         assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27), usecs(5203)).endOfMonth ==
7758                SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7759 
7760         assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9), hnsecs(12345)).endOfMonth ==
7761                SysTime(DateTime(2000, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7762     }
7763 
7764     @safe unittest
7765     {
7766         import core.time;
7767         // Test A.D.
7768         assert(SysTime(Date(1999, 1, 1)).endOfMonth == SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7769         assert(SysTime(Date(1999, 2, 1)).endOfMonth == SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7770         assert(SysTime(Date(2000, 2, 1)).endOfMonth == SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7771         assert(SysTime(Date(1999, 3, 1)).endOfMonth == SysTime(DateTime(1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
7772         assert(SysTime(Date(1999, 4, 1)).endOfMonth == SysTime(DateTime(1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
7773         assert(SysTime(Date(1999, 5, 1)).endOfMonth == SysTime(DateTime(1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
7774         assert(SysTime(Date(1999, 6, 1)).endOfMonth == SysTime(DateTime(1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7775         assert(SysTime(Date(1999, 7, 1)).endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7776         assert(SysTime(Date(1999, 8, 1)).endOfMonth == SysTime(DateTime(1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
7777         assert(SysTime(Date(1999, 9, 1)).endOfMonth == SysTime(DateTime(1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
7778         assert(SysTime(Date(1999, 10, 1)).endOfMonth == SysTime(DateTime(1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
7779         assert(SysTime(Date(1999, 11, 1)).endOfMonth == SysTime(DateTime(1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
7780         assert(SysTime(Date(1999, 12, 1)).endOfMonth == SysTime(DateTime(1999, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7781 
7782         // Test B.C.
7783         assert(SysTime(Date(-1999, 1, 1)).endOfMonth == SysTime(DateTime(-1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7784         assert(SysTime(Date(-1999, 2, 1)).endOfMonth == SysTime(DateTime(-1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7785         assert(SysTime(Date(-2000, 2, 1)).endOfMonth == SysTime(DateTime(-2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7786         assert(SysTime(Date(-1999, 3, 1)).endOfMonth == SysTime(DateTime(-1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
7787         assert(SysTime(Date(-1999, 4, 1)).endOfMonth == SysTime(DateTime(-1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
7788         assert(SysTime(Date(-1999, 5, 1)).endOfMonth == SysTime(DateTime(-1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
7789         assert(SysTime(Date(-1999, 6, 1)).endOfMonth == SysTime(DateTime(-1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7790         assert(SysTime(Date(-1999, 7, 1)).endOfMonth == SysTime(DateTime(-1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7791         assert(SysTime(Date(-1999, 8, 1)).endOfMonth == SysTime(DateTime(-1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
7792         assert(SysTime(Date(-1999, 9, 1)).endOfMonth == SysTime(DateTime(-1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
7793         assert(SysTime(Date(-1999, 10, 1)).endOfMonth ==
7794                SysTime(DateTime(-1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
7795         assert(SysTime(Date(-1999, 11, 1)).endOfMonth ==
7796                SysTime(DateTime(-1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
7797         assert(SysTime(Date(-1999, 12, 1)).endOfMonth ==
7798                SysTime(DateTime(-1999, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7799 
7800         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7801         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7802         assert(cst.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7803         assert(ist.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7804 
7805         static void testScope(scope ref SysTime st) @safe
7806         {
7807             auto result = st.endOfMonth;
7808         }
7809     }
7810 
7811 
7812     /++
7813         The last day in the month that this $(LREF SysTime) is in.
7814       +/
7815     @property ubyte daysInMonth() @safe const nothrow scope
7816     {
7817         return Date(dayOfGregorianCal).daysInMonth;
7818     }
7819 
7820     ///
7821     @safe unittest
7822     {
7823         import core.time;
7824         import std.datetime.date : DateTime;
7825 
7826         assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).daysInMonth == 31);
7827         assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0)).daysInMonth == 28);
7828         assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27)).daysInMonth == 29);
7829         assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9)).daysInMonth == 30);
7830     }
7831 
7832     @safe unittest
7833     {
7834         import core.time;
7835         // Test A.D.
7836         assert(SysTime(DateTime(1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
7837         assert(SysTime(DateTime(1999, 2, 1, 17, 13, 12)).daysInMonth == 28);
7838         assert(SysTime(DateTime(2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
7839         assert(SysTime(DateTime(1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
7840         assert(SysTime(DateTime(1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
7841         assert(SysTime(DateTime(1999, 5, 1, 15, 13, 12)).daysInMonth == 31);
7842         assert(SysTime(DateTime(1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
7843         assert(SysTime(DateTime(1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
7844         assert(SysTime(DateTime(1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
7845         assert(SysTime(DateTime(1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
7846         assert(SysTime(DateTime(1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
7847         assert(SysTime(DateTime(1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
7848         assert(SysTime(DateTime(1999, 12, 1, 12, 52, 13)).daysInMonth == 31);
7849 
7850         // Test B.C.
7851         assert(SysTime(DateTime(-1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
7852         assert(SysTime(DateTime(-1999, 2, 1, 7, 13, 12)).daysInMonth == 28);
7853         assert(SysTime(DateTime(-2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
7854         assert(SysTime(DateTime(-1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
7855         assert(SysTime(DateTime(-1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
7856         assert(SysTime(DateTime(-1999, 5, 1, 5, 13, 12)).daysInMonth == 31);
7857         assert(SysTime(DateTime(-1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
7858         assert(SysTime(DateTime(-1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
7859         assert(SysTime(DateTime(-1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
7860         assert(SysTime(DateTime(-1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
7861         assert(SysTime(DateTime(-1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
7862         assert(SysTime(DateTime(-1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
7863         assert(SysTime(DateTime(-1999, 12, 1, 12, 52, 13)).daysInMonth == 31);
7864 
7865         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7866         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7867         assert(cst.daysInMonth == 31);
7868         assert(ist.daysInMonth == 31);
7869 
7870         static void testScope(scope ref SysTime st) @safe
7871         {
7872             auto result = st.daysInMonth;
7873         }
7874     }
7875 
7876 
7877     /++
7878         Whether the current year is a date in A.D.
7879       +/
7880     @property bool isAD() @safe const nothrow scope
7881     {
7882         return adjTime >= 0;
7883     }
7884 
7885     ///
7886     @safe unittest
7887     {
7888         import core.time;
7889         import std.datetime.date : DateTime;
7890 
7891         assert(SysTime(DateTime(1, 1, 1, 12, 7, 0)).isAD);
7892         assert(SysTime(DateTime(2010, 12, 31, 0, 0, 0)).isAD);
7893         assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
7894         assert(!SysTime(DateTime(-2010, 1, 1, 2, 2, 2)).isAD);
7895     }
7896 
7897     @safe unittest
7898     {
7899         import core.time;
7900         assert(SysTime(DateTime(2010, 7, 4, 12, 0, 9)).isAD);
7901         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).isAD);
7902         assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
7903         assert(!SysTime(DateTime(0, 1, 1, 23, 59, 59)).isAD);
7904         assert(!SysTime(DateTime(-1, 1, 1, 23 ,59 ,59)).isAD);
7905         assert(!SysTime(DateTime(-2010, 7, 4, 12, 2, 2)).isAD);
7906 
7907         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7908         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7909         assert(cst.isAD);
7910         assert(ist.isAD);
7911 
7912         static void testScope(scope ref SysTime st) @safe
7913         {
7914             auto result = st.isAD;
7915         }
7916     }
7917 
7918 
7919     /++
7920         The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day)
7921         for this $(LREF SysTime) at the given time. For example,
7922         prior to noon, 1996-03-31 would be the Julian day number 2_450_173, so
7923         this function returns 2_450_173, while from noon onward, the Julian
7924         day number would be 2_450_174, so this function returns 2_450_174.
7925       +/
7926     @property long julianDay() @safe const nothrow scope
7927     {
7928         immutable jd = dayOfGregorianCal + 1_721_425;
7929         return hour < 12 ? jd - 1 : jd;
7930     }
7931 
7932     @safe unittest
7933     {
7934         import core.time;
7935         assert(SysTime(DateTime(-4713, 11, 24, 0, 0, 0)).julianDay == -1);
7936         assert(SysTime(DateTime(-4713, 11, 24, 12, 0, 0)).julianDay == 0);
7937 
7938         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).julianDay == 1_721_424);
7939         assert(SysTime(DateTime(0, 12, 31, 12, 0, 0)).julianDay == 1_721_425);
7940 
7941         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).julianDay == 1_721_425);
7942         assert(SysTime(DateTime(1, 1, 1, 12, 0, 0)).julianDay == 1_721_426);
7943 
7944         assert(SysTime(DateTime(1582, 10, 15, 0, 0, 0)).julianDay == 2_299_160);
7945         assert(SysTime(DateTime(1582, 10, 15, 12, 0, 0)).julianDay == 2_299_161);
7946 
7947         assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).julianDay == 2_400_000);
7948         assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).julianDay == 2_400_001);
7949 
7950         assert(SysTime(DateTime(1982, 1, 4, 0, 0, 0)).julianDay == 2_444_973);
7951         assert(SysTime(DateTime(1982, 1, 4, 12, 0, 0)).julianDay == 2_444_974);
7952 
7953         assert(SysTime(DateTime(1996, 3, 31, 0, 0, 0)).julianDay == 2_450_173);
7954         assert(SysTime(DateTime(1996, 3, 31, 12, 0, 0)).julianDay == 2_450_174);
7955 
7956         assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).julianDay == 2_455_432);
7957         assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).julianDay == 2_455_433);
7958 
7959         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7960         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7961         assert(cst.julianDay == 2_451_366);
7962         assert(ist.julianDay == 2_451_366);
7963 
7964         static void testScope(scope ref SysTime st) @safe
7965         {
7966             auto result = st.julianDay;
7967         }
7968     }
7969 
7970 
7971     /++
7972         The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for
7973         any time on this date (since, the modified Julian day changes at
7974         midnight).
7975       +/
7976     @property long modJulianDay() @safe const nothrow scope
7977     {
7978         return dayOfGregorianCal + 1_721_425 - 2_400_001;
7979     }
7980 
7981     @safe unittest
7982     {
7983         import core.time;
7984         assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).modJulianDay == 0);
7985         assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).modJulianDay == 0);
7986 
7987         assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).modJulianDay == 55_432);
7988         assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).modJulianDay == 55_432);
7989 
7990         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7991         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7992         assert(cst.modJulianDay == 51_365);
7993         assert(ist.modJulianDay == 51_365);
7994 
7995         static void testScope(scope ref SysTime st) @safe
7996         {
7997             auto result = st.modJulianDay;
7998         }
7999     }
8000 
8001 
8002     /++
8003         Returns a $(REF Date,std,datetime,date) equivalent to this $(LREF SysTime).
8004       +/
8005     Date opCast(T)() @safe const nothrow scope
8006     if (is(immutable T == immutable Date))
8007     {
8008         return Date(dayOfGregorianCal);
8009     }
8010 
8011     @safe unittest
8012     {
8013         import core.time;
8014         assert(cast(Date) SysTime(Date(1999, 7, 6)) == Date(1999, 7, 6));
8015         assert(cast(Date) SysTime(Date(2000, 12, 31)) == Date(2000, 12, 31));
8016         assert(cast(Date) SysTime(Date(2001, 1, 1)) == Date(2001, 1, 1));
8017 
8018         assert(cast(Date) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == Date(1999, 7, 6));
8019         assert(cast(Date) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == Date(2000, 12, 31));
8020         assert(cast(Date) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == Date(2001, 1, 1));
8021 
8022         assert(cast(Date) SysTime(Date(-1999, 7, 6)) == Date(-1999, 7, 6));
8023         assert(cast(Date) SysTime(Date(-2000, 12, 31)) == Date(-2000, 12, 31));
8024         assert(cast(Date) SysTime(Date(-2001, 1, 1)) == Date(-2001, 1, 1));
8025 
8026         assert(cast(Date) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == Date(-1999, 7, 6));
8027         assert(cast(Date) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == Date(-2000, 12, 31));
8028         assert(cast(Date) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == Date(-2001, 1, 1));
8029 
8030         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8031         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8032         assert(cast(Date) cst != Date.init);
8033         assert(cast(Date) ist != Date.init);
8034 
8035         static void testScope(scope ref SysTime st) @safe
8036         {
8037             auto result = cast(Date) st;
8038         }
8039     }
8040 
8041 
8042     /++
8043         Returns a $(REF DateTime,std,datetime,date) equivalent to this
8044         $(LREF SysTime).
8045       +/
8046     DateTime opCast(T)() @safe const nothrow scope
8047     if (is(immutable T == immutable DateTime))
8048     {
8049         try
8050         {
8051             auto hnsecs = adjTime;
8052             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8053 
8054             if (hnsecs < 0)
8055             {
8056                 hnsecs += convert!("hours", "hnsecs")(24);
8057                 --days;
8058             }
8059 
8060             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8061             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8062             immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
8063 
8064             return DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour, cast(int) minute, cast(int) second));
8065         }
8066         catch (Exception e)
8067             assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw.");
8068     }
8069 
8070     @safe unittest
8071     {
8072         import core.time;
8073         assert(cast(DateTime) SysTime(DateTime(1, 1, 6, 7, 12, 22)) == DateTime(1, 1, 6, 7, 12, 22));
8074         assert(cast(DateTime) SysTime(DateTime(1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(1, 1, 6, 7, 12, 22));
8075         assert(cast(DateTime) SysTime(Date(1999, 7, 6)) == DateTime(1999, 7, 6, 0, 0, 0));
8076         assert(cast(DateTime) SysTime(Date(2000, 12, 31)) == DateTime(2000, 12, 31, 0, 0, 0));
8077         assert(cast(DateTime) SysTime(Date(2001, 1, 1)) == DateTime(2001, 1, 1, 0, 0, 0));
8078 
8079         assert(cast(DateTime) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == DateTime(1999, 7, 6, 12, 10, 9));
8080         assert(cast(DateTime) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == DateTime(2000, 12, 31, 13, 11, 10));
8081         assert(cast(DateTime) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == DateTime(2001, 1, 1, 14, 12, 11));
8082 
8083         assert(cast(DateTime) SysTime(DateTime(-1, 1, 6, 7, 12, 22)) == DateTime(-1, 1, 6, 7, 12, 22));
8084         assert(cast(DateTime) SysTime(DateTime(-1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(-1, 1, 6, 7, 12, 22));
8085         assert(cast(DateTime) SysTime(Date(-1999, 7, 6)) == DateTime(-1999, 7, 6, 0, 0, 0));
8086         assert(cast(DateTime) SysTime(Date(-2000, 12, 31)) == DateTime(-2000, 12, 31, 0, 0, 0));
8087         assert(cast(DateTime) SysTime(Date(-2001, 1, 1)) == DateTime(-2001, 1, 1, 0, 0, 0));
8088 
8089         assert(cast(DateTime) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == DateTime(-1999, 7, 6, 12, 10, 9));
8090         assert(cast(DateTime) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == DateTime(-2000, 12, 31, 13, 11, 10));
8091         assert(cast(DateTime) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == DateTime(-2001, 1, 1, 14, 12, 11));
8092 
8093         assert(cast(DateTime) SysTime(DateTime(2011, 1, 13, 8, 17, 2), msecs(296), LocalTime()) ==
8094                DateTime(2011, 1, 13, 8, 17, 2));
8095 
8096         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8097         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8098         assert(cast(DateTime) cst != DateTime.init);
8099         assert(cast(DateTime) ist != DateTime.init);
8100 
8101         static void testScope(scope ref SysTime st) @safe
8102         {
8103             auto result = cast(DateTime) st;
8104         }
8105     }
8106 
8107 
8108     /++
8109         Returns a $(REF TimeOfDay,std,datetime,date) equivalent to this
8110         $(LREF SysTime).
8111       +/
8112     TimeOfDay opCast(T)() @safe const nothrow scope
8113     if (is(immutable T == immutable TimeOfDay))
8114     {
8115         try
8116         {
8117             auto hnsecs = adjTime;
8118             hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
8119 
8120             if (hnsecs < 0)
8121                 hnsecs += convert!("hours", "hnsecs")(24);
8122 
8123             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8124             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8125             immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
8126 
8127             return TimeOfDay(cast(int) hour, cast(int) minute, cast(int) second);
8128         }
8129         catch (Exception e)
8130             assert(0, "TimeOfDay's constructor threw.");
8131     }
8132 
8133     @safe unittest
8134     {
8135         import core.time;
8136         assert(cast(TimeOfDay) SysTime(Date(1999, 7, 6)) == TimeOfDay(0, 0, 0));
8137         assert(cast(TimeOfDay) SysTime(Date(2000, 12, 31)) == TimeOfDay(0, 0, 0));
8138         assert(cast(TimeOfDay) SysTime(Date(2001, 1, 1)) == TimeOfDay(0, 0, 0));
8139 
8140         assert(cast(TimeOfDay) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
8141         assert(cast(TimeOfDay) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
8142         assert(cast(TimeOfDay) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11));
8143 
8144         assert(cast(TimeOfDay) SysTime(Date(-1999, 7, 6)) == TimeOfDay(0, 0, 0));
8145         assert(cast(TimeOfDay) SysTime(Date(-2000, 12, 31)) == TimeOfDay(0, 0, 0));
8146         assert(cast(TimeOfDay) SysTime(Date(-2001, 1, 1)) == TimeOfDay(0, 0, 0));
8147 
8148         assert(cast(TimeOfDay) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
8149         assert(cast(TimeOfDay) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
8150         assert(cast(TimeOfDay) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11));
8151 
8152         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8153         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8154         assert(cast(TimeOfDay) cst != TimeOfDay.init);
8155         assert(cast(TimeOfDay) ist != TimeOfDay.init);
8156 
8157         static void testScope(scope ref SysTime st) @safe
8158         {
8159             auto result = cast(TimeOfDay) st;
8160         }
8161     }
8162 
8163 
8164     // Temporary hack until bug https://issues.dlang.org/show_bug.cgi?id=4867 is fixed.
8165     // This allows assignment from const(SysTime) to SysTime.
8166     // It may be a good idea to keep it though, since casting from a type to itself
8167     // should be allowed, and it doesn't work without this opCast() since opCast()
8168     // has already been defined for other types.
8169     SysTime opCast(T)() @safe const pure nothrow scope
8170     if (is(immutable T == immutable SysTime))
8171     {
8172         return SysTime(_stdTime, _timezone);
8173     }
8174 
8175     @safe unittest
8176     {
8177         static void testScope(scope ref SysTime st) @safe
8178         {
8179             auto result = cast(SysTime) st;
8180         }
8181     }
8182 
8183 
8184     /++
8185         Converts this $(LREF SysTime) to a string with the format
8186         YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds and TZ is time
8187         zone).
8188 
8189         Note that the number of digits in the fractional seconds varies with the
8190         number of fractional seconds. It's a maximum of 7 (which would be
8191         hnsecs), but only has as many as are necessary to hold the correct value
8192         (so no trailing zeroes), and if there are no fractional seconds, then
8193         there is no decimal point.
8194 
8195         If this $(LREF SysTime)'s time zone is
8196         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
8197         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
8198         (e.g. +0100 or -0700). Note that the offset from UTC is $(I not) enough
8199         to uniquely identify the time zone.
8200 
8201         Time zone offsets will be in the form +HHMM or -HHMM.
8202 
8203         $(RED Warning:
8204             Previously, toISOString did the same as $(LREF toISOExtString) and
8205             generated +HH:MM or -HH:MM for the time zone when it was not
8206             $(REF LocalTime,std,datetime,timezone) or
8207             $(REF UTC,std,datetime,timezone), which is not in conformance with
8208             ISO 8601 for the non-extended string format. This has now been
8209             fixed. However, for now, fromISOString will continue to accept the
8210             extended format for the time zone so that any code which has been
8211             writing out the result of toISOString to read in later will continue
8212             to work. The current behavior will be kept until July 2019 at which
8213             point, fromISOString will be fixed to be standards compliant.)
8214 
8215         Params:
8216             writer = A `char` accepting
8217             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8218         Returns:
8219             A `string` when not using an output range; `void` otherwise.
8220       +/
8221     string toISOString() @safe const nothrow scope
8222     {
8223         import std.array : appender;
8224         auto app = appender!string();
8225         app.reserve(30);
8226         try
8227             toISOString(app);
8228         catch (Exception e)
8229             assert(0, "toISOString() threw.");
8230         return app.data;
8231     }
8232 
8233     /// ditto
8234     void toISOString(W)(ref W writer) const scope
8235     if (isOutputRange!(W, char))
8236     {
8237         immutable adjustedTime = adjTime;
8238         long hnsecs = adjustedTime;
8239 
8240         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8241 
8242         if (hnsecs < 0)
8243         {
8244             hnsecs += convert!("hours", "hnsecs")(24);
8245             --days;
8246         }
8247 
8248         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8249         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8250         immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
8251 
8252         auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
8253                                       cast(int) minute, cast(int) second));
8254 
8255         if (_timezone is LocalTime())
8256         {
8257             dateTime.toISOString(writer);
8258             fracSecsToISOString(writer, cast(int) hnsecs);
8259             return;
8260         }
8261 
8262         if (_timezone is UTC())
8263         {
8264             dateTime.toISOString(writer);
8265             fracSecsToISOString(writer, cast(int) hnsecs);
8266             put(writer, 'Z');
8267             return;
8268         }
8269 
8270         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
8271 
8272         dateTime.toISOString(writer);
8273         fracSecsToISOString(writer, cast(int) hnsecs);
8274         SimpleTimeZone.toISOExtString(writer, utcOffset);
8275     }
8276 
8277     ///
8278     @safe unittest
8279     {
8280         import core.time : msecs, hnsecs;
8281         import std.datetime.date : DateTime;
8282 
8283         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOString() ==
8284                "20100704T070612");
8285 
8286         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOString() ==
8287                "19981225T021500.024");
8288 
8289         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOString() ==
8290                "00000105T230959");
8291 
8292         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOString() ==
8293                "-00040105T000002.052092");
8294     }
8295 
8296     @safe unittest
8297     {
8298         import core.time;
8299         // Test A.D.
8300         assert(SysTime(DateTime.init, UTC()).toISOString() == "00010101T000000Z");
8301         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOString() == "00010101T000000.0000001Z");
8302 
8303         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOString() == "00091204T000000");
8304         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOString() == "00991204T050612");
8305         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOString() == "09991204T134459");
8306         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOString() == "99990704T235959");
8307         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOString() == "+100001020T010101");
8308 
8309         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "00091204T000000.042");
8310         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "00991204T050612.1");
8311         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "09991204T134459.04502");
8312         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "99990704T235959.0000012");
8313         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "+100001020T010101.050789");
8314 
8315         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8316                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOString() ==
8317                "20121221T121212-06:00");
8318 
8319         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8320                        new immutable SimpleTimeZone(dur!"minutes"(420))).toISOString() ==
8321                "20121221T121212+07:00");
8322 
8323         // Test B.C.
8324         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOString() ==
8325                "00001231T235959.9999999Z");
8326         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOString() == "00001231T235959.0000001Z");
8327         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOString() == "00001231T235959Z");
8328 
8329         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOString() == "00001204T001204");
8330         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOString() == "-00091204T000000");
8331         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOString() == "-00991204T050612");
8332         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOString() == "-09991204T134459");
8333         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOString() == "-99990704T235959");
8334         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOString() == "-100001020T010101");
8335 
8336         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOString() == "00001204T000000.007");
8337         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "-00091204T000000.042");
8338         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "-00991204T050612.1");
8339         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "-09991204T134459.04502");
8340         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "-99990704T235959.0000012");
8341         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "-100001020T010101.050789");
8342 
8343         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8344         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8345         assert(cst.toISOString() == "19990706T123033");
8346         assert(ist.toISOString() == "19990706T123033");
8347 
8348         static void testScope(scope ref SysTime st) @safe
8349         {
8350             auto result = st.toISOString();
8351         }
8352     }
8353 
8354 
8355 
8356     /++
8357         Converts this $(LREF SysTime) to a string with the format
8358         YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
8359         is the time zone).
8360 
8361         Default behaviour:
8362         Note that the number of digits in the fractional seconds varies with the
8363         number of fractional seconds. It's a maximum of 7 (which would be
8364         hnsecs), but only has as many as are necessary to hold the correct value
8365         (so no trailing zeroes), and if there are no fractional seconds, then
8366         there is no decimal point.
8367 
8368         The optional parameter "prec" allows to change the default behavior by
8369         specifying the precision of the fractional seconds. The accepted values
8370         are in the range [-1, 7], where -1 represents the default behavior.
8371 
8372         If this $(LREF SysTime)'s time zone is
8373         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
8374         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
8375         (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not)
8376         enough to uniquely identify the time zone.
8377 
8378         Time zone offsets will be in the form +HH:MM or -HH:MM.
8379 
8380         Params:
8381             writer = A `char` accepting
8382             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8383             prec = An `int` representing the desired precision. Acceptable values range from -1 to 7, where -1 represents the default behavior.
8384         Returns:
8385             A `string` when not using an output range; `void` otherwise.
8386       +/
8387     string toISOExtString(int prec = -1) @safe const nothrow scope
8388     {
8389         assert(prec >= -1 && prec <= 7, "Precision must be in the range [-1, 7]");
8390 
8391         import std.array : appender;
8392         auto app = appender!string();
8393         app.reserve(35);
8394         try
8395             toISOExtString(app, prec);
8396         catch (Exception e)
8397             assert(0, "toISOExtString() threw.");
8398         return app.data;
8399     }
8400 
8401     /// ditto
8402     void toISOExtString(W)(ref W writer, int prec = -1) const scope
8403     if (isOutputRange!(W, char))
8404     {
8405         assert(prec >= -1 && prec <= 7, "Precision must be in the range [-1, 7]");
8406 
8407         immutable adjustedTime = adjTime;
8408         long hnsecs = adjustedTime;
8409 
8410         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8411 
8412         if (hnsecs < 0)
8413         {
8414             hnsecs += convert!("hours", "hnsecs")(24);
8415             --days;
8416         }
8417 
8418         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8419         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8420         immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
8421 
8422         immutable dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
8423                                       cast(int) minute, cast(int) second));
8424 
8425         if (_timezone is LocalTime())
8426         {
8427             dateTime.toISOExtString(writer);
8428             fracSecsToISOString(writer, cast(int) hnsecs, prec);
8429             return;
8430         }
8431 
8432         if (_timezone is UTC())
8433         {
8434             dateTime.toISOExtString(writer);
8435             fracSecsToISOString(writer, cast(int) hnsecs, prec);
8436             put(writer, 'Z');
8437             return;
8438         }
8439 
8440         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
8441 
8442         dateTime.toISOExtString(writer);
8443         fracSecsToISOString(writer, cast(int) hnsecs, prec);
8444         SimpleTimeZone.toISOExtString(writer, utcOffset);
8445     }
8446 
8447     ///
8448     @safe unittest
8449     {
8450         import core.time : msecs, hnsecs;
8451         import std.datetime.date : DateTime;
8452 
8453         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOExtString() ==
8454                "2010-07-04T07:06:12");
8455 
8456         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOExtString() ==
8457                "1998-12-25T02:15:00.024");
8458 
8459         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOExtString() ==
8460                "0000-01-05T23:09:59");
8461 
8462         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString() ==
8463                "-0004-01-05T00:00:02.052092");
8464 
8465         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(4) ==
8466                "-0004-01-05T00:00:02.0520");
8467 
8468         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(2) ==
8469                "-0004-01-05T00:00:02.05");
8470 
8471         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(7) ==
8472                "-0004-01-05T00:00:02.0520920");
8473     }
8474 
8475     @safe unittest
8476     {
8477         import core.time;
8478         // Test A.D.
8479         assert(SysTime(DateTime.init, UTC()).toISOExtString() == "0001-01-01T00:00:00Z");
8480         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOExtString() ==
8481                "0001-01-01T00:00:00.0000001Z");
8482 
8483         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00");
8484         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12");
8485         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59");
8486         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59");
8487         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01");
8488 
8489         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "0009-12-04T00:00:00.042");
8490         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "0099-12-04T05:06:12.1");
8491         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() == "0999-12-04T13:44:59.04502");
8492         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() == "9999-07-04T23:59:59.0000012");
8493         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
8494                "+10000-10-20T01:01:01.050789");
8495 
8496         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8497                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOExtString() ==
8498                "2012-12-21T12:12:12-06:00");
8499 
8500         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8501                        new immutable SimpleTimeZone(dur!"minutes"(420))).toISOExtString() ==
8502                "2012-12-21T12:12:12+07:00");
8503 
8504         // Test B.C.
8505         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOExtString() ==
8506                "0000-12-31T23:59:59.9999999Z");
8507         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOExtString() ==
8508                "0000-12-31T23:59:59.0000001Z");
8509         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOExtString() == "0000-12-31T23:59:59Z");
8510 
8511         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04");
8512         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00");
8513         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12");
8514         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59");
8515         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59");
8516         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01");
8517 
8518         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOExtString() == "0000-12-04T00:00:00.007");
8519         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "-0009-12-04T00:00:00.042");
8520         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "-0099-12-04T05:06:12.1");
8521         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() ==
8522                "-0999-12-04T13:44:59.04502");
8523         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() ==
8524                "-9999-07-04T23:59:59.0000012");
8525         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
8526                "-10000-10-20T01:01:01.050789");
8527 
8528         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8529         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8530         assert(cst.toISOExtString() == "1999-07-06T12:30:33");
8531         assert(ist.toISOExtString() == "1999-07-06T12:30:33");
8532 
8533         static void testScope(scope ref SysTime st) @safe
8534         {
8535             auto result = st.toISOExtString();
8536         }
8537     }
8538 
8539     /++
8540         Converts this $(LREF SysTime) to a string with the format
8541         YYYY-Mon-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
8542         is the time zone).
8543 
8544         Note that the number of digits in the fractional seconds varies with the
8545         number of fractional seconds. It's a maximum of 7 (which would be
8546         hnsecs), but only has as many as are necessary to hold the correct value
8547         (so no trailing zeroes), and if there are no fractional seconds, then
8548         there is no decimal point.
8549 
8550         If this $(LREF SysTime)'s time zone is
8551         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
8552         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
8553         (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not)
8554         enough to uniquely identify the time zone.
8555 
8556         Time zone offsets will be in the form +HH:MM or -HH:MM.
8557 
8558         Params:
8559             writer = A `char` accepting
8560             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8561         Returns:
8562             A `string` when not using an output range; `void` otherwise.
8563       +/
8564     string toSimpleString() @safe const nothrow scope
8565     {
8566         import std.array : appender;
8567         auto app = appender!string();
8568         app.reserve(35);
8569         try
8570             toSimpleString(app);
8571         catch (Exception e)
8572             assert(0, "toSimpleString() threw.");
8573         return app.data;
8574     }
8575 
8576     /// ditto
8577     void toSimpleString(W)(ref W writer) const scope
8578     if (isOutputRange!(W, char))
8579     {
8580         immutable adjustedTime = adjTime;
8581         long hnsecs = adjustedTime;
8582 
8583         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8584 
8585         if (hnsecs < 0)
8586         {
8587             hnsecs += convert!("hours", "hnsecs")(24);
8588             --days;
8589         }
8590 
8591         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8592         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8593         immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
8594 
8595         immutable dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
8596                                       cast(int) minute, cast(int) second));
8597 
8598         if (_timezone is LocalTime())
8599         {
8600             dateTime.toSimpleString(writer);
8601             fracSecsToISOString(writer, cast(int) hnsecs);
8602             return;
8603         }
8604 
8605         if (_timezone is UTC())
8606         {
8607             dateTime.toSimpleString(writer);
8608             fracSecsToISOString(writer, cast(int) hnsecs);
8609             put(writer, 'Z');
8610             return;
8611         }
8612 
8613         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
8614 
8615         dateTime.toSimpleString(writer);
8616         fracSecsToISOString(writer, cast(int) hnsecs);
8617         SimpleTimeZone.toISOExtString(writer, utcOffset);
8618     }
8619 
8620     ///
8621     @safe unittest
8622     {
8623         import core.time : msecs, hnsecs;
8624         import std.datetime.date : DateTime;
8625 
8626         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toSimpleString() ==
8627                "2010-Jul-04 07:06:12");
8628 
8629         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toSimpleString() ==
8630                "1998-Dec-25 02:15:00.024");
8631 
8632         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toSimpleString() ==
8633                "0000-Jan-05 23:09:59");
8634 
8635         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toSimpleString() ==
8636                 "-0004-Jan-05 00:00:02.052092");
8637     }
8638 
8639     @safe unittest
8640     {
8641         import core.time;
8642         // Test A.D.
8643         assert(SysTime(DateTime.init, UTC()).toString() == "0001-Jan-01 00:00:00Z");
8644         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toString() == "0001-Jan-01 00:00:00.0000001Z");
8645 
8646         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00");
8647         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12");
8648         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59");
8649         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59");
8650         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01");
8651 
8652         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "0009-Dec-04 00:00:00.042");
8653         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "0099-Dec-04 05:06:12.1");
8654         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
8655                "0999-Dec-04 13:44:59.04502");
8656         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
8657                "9999-Jul-04 23:59:59.0000012");
8658         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() ==
8659                "+10000-Oct-20 01:01:01.050789");
8660 
8661         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8662                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toSimpleString() ==
8663                "2012-Dec-21 12:12:12-06:00");
8664 
8665         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8666                        new immutable SimpleTimeZone(dur!"minutes"(420))).toSimpleString() ==
8667                "2012-Dec-21 12:12:12+07:00");
8668 
8669         // Test B.C.
8670         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toSimpleString() ==
8671                "0000-Dec-31 23:59:59.9999999Z");
8672         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toSimpleString() ==
8673                "0000-Dec-31 23:59:59.0000001Z");
8674         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toSimpleString() == "0000-Dec-31 23:59:59Z");
8675 
8676         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04");
8677         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00");
8678         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12");
8679         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59");
8680         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59");
8681         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01");
8682 
8683         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toSimpleString() == "0000-Dec-04 00:00:00.007");
8684         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "-0009-Dec-04 00:00:00.042");
8685         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "-0099-Dec-04 05:06:12.1");
8686         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
8687                "-0999-Dec-04 13:44:59.04502");
8688         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
8689                "-9999-Jul-04 23:59:59.0000012");
8690         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() ==
8691                "-10000-Oct-20 01:01:01.050789");
8692 
8693         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8694         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8695         assert(cst.toSimpleString() == "1999-Jul-06 12:30:33");
8696         assert(ist.toSimpleString() == "1999-Jul-06 12:30:33");
8697 
8698         static void testScope(scope ref SysTime st) @safe
8699         {
8700             auto result = st.toSimpleString();
8701         }
8702     }
8703 
8704 
8705     /++
8706         Converts this $(LREF SysTime) to a string.
8707 
8708         This function exists to make it easy to convert a $(LREF SysTime) to a
8709         string for code that does not care what the exact format is - just that
8710         it presents the information in a clear manner. It also makes it easy to
8711         simply convert a $(LREF SysTime) to a string when using functions such
8712         as `to!string`, `format`, or `writeln` which use toString to convert
8713         user-defined types. So, it is unlikely that much code will call
8714         toString directly.
8715 
8716         The format of the string is purposefully unspecified, and code that
8717         cares about the format of the string should use `toISOString`,
8718         `toISOExtString`, `toSimpleString`, or some other custom formatting
8719         function that explicitly generates the format that the code needs. The
8720         reason is that the code is then clear about what format it's using,
8721         making it less error-prone to maintain the code and interact with other
8722         software that consumes the generated strings. It's for this same reason
8723         that $(LREF SysTime) has no `fromString` function, whereas it does have
8724         `fromISOString`, `fromISOExtString`, and `fromSimpleString`.
8725 
8726         The format returned by toString may or may not change in the future.
8727 
8728         Params:
8729             writer = A `char` accepting
8730             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8731         Returns:
8732             A `string` when not using an output range; `void` otherwise.
8733       +/
8734     string toString() @safe const nothrow scope
8735     {
8736         return toSimpleString();
8737     }
8738 
8739     /// ditto
8740     void toString(W)(ref W writer) const scope
8741     if (isOutputRange!(W, char))
8742     {
8743         toSimpleString(writer);
8744     }
8745 
8746     @safe unittest
8747     {
8748         import core.time;
8749         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8750         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8751         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8752         static assert(__traits(compiles, st.toString()));
8753         static assert(__traits(compiles, cst.toString()));
8754         static assert(__traits(compiles, ist.toString()));
8755 
8756         static void testScope(scope ref SysTime st) @safe
8757         {
8758             auto result = st.toString();
8759         }
8760     }
8761 
8762 
8763     /++
8764         Creates a $(LREF SysTime) from a string with the format
8765         YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds and TZ
8766         is the time zone). Whitespace is stripped from the given string.
8767 
8768         The exact format is exactly as described in $(LREF toISOString) except
8769         that trailing zeroes are permitted - including having fractional seconds
8770         with all zeroes. The time zone and fractional seconds are optional,
8771         however, a decimal point with nothing following it is invalid.
8772         Also, while $(LREF toISOString) will never generate a string
8773         with more than 7 digits in the fractional seconds (because that's the
8774         limit with hecto-nanosecond precision), it will allow more than 7 digits
8775         in order to read strings from other sources that have higher precision
8776         (however, any digits beyond 7 will be truncated).
8777 
8778         If there is no time zone in the string, then
8779         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
8780         then `UTC` is used. Otherwise, a
8781         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
8782         given offset from UTC is used. To get the returned $(LREF SysTime) to be
8783         a particular time zone, pass in that time zone and the $(LREF SysTime)
8784         to be returned will be converted to that time zone (though it will still
8785         be read in as whatever time zone is in its string).
8786 
8787         The accepted formats for time zone offsets are +HH, -HH, +HHMM, and
8788         -HHMM.
8789 
8790         $(RED Warning:
8791             Previously, $(LREF toISOString) did the same as
8792             $(LREF toISOExtString) and generated +HH:MM or -HH:MM for the time
8793             zone when it was not $(REF LocalTime,std,datetime,timezone) or
8794             $(REF UTC,std,datetime,timezone), which is not in conformance with
8795             ISO 8601 for the non-extended string format. This has now been
8796             fixed. However, for now, fromISOString will continue to accept the
8797             extended format for the time zone so that any code which has been
8798             writing out the result of toISOString to read in later will continue
8799             to work. The current behavior will be kept until July 2019 at which
8800             point, fromISOString will be fixed to be standards compliant.)
8801 
8802         Params:
8803             isoString = A string formatted in the ISO format for dates and times.
8804             tz        = The time zone to convert the given time to (no
8805                         conversion occurs if null).
8806 
8807         Throws:
8808             $(REF DateTimeException,std,datetime,date) if the given string is
8809             not in the ISO format or if the resulting $(LREF SysTime) would not
8810             be valid.
8811       +/
8812     static SysTime fromISOString(S)(scope const S isoString, immutable TimeZone tz = null) @safe
8813     if (isSomeString!S)
8814     {
8815         import std.algorithm.searching : startsWith, find;
8816         import std.conv : to;
8817         import std.string : strip;
8818         import std.utf : byCodeUnit;
8819 
8820         auto str = strip(isoString);
8821         immutable skipFirst = str.startsWith('+', '-');
8822 
8823         auto found = (skipFirst ? str[1..$] : str).byCodeUnit.find('.', 'Z', '+', '-');
8824         auto dateTimeStr = str[0 .. $ - found[0].length];
8825 
8826         typeof(str.byCodeUnit) foundTZ; // needs to have longer lifetime than zoneStr
8827         typeof(str) fracSecStr;
8828         typeof(str) zoneStr;
8829 
8830         if (found[1] != 0)
8831         {
8832             if (found[1] == 1)
8833             {
8834                 foundTZ = found[0].find('Z', '+', '-')[0];
8835 
8836                 if (foundTZ.length != 0)
8837                 {
8838                     static if (isNarrowString!S)
8839                     {
8840                         fracSecStr = found[0][0 .. $ - foundTZ.length].source;
8841                         zoneStr = foundTZ.source;
8842                     }
8843                     else
8844                     {
8845                         fracSecStr = found[0][0 .. $ - foundTZ.length];
8846                         zoneStr = foundTZ;
8847                     }
8848                 }
8849                 else
8850                 {
8851                     static if (isNarrowString!S)
8852                         fracSecStr = found[0].source;
8853                     else
8854                         fracSecStr = found[0];
8855                 }
8856             }
8857             else
8858             {
8859                 static if (isNarrowString!S)
8860                     zoneStr = found[0].source;
8861                 else
8862                     zoneStr = found[0];
8863             }
8864         }
8865 
8866         try
8867         {
8868             auto dateTime = DateTime.fromISOString(dateTimeStr);
8869             auto fracSec = fracSecsFromISOString(fracSecStr);
8870 
8871             Rebindable!(immutable TimeZone) parsedZone;
8872 
8873             if (zoneStr.empty)
8874                 parsedZone = LocalTime();
8875             else if (zoneStr == "Z")
8876                 parsedZone = UTC();
8877             else
8878             {
8879                 try
8880                     parsedZone = SimpleTimeZone.fromISOString(zoneStr);
8881                 catch (DateTimeException dte)
8882                     parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
8883             }
8884 
8885             auto retval = SysTime(dateTime, fracSec, parsedZone);
8886 
8887             if (tz !is null)
8888                 retval.timezone = tz;
8889 
8890             return retval;
8891         }
8892         catch (DateTimeException dte)
8893             throw new DateTimeException(format("Invalid format for SysTime.fromISOString: %s", isoString));
8894     }
8895 
8896     ///
8897     @safe unittest
8898     {
8899         import core.time : hours, msecs, usecs, hnsecs;
8900         import std.datetime.date : DateTime;
8901         import std.datetime.timezone : SimpleTimeZone, UTC;
8902 
8903         assert(SysTime.fromISOString("20100704T070612") ==
8904                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8905 
8906         assert(SysTime.fromISOString("19981225T021500.007") ==
8907                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
8908 
8909         assert(SysTime.fromISOString("00000105T230959.00002") ==
8910                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
8911 
8912         assert(SysTime.fromISOString("20130207T043937.000050392") ==
8913                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
8914 
8915         assert(SysTime.fromISOString("-00040105T000002") ==
8916                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
8917 
8918         assert(SysTime.fromISOString(" 20100704T070612 ") ==
8919                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8920 
8921         assert(SysTime.fromISOString("20100704T070612Z") ==
8922                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
8923 
8924         assert(SysTime.fromISOString("20100704T070612-0800") ==
8925                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8926                        new immutable SimpleTimeZone(hours(-8))));
8927 
8928         assert(SysTime.fromISOString("20100704T070612+0800") ==
8929                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8930                        new immutable SimpleTimeZone(hours(8))));
8931     }
8932 
8933     @safe unittest
8934     {
8935         import core.time;
8936         foreach (str; ["", "20100704000000", "20100704 000000", "20100704t000000",
8937                        "20100704T000000.", "20100704T000000.A", "20100704T000000.Z",
8938                        "20100704T000000.0000000A", "20100704T000000.00000000A",
8939                        "20100704T000000+", "20100704T000000-", "20100704T000000:",
8940                        "20100704T000000-:", "20100704T000000+:", "20100704T000000-1:",
8941                        "20100704T000000+1:", "20100704T000000+1:0",
8942                        "20100704T000000-12.00", "20100704T000000+12.00",
8943                        "20100704T000000-8", "20100704T000000+8",
8944                        "20100704T000000-800", "20100704T000000+800",
8945                        "20100704T000000-080", "20100704T000000+080",
8946                        "20100704T000000-2400", "20100704T000000+2400",
8947                        "20100704T000000-1260", "20100704T000000+1260",
8948                        "20100704T000000.0-8", "20100704T000000.0+8",
8949                        "20100704T000000.0-800", "20100704T000000.0+800",
8950                        "20100704T000000.0-080", "20100704T000000.0+080",
8951                        "20100704T000000.0-2400", "20100704T000000.0+2400",
8952                        "20100704T000000.0-1260", "20100704T000000.0+1260",
8953                        "20100704T000000-8:00", "20100704T000000+8:00",
8954                        "20100704T000000-08:0", "20100704T000000+08:0",
8955                        "20100704T000000-24:00", "20100704T000000+24:00",
8956                        "20100704T000000-12:60", "20100704T000000+12:60",
8957                        "20100704T000000.0-8:00", "20100704T000000.0+8:00",
8958                        "20100704T000000.0-08:0", "20100704T000000.0+08:0",
8959                        "20100704T000000.0-24:00", "20100704T000000.0+24:00",
8960                        "20100704T000000.0-12:60", "20100704T000000.0+12:60",
8961                        "2010-07-0400:00:00", "2010-07-04 00:00:00",
8962                        "2010-07-04t00:00:00", "2010-07-04T00:00:00.",
8963                        "2010-Jul-0400:00:00", "2010-Jul-04 00:00:00", "2010-Jul-04t00:00:00",
8964                        "2010-Jul-04T00:00:00", "2010-Jul-04 00:00:00.",
8965                        "2010-12-22T172201", "2010-Dec-22 17:22:01"])
8966         {
8967             assertThrown!DateTimeException(SysTime.fromISOString(str), format("[%s]", str));
8968         }
8969 
8970         static void test(string str, SysTime st, size_t line = __LINE__)
8971         {
8972             if (SysTime.fromISOString(str) != st)
8973                 throw new AssertError("unittest failure", __FILE__, line);
8974         }
8975 
8976         test("20101222T172201", SysTime(DateTime(2010, 12, 22, 17, 22, 1)));
8977         test("19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8978         test("-19990706T123033", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
8979         test("+019990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8980         test("19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8981         test(" 19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8982         test(" 19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8983 
8984         test("19070707T121212.0", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
8985         test("19070707T121212.0000000", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
8986         test("19070707T121212.0000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), hnsecs(1)));
8987         test("20100704T000000.00000000", SysTime(Date(2010, 7, 4)));
8988         test("20100704T000000.00000009", SysTime(Date(2010, 7, 4)));
8989         test("20100704T000000.00000019", SysTime(DateTime(2010, 7, 4), hnsecs(1)));
8990         test("19070707T121212.000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
8991         test("19070707T121212.0000010", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
8992         test("19070707T121212.001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
8993         test("19070707T121212.0010000", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
8994 
8995         auto west60 = new immutable SimpleTimeZone(hours(-1));
8996         auto west90 = new immutable SimpleTimeZone(minutes(-90));
8997         auto west480 = new immutable SimpleTimeZone(hours(-8));
8998         auto east60 = new immutable SimpleTimeZone(hours(1));
8999         auto east90 = new immutable SimpleTimeZone(minutes(90));
9000         auto east480 = new immutable SimpleTimeZone(hours(8));
9001 
9002         test("20101222T172201Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), UTC()));
9003         test("20101222T172201-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9004         test("20101222T172201-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9005         test("20101222T172201-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
9006         test("20101222T172201-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
9007         test("20101222T172201+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9008         test("20101222T172201+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9009         test("20101222T172201+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9010         test("20101222T172201+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
9011 
9012         test("20101103T065106.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
9013         test("20101222T172201.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_341_200), UTC()));
9014         test("20101222T172201.23112-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9015         test("20101222T172201.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), west60));
9016         test("20101222T172201.1-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
9017         test("20101222T172201.55-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
9018         test("20101222T172201.1234567+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
9019         test("20101222T172201.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9020         test("20101222T172201.0000000+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9021         test("20101222T172201.45+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
9022 
9023         // for dstring coverage
9024         assert(SysTime.fromISOString("20101222T172201.23112-0100"d) == SysTime(
9025             DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9026         assert(SysTime.fromISOString("19070707T121212.0010000"d) == SysTime(
9027             DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9028 
9029         // @@@DEPRECATED_2019-07@@@
9030         // This isn't deprecated per se, but that text will make it so that it
9031         // pops up when deprecations are moved along around July 2019. At that
9032         // time, we will update fromISOString so that it is conformant with ISO
9033         // 8601, and it will no longer accept ISO extended time zones (it does
9034         // currently because of https://issues.dlang.org/show_bug.cgi?id=15654
9035         // toISOString used to incorrectly use the ISO extended time zone format).
9036         // These tests will then start failing will need to be updated accordingly.
9037         // Also, the notes about this issue in toISOString and fromISOString's
9038         // documentation will need to be removed.
9039         test("20101222T172201-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9040         test("20101222T172201-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
9041         test("20101222T172201-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
9042         test("20101222T172201+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9043         test("20101222T172201+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9044         test("20101222T172201+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
9045 
9046         test("20101222T172201.23112-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9047         test("20101222T172201.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
9048         test("20101222T172201.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
9049         test("20101222T172201.1234567+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
9050         test("20101222T172201.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9051         test("20101222T172201.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
9052 
9053         static void testScope(scope ref string str) @safe
9054         {
9055             auto result = SysTime.fromISOString(str);
9056         }
9057     }
9058 
9059     // https://issues.dlang.org/show_bug.cgi?id=17801
9060     @safe unittest
9061     {
9062         import std.conv : to;
9063         import std.meta : AliasSeq;
9064         static foreach (C; AliasSeq!(char, wchar, dchar))
9065         {
9066             static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
9067             {
9068                 assert(SysTime.fromISOString(to!S("20121221T141516Z")) ==
9069                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
9070             }
9071         }
9072     }
9073 
9074 
9075     /++
9076         Creates a $(LREF SysTime) from a string with the format
9077         YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
9078         is the time zone). Whitespace is stripped from the given string.
9079 
9080         The exact format is exactly as described in $(LREF toISOExtString)
9081         except that trailing zeroes are permitted - including having fractional
9082         seconds with all zeroes. The time zone and fractional seconds are
9083         optional, however, a decimal point with nothing following it is invalid.
9084         Also, while $(LREF toISOExtString) will never generate a
9085         string with more than 7 digits in the fractional seconds (because that's
9086         the limit with hecto-nanosecond precision), it will allow more than 7
9087         digits in order to read strings from other sources that have higher
9088         precision (however, any digits beyond 7 will be truncated).
9089 
9090         If there is no time zone in the string, then
9091         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
9092         then `UTC` is used. Otherwise, a
9093         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
9094         given offset from UTC is used. To get the returned $(LREF SysTime) to be
9095         a particular time zone, pass in that time zone and the $(LREF SysTime)
9096         to be returned will be converted to that time zone (though it will still
9097         be read in as whatever time zone is in its string).
9098 
9099         The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and
9100         -HH:MM.
9101 
9102         Params:
9103             isoExtString = A string formatted in the ISO Extended format for
9104                            dates and times.
9105             tz           = The time zone to convert the given time to (no
9106                            conversion occurs if null).
9107 
9108         Throws:
9109             $(REF DateTimeException,std,datetime,date) if the given string is
9110             not in the ISO format or if the resulting $(LREF SysTime) would not
9111             be valid.
9112       +/
9113     static SysTime fromISOExtString(S)(scope const S isoExtString, immutable TimeZone tz = null) @safe
9114     if (isSomeString!(S))
9115     {
9116         import std.algorithm.searching : countUntil, find;
9117         import std.conv : to;
9118         import std.string : strip, indexOf;
9119 
9120         auto str = strip(isoExtString);
9121 
9122         auto tIndex = str.indexOf('T');
9123         enforce!DateTimeException(tIndex != -1,
9124                                   format("Invalid format for SysTime.fromISOExtString: %s", isoExtString));
9125 
9126         auto found = str[tIndex + 1 .. $].find('.', 'Z', '+', '-');
9127         auto dateTimeStr = str[0 .. $ - found[0].length];
9128 
9129         typeof(str) foundTZ;  // needs to have longer lifetime than zoneStr
9130         typeof(str) fracSecStr;
9131         typeof(str) zoneStr;
9132 
9133         if (found[1] != 0)
9134         {
9135             if (found[1] == 1)
9136             {
9137                 foundTZ = found[0].find('Z', '+', '-')[0];
9138 
9139                 if (foundTZ.length != 0)
9140                 {
9141                     fracSecStr = found[0][0 .. $ - foundTZ.length];
9142                     zoneStr = foundTZ;
9143                 }
9144                 else
9145                     fracSecStr = found[0];
9146             }
9147             else
9148                 zoneStr = found[0];
9149         }
9150 
9151         try
9152         {
9153             auto dateTime = DateTime.fromISOExtString(dateTimeStr);
9154             auto fracSec = fracSecsFromISOString(fracSecStr);
9155             Rebindable!(immutable TimeZone) parsedZone;
9156 
9157             if (zoneStr.empty)
9158                 parsedZone = LocalTime();
9159             else if (zoneStr == "Z")
9160                 parsedZone = UTC();
9161             else
9162                 parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
9163 
9164             auto retval = SysTime(dateTime, fracSec, parsedZone);
9165 
9166             if (tz !is null)
9167                 retval.timezone = tz;
9168 
9169             return retval;
9170         }
9171         catch (DateTimeException dte)
9172             throw new DateTimeException(format("Invalid format for SysTime.fromISOExtString: %s", isoExtString));
9173     }
9174 
9175     ///
9176     @safe unittest
9177     {
9178         import core.time : hours, msecs, usecs, hnsecs;
9179         import std.datetime.date : DateTime;
9180         import std.datetime.timezone : SimpleTimeZone, UTC;
9181 
9182         assert(SysTime.fromISOExtString("2010-07-04T07:06:12") ==
9183                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9184 
9185         assert(SysTime.fromISOExtString("1998-12-25T02:15:00.007") ==
9186                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
9187 
9188         assert(SysTime.fromISOExtString("0000-01-05T23:09:59.00002") ==
9189                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
9190 
9191         assert(SysTime.fromISOExtString("2013-02-07T04:39:37.000050392") ==
9192                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
9193 
9194         assert(SysTime.fromISOExtString("-0004-01-05T00:00:02") ==
9195                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
9196 
9197         assert(SysTime.fromISOExtString(" 2010-07-04T07:06:12 ") ==
9198                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9199 
9200         assert(SysTime.fromISOExtString("2010-07-04T07:06:12Z") ==
9201                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
9202 
9203         assert(SysTime.fromISOExtString("2010-07-04T07:06:12-08:00") ==
9204                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9205                        new immutable SimpleTimeZone(hours(-8))));
9206         assert(SysTime.fromISOExtString("2010-07-04T07:06:12+08:00") ==
9207                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9208                        new immutable SimpleTimeZone(hours(8))));
9209     }
9210 
9211     @safe unittest
9212     {
9213         import core.time;
9214         foreach (str; ["", "20100704000000", "20100704 000000",
9215                        "20100704t000000", "20100704T000000.", "20100704T000000.0",
9216                        "2010-07:0400:00:00", "2010-07-04 00:00:00",
9217                        "2010-07-04 00:00:00", "2010-07-04t00:00:00",
9218                        "2010-07-04T00:00:00.", "2010-07-04T00:00:00.A", "2010-07-04T00:00:00.Z",
9219                        "2010-07-04T00:00:00.0000000A", "2010-07-04T00:00:00.00000000A",
9220                        "2010-07-04T00:00:00+", "2010-07-04T00:00:00-",
9221                        "2010-07-04T00:00:00:", "2010-07-04T00:00:00-:", "2010-07-04T00:00:00+:",
9222                        "2010-07-04T00:00:00-1:", "2010-07-04T00:00:00+1:", "2010-07-04T00:00:00+1:0",
9223                        "2010-07-04T00:00:00-12.00", "2010-07-04T00:00:00+12.00",
9224                        "2010-07-04T00:00:00-8", "2010-07-04T00:00:00+8",
9225                        "20100704T000000-800", "20100704T000000+800",
9226                        "20100704T000000-080", "20100704T000000+080",
9227                        "20100704T000000-2400", "20100704T000000+2400",
9228                        "20100704T000000-1260", "20100704T000000+1260",
9229                        "20100704T000000.0-800", "20100704T000000.0+800",
9230                        "20100704T000000.0-8", "20100704T000000.0+8",
9231                        "20100704T000000.0-080", "20100704T000000.0+080",
9232                        "20100704T000000.0-2400", "20100704T000000.0+2400",
9233                        "20100704T000000.0-1260", "20100704T000000.0+1260",
9234                        "2010-07-04T00:00:00-8:00", "2010-07-04T00:00:00+8:00",
9235                        "2010-07-04T00:00:00-24:00", "2010-07-04T00:00:00+24:00",
9236                        "2010-07-04T00:00:00-12:60", "2010-07-04T00:00:00+12:60",
9237                        "2010-07-04T00:00:00.0-8:00", "2010-07-04T00:00:00.0+8:00",
9238                        "2010-07-04T00:00:00.0-8", "2010-07-04T00:00:00.0+8",
9239                        "2010-07-04T00:00:00.0-24:00", "2010-07-04T00:00:00.0+24:00",
9240                        "2010-07-04T00:00:00.0-12:60", "2010-07-04T00:00:00.0+12:60",
9241                        "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00",
9242                        "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.0",
9243                        "20101222T172201", "2010-Dec-22 17:22:01"])
9244         {
9245             assertThrown!DateTimeException(SysTime.fromISOExtString(str), format("[%s]", str));
9246         }
9247 
9248         static void test(string str, SysTime st, size_t line = __LINE__)
9249         {
9250             if (SysTime.fromISOExtString(str) != st)
9251                 throw new AssertError("unittest failure", __FILE__, line);
9252         }
9253 
9254         test("2010-12-22T17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 1)));
9255         test("1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9256         test("-1999-07-06T12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
9257         test("+01999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9258         test("1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9259         test(" 1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9260         test(" 1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9261 
9262         test("1907-07-07T12:12:12.0", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9263         test("1907-07-07T12:12:12.0000000", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9264         test("1907-07-07T12:12:12.0000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), hnsecs(1)));
9265         test("2010-07-04T00:00:00.00000000", SysTime(Date(2010, 7, 4)));
9266         test("2010-07-04T00:00:00.00000009", SysTime(Date(2010, 7, 4)));
9267         test("2010-07-04T00:00:00.00000019", SysTime(DateTime(2010, 7, 4), hnsecs(1)));
9268         test("1907-07-07T12:12:12.000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9269         test("1907-07-07T12:12:12.0000010", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9270         test("1907-07-07T12:12:12.001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9271         test("1907-07-07T12:12:12.0010000", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9272 
9273         auto west60 = new immutable SimpleTimeZone(hours(-1));
9274         auto west90 = new immutable SimpleTimeZone(minutes(-90));
9275         auto west480 = new immutable SimpleTimeZone(hours(-8));
9276         auto east60 = new immutable SimpleTimeZone(hours(1));
9277         auto east90 = new immutable SimpleTimeZone(minutes(90));
9278         auto east480 = new immutable SimpleTimeZone(hours(8));
9279 
9280         test("2010-12-22T17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), UTC()));
9281         test("2010-12-22T17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9282         test("2010-12-22T17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9283         test("2010-12-22T17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
9284         test("2010-12-22T17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
9285         test("2010-12-22T17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9286         test("2010-12-22T17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9287         test("2010-12-22T17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9288         test("2010-12-22T17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
9289 
9290         test("2010-11-03T06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
9291         test("2010-12-22T17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_341_200), UTC()));
9292         test("2010-12-22T17:22:01.23112-01:00",
9293              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9294         test("2010-12-22T17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), west60));
9295         test("2010-12-22T17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
9296         test("2010-12-22T17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
9297         test("2010-12-22T17:22:01.1234567+01:00",
9298              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
9299         test("2010-12-22T17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9300         test("2010-12-22T17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9301         test("2010-12-22T17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
9302 
9303         static void testScope(scope ref string str) @safe
9304         {
9305             auto result = SysTime.fromISOExtString(str);
9306         }
9307     }
9308 
9309     // https://issues.dlang.org/show_bug.cgi?id=17801
9310     @safe unittest
9311     {
9312         import core.time;
9313         import std.conv : to;
9314         import std.meta : AliasSeq;
9315         static foreach (C; AliasSeq!(char, wchar, dchar))
9316         {
9317             static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
9318             {
9319                 assert(SysTime.fromISOExtString(to!S("2012-12-21T14:15:16Z")) ==
9320                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
9321             }
9322         }
9323     }
9324 
9325 
9326     /++
9327         Creates a $(LREF SysTime) from a string with the format
9328         YYYY-Mon-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
9329         is the time zone). Whitespace is stripped from the given string.
9330 
9331         The exact format is exactly as described in $(LREF toSimpleString) except
9332         that trailing zeroes are permitted - including having fractional seconds
9333         with all zeroes. The time zone and fractional seconds are optional,
9334         however, a decimal point with nothing following it is invalid.
9335         Also, while $(LREF toSimpleString) will never generate a
9336         string with more than 7 digits in the fractional seconds (because that's
9337         the limit with hecto-nanosecond precision), it will allow more than 7
9338         digits in order to read strings from other sources that have higher
9339         precision (however, any digits beyond 7 will be truncated).
9340 
9341         If there is no time zone in the string, then
9342         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
9343         then `UTC` is used. Otherwise, a
9344         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
9345         given offset from UTC is used. To get the returned $(LREF SysTime) to be
9346         a particular time zone, pass in that time zone and the $(LREF SysTime)
9347         to be returned will be converted to that time zone (though it will still
9348         be read in as whatever time zone is in its string).
9349 
9350         The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and
9351         -HH:MM.
9352 
9353         Params:
9354             simpleString = A string formatted in the way that
9355                            `toSimpleString` formats dates and times.
9356             tz           = The time zone to convert the given time to (no
9357                            conversion occurs if null).
9358 
9359         Throws:
9360             $(REF DateTimeException,std,datetime,date) if the given string is
9361             not in the ISO format or if the resulting $(LREF SysTime) would not
9362             be valid.
9363       +/
9364     static SysTime fromSimpleString(S)(scope const S simpleString, immutable TimeZone tz = null) @safe
9365     if (isSomeString!(S))
9366     {
9367         import std.algorithm.searching : find;
9368         import std.conv : to;
9369         import std.string : strip, indexOf;
9370 
9371         auto str = strip(simpleString);
9372 
9373         auto spaceIndex = str.indexOf(' ');
9374         enforce!DateTimeException(spaceIndex != -1,
9375                                   format("Invalid format for SysTime.fromSimpleString: %s", simpleString));
9376 
9377         auto found = str[spaceIndex + 1 .. $].find('.', 'Z', '+', '-');
9378         auto dateTimeStr = str[0 .. $ - found[0].length];
9379 
9380         typeof(str) foundTZ;  // needs to have longer lifetime than zoneStr
9381         typeof(str) fracSecStr;
9382         typeof(str) zoneStr;
9383 
9384         if (found[1] != 0)
9385         {
9386             if (found[1] == 1)
9387             {
9388                 foundTZ = found[0].find('Z', '+', '-')[0];
9389 
9390                 if (foundTZ.length != 0)
9391                 {
9392                     fracSecStr = found[0][0 .. $ - foundTZ.length];
9393                     zoneStr = foundTZ;
9394                 }
9395                 else
9396                     fracSecStr = found[0];
9397             }
9398             else
9399                 zoneStr = found[0];
9400         }
9401 
9402         try
9403         {
9404             auto dateTime = DateTime.fromSimpleString(dateTimeStr);
9405             auto fracSec = fracSecsFromISOString(fracSecStr);
9406             Rebindable!(immutable TimeZone) parsedZone;
9407 
9408             if (zoneStr.empty)
9409                 parsedZone = LocalTime();
9410             else if (zoneStr == "Z")
9411                 parsedZone = UTC();
9412             else
9413                 parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
9414 
9415             auto retval = SysTime(dateTime, fracSec, parsedZone);
9416 
9417             if (tz !is null)
9418                 retval.timezone = tz;
9419 
9420             return retval;
9421         }
9422         catch (DateTimeException dte)
9423             throw new DateTimeException(format("Invalid format for SysTime.fromSimpleString: %s", simpleString));
9424     }
9425 
9426     ///
9427     @safe unittest
9428     {
9429         import core.time : hours, msecs, usecs, hnsecs;
9430         import std.datetime.date : DateTime;
9431         import std.datetime.timezone : SimpleTimeZone, UTC;
9432 
9433         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12") ==
9434                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9435 
9436         assert(SysTime.fromSimpleString("1998-Dec-25 02:15:00.007") ==
9437                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
9438 
9439         assert(SysTime.fromSimpleString("0000-Jan-05 23:09:59.00002") ==
9440                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
9441 
9442         assert(SysTime.fromSimpleString("2013-Feb-07 04:39:37.000050392") ==
9443                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
9444 
9445         assert(SysTime.fromSimpleString("-0004-Jan-05 00:00:02") ==
9446                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
9447 
9448         assert(SysTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") ==
9449                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9450 
9451         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12Z") ==
9452                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
9453 
9454         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12-08:00") ==
9455                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9456                        new immutable SimpleTimeZone(hours(-8))));
9457 
9458         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12+08:00") ==
9459                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9460                        new immutable SimpleTimeZone(hours(8))));
9461     }
9462 
9463     @safe unittest
9464     {
9465         import core.time;
9466         foreach (str; ["", "20100704000000", "20100704 000000",
9467                        "20100704t000000", "20100704T000000.", "20100704T000000.0",
9468                        "2010-07-0400:00:00", "2010-07-04 00:00:00", "2010-07-04t00:00:00",
9469                        "2010-07-04T00:00:00.", "2010-07-04T00:00:00.0",
9470                        "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00", "2010-Jul-04T00:00:00",
9471                        "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.A", "2010-Jul-04 00:00:00.Z",
9472                        "2010-Jul-04 00:00:00.0000000A", "2010-Jul-04 00:00:00.00000000A",
9473                        "2010-Jul-04 00:00:00+", "2010-Jul-04 00:00:00-",
9474                        "2010-Jul-04 00:00:00:", "2010-Jul-04 00:00:00-:",
9475                        "2010-Jul-04 00:00:00+:", "2010-Jul-04 00:00:00-1:",
9476                        "2010-Jul-04 00:00:00+1:", "2010-Jul-04 00:00:00+1:0",
9477                        "2010-Jul-04 00:00:00-12.00", "2010-Jul-04 00:00:00+12.00",
9478                        "2010-Jul-04 00:00:00-8", "2010-Jul-04 00:00:00+8",
9479                        "20100704T000000-800", "20100704T000000+800",
9480                        "20100704T000000-080", "20100704T000000+080",
9481                        "20100704T000000-2400", "20100704T000000+2400",
9482                        "20100704T000000-1260", "20100704T000000+1260",
9483                        "20100704T000000.0-800", "20100704T000000.0+800",
9484                        "20100704T000000.0-8", "20100704T000000.0+8",
9485                        "20100704T000000.0-080", "20100704T000000.0+080",
9486                        "20100704T000000.0-2400", "20100704T000000.0+2400",
9487                        "20100704T000000.0-1260", "20100704T000000.0+1260",
9488                        "2010-Jul-04 00:00:00-8:00", "2010-Jul-04 00:00:00+8:00",
9489                        "2010-Jul-04 00:00:00-08:0", "2010-Jul-04 00:00:00+08:0",
9490                        "2010-Jul-04 00:00:00-24:00", "2010-Jul-04 00:00:00+24:00",
9491                        "2010-Jul-04 00:00:00-12:60", "2010-Jul-04 00:00:00+24:60",
9492                        "2010-Jul-04 00:00:00.0-8:00", "2010-Jul-04 00:00:00+8:00",
9493                        "2010-Jul-04 00:00:00.0-8", "2010-Jul-04 00:00:00.0+8",
9494                        "2010-Jul-04 00:00:00.0-08:0", "2010-Jul-04 00:00:00.0+08:0",
9495                        "2010-Jul-04 00:00:00.0-24:00", "2010-Jul-04 00:00:00.0+24:00",
9496                        "2010-Jul-04 00:00:00.0-12:60", "2010-Jul-04 00:00:00.0+24:60",
9497                        "20101222T172201", "2010-12-22T172201"])
9498         {
9499             assertThrown!DateTimeException(SysTime.fromSimpleString(str), format("[%s]", str));
9500         }
9501 
9502         static void test(string str, SysTime st, size_t line = __LINE__)
9503         {
9504             if (SysTime.fromSimpleString(str) != st)
9505                 throw new AssertError("unittest failure", __FILE__, line);
9506         }
9507 
9508         test("2010-Dec-22 17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 1)));
9509         test("1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9510         test("-1999-Jul-06 12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
9511         test("+01999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9512         test("1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9513         test(" 1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9514         test(" 1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9515 
9516         test("1907-Jul-07 12:12:12.0", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9517         test("1907-Jul-07 12:12:12.0000000", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9518         test("2010-Jul-04 00:00:00.00000000", SysTime(Date(2010, 7, 4)));
9519         test("2010-Jul-04 00:00:00.00000009", SysTime(Date(2010, 7, 4)));
9520         test("2010-Jul-04 00:00:00.00000019", SysTime(DateTime(2010, 7, 4), hnsecs(1)));
9521         test("1907-Jul-07 12:12:12.0000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), hnsecs(1)));
9522         test("1907-Jul-07 12:12:12.000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9523         test("1907-Jul-07 12:12:12.0000010", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9524         test("1907-Jul-07 12:12:12.001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9525         test("1907-Jul-07 12:12:12.0010000", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9526 
9527         auto west60 = new immutable SimpleTimeZone(hours(-1));
9528         auto west90 = new immutable SimpleTimeZone(minutes(-90));
9529         auto west480 = new immutable SimpleTimeZone(hours(-8));
9530         auto east60 = new immutable SimpleTimeZone(hours(1));
9531         auto east90 = new immutable SimpleTimeZone(minutes(90));
9532         auto east480 = new immutable SimpleTimeZone(hours(8));
9533 
9534         test("2010-Dec-22 17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), UTC()));
9535         test("2010-Dec-22 17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9536         test("2010-Dec-22 17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9537         test("2010-Dec-22 17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
9538         test("2010-Dec-22 17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
9539         test("2010-Dec-22 17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9540         test("2010-Dec-22 17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9541         test("2010-Dec-22 17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9542         test("2010-Dec-22 17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
9543 
9544         test("2010-Nov-03 06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
9545         test("2010-Dec-22 17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_341_200), UTC()));
9546         test("2010-Dec-22 17:22:01.23112-01:00",
9547              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9548         test("2010-Dec-22 17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), west60));
9549         test("2010-Dec-22 17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
9550         test("2010-Dec-22 17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
9551         test("2010-Dec-22 17:22:01.1234567+01:00",
9552              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
9553         test("2010-Dec-22 17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9554         test("2010-Dec-22 17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9555         test("2010-Dec-22 17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
9556 
9557         static void testScope(scope ref string str) @safe
9558         {
9559             auto result = SysTime.fromSimpleString(str);
9560         }
9561     }
9562 
9563     // https://issues.dlang.org/show_bug.cgi?id=17801
9564     @safe unittest
9565     {
9566         import core.time;
9567         import std.conv : to;
9568         import std.meta : AliasSeq;
9569         static foreach (C; AliasSeq!(char, wchar, dchar))
9570         {
9571             static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
9572             {
9573                 assert(SysTime.fromSimpleString(to!S("2012-Dec-21 14:15:16Z")) ==
9574                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
9575             }
9576         }
9577     }
9578 
9579 
9580     /++
9581         Returns the $(LREF SysTime) farthest in the past which is representable
9582         by $(LREF SysTime).
9583 
9584         The $(LREF SysTime) which is returned is in UTC.
9585       +/
9586     @property static SysTime min() @safe pure nothrow
9587     {
9588         return SysTime(long.min, UTC());
9589     }
9590 
9591     @safe unittest
9592     {
9593         assert(SysTime.min.year < 0);
9594         assert(SysTime.min < SysTime.max);
9595     }
9596 
9597 
9598     /++
9599         Returns the $(LREF SysTime) farthest in the future which is representable
9600         by $(LREF SysTime).
9601 
9602         The $(LREF SysTime) which is returned is in UTC.
9603       +/
9604     @property static SysTime max() @safe pure nothrow
9605     {
9606         return SysTime(long.max, UTC());
9607     }
9608 
9609     @safe unittest
9610     {
9611         assert(SysTime.max.year > 0);
9612         assert(SysTime.max > SysTime.min);
9613     }
9614 
9615 
9616 private:
9617 
9618     /+
9619         Returns `stdTime` converted to $(LREF SysTime)'s time zone.
9620       +/
9621     @property long adjTime() @safe const nothrow scope
9622     {
9623         return _timezone.utcToTZ(_stdTime);
9624     }
9625 
9626 
9627     /+
9628         Converts the given hnsecs from $(LREF SysTime)'s time zone to std time.
9629       +/
9630     @property void adjTime(long adjTime) @safe nothrow scope
9631     {
9632         _stdTime = _timezone.tzToUTC(adjTime);
9633     }
9634 
9635 
9636     final class InitTimeZone : TimeZone
9637     {
9638     public:
9639 
9640         static immutable(InitTimeZone) opCall() @safe pure nothrow @nogc { return _initTimeZone; }
9641 
9642         @property override bool hasDST() @safe const nothrow @nogc { return false; }
9643 
9644         override bool dstInEffect(long stdTime) @safe const scope nothrow @nogc { return false; }
9645 
9646         override long utcToTZ(long stdTime) @safe const scope nothrow @nogc { return 0; }
9647 
9648         override long tzToUTC(long adjTime) @safe const scope nothrow @nogc { return 0; }
9649 
9650         override Duration utcOffsetAt(long stdTime) @safe const scope nothrow @nogc { return Duration.zero; }
9651 
9652     private:
9653 
9654         this() @safe immutable pure
9655         {
9656             super("SysTime.init's timezone", "SysTime.init's timezone", "SysTime.init's timezone");
9657         }
9658 
9659         static immutable InitTimeZone _initTimeZone = new immutable(InitTimeZone);
9660     }
9661 
9662     // https://issues.dlang.org/show_bug.cgi?id=17732
9663     @safe unittest
9664     {
9665         assert(SysTime.init.timezone is InitTimeZone());
9666         assert(SysTime.init.toISOString() == "00010101T000000+00:00");
9667         assert(SysTime.init.toISOExtString() == "0001-01-01T00:00:00+00:00");
9668         assert(SysTime.init.toSimpleString() == "0001-Jan-01 00:00:00+00:00");
9669         assert(SysTime.init.toString() == "0001-Jan-01 00:00:00+00:00");
9670     }
9671 
9672     // Assigning a value to _timezone in SysTime.init currently doesn't work due
9673     // to https://issues.dlang.org/show_bug.cgi?id=17740. So, to hack around
9674     // that problem, these accessors have been added so that we can insert a
9675     // runtime check for null and then use InitTimeZone for SysTime.init (which
9676     // which is the only case where _timezone would be null). This thus fixes
9677     // the problem with segfaulting when using SysTime.init but at the cost of
9678     // what should be an unnecessary null check. Once 17740 has finally been
9679     // fixed, _timezoneStorage should be removed, these accessors should be
9680     // removed, and the _timezone variable declaration should be restored.
9681     pragma(inline, true) @property _timezone() @safe const pure nothrow @nogc
9682     {
9683         return _timezoneStorage is null ? InitTimeZone() : _timezoneStorage;
9684     }
9685 
9686     pragma(inline, true) @property void _timezone(return scope immutable TimeZone tz) @safe pure nothrow @nogc scope
9687     {
9688         _timezoneStorage = tz;
9689     }
9690 
9691 
9692     long  _stdTime;
9693     Rebindable!(immutable TimeZone) _timezoneStorage;
9694     //Rebindable!(immutable TimeZone) _timezone = InitTimeZone();
9695 }
9696 
9697 ///
9698 @safe unittest
9699 {
9700     import core.time : days, hours, seconds;
9701     import std.datetime.date : Date, DateTime;
9702     import std.datetime.timezone : SimpleTimeZone, UTC;
9703 
9704     const dt = DateTime(2018, 1, 1, 10, 30, 0);
9705     // make a specific point in time in the UTC timezone
9706     auto st = SysTime(dt, UTC());
9707     assert(st.year == 2018);
9708     assert(st.hour == 10);
9709 
9710     // cast to convert
9711     assert(cast(DateTime) st == dt);
9712     assert(cast(Date) st == Date(2018, 1, 1));
9713 
9714     // make a specific point in time in the New York timezone
9715     const ny = SysTime(dt,
9716         new immutable SimpleTimeZone(-5.hours, "America/New_York")
9717     );
9718     assert(ny != st);
9719     assert(ny.hour == 10);
9720 
9721     // ISO standard time strings
9722     assert(st.toISOString() == "20180101T103000Z");
9723     assert(st.toISOExtString() == "2018-01-01T10:30:00Z");
9724 
9725     // add two days and 30 seconds
9726     st += 2.days + 30.seconds;
9727     assert(st.toISOExtString() == "2018-01-03T10:30:30Z");
9728 }
9729 
9730 
9731 /++
9732     Converts from unix time (which uses midnight, January 1st, 1970 UTC as its
9733     epoch and seconds as its units) to "std time" (which uses midnight,
9734     January 1st, 1 A.D. UTC and hnsecs as its units).
9735 
9736     The C standard does not specify the representation of time_t, so it is
9737     implementation defined. On POSIX systems, unix time is equivalent to
9738     time_t, but that's not necessarily true on other systems (e.g. it is
9739     not true for the Digital Mars C runtime). So, be careful when using unix
9740     time with C functions on non-POSIX systems.
9741 
9742     "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO
9743     8601 and is what $(LREF SysTime) uses internally. However, holding the time
9744     as an integer in hnsecs since that epoch technically isn't actually part of
9745     the standard, much as it's based on it, so the name "std time" isn't
9746     particularly good, but there isn't an official name for it. C# uses "ticks"
9747     for the same thing, but they aren't actually clock ticks, and the term
9748     "ticks" $(I is) used for actual clock ticks for $(REF MonoTime, core,time),
9749     so it didn't make sense to use the term ticks here. So, for better or worse,
9750     std.datetime uses the term "std time" for this.
9751 
9752     Params:
9753         unixTime = The unix time to convert.
9754 
9755     See_Also:
9756         SysTime.fromUnixTime
9757   +/
9758 long unixTimeToStdTime(long unixTime) @safe pure nothrow @nogc
9759 {
9760     return 621_355_968_000_000_000L + convert!("seconds", "hnsecs")(unixTime);
9761 }
9762 
9763 ///
9764 @safe unittest
9765 {
9766     import std.datetime.date : DateTime;
9767     import std.datetime.timezone : UTC;
9768 
9769     // Midnight, January 1st, 1970
9770     assert(unixTimeToStdTime(0) == 621_355_968_000_000_000L);
9771     assert(SysTime(unixTimeToStdTime(0)) ==
9772            SysTime(DateTime(1970, 1, 1), UTC()));
9773 
9774     assert(unixTimeToStdTime(int.max) == 642_830_804_470_000_000L);
9775     assert(SysTime(unixTimeToStdTime(int.max)) ==
9776            SysTime(DateTime(2038, 1, 19, 3, 14, 7), UTC()));
9777 
9778     assert(unixTimeToStdTime(-127_127) == 621_354_696_730_000_000L);
9779     assert(SysTime(unixTimeToStdTime(-127_127)) ==
9780            SysTime(DateTime(1969, 12, 30, 12, 41, 13), UTC()));
9781 }
9782 
9783 @safe unittest
9784 {
9785     // Midnight, January 2nd, 1970
9786     assert(unixTimeToStdTime(86_400) == 621_355_968_000_000_000L + 864_000_000_000L);
9787     // Midnight, December 31st, 1969
9788     assert(unixTimeToStdTime(-86_400) == 621_355_968_000_000_000L - 864_000_000_000L);
9789 
9790     assert(unixTimeToStdTime(0) == (Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs");
9791     assert(unixTimeToStdTime(0) == (DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs");
9792 
9793     foreach (dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)])
9794         assert(unixTimeToStdTime((dt - DateTime(1970, 1, 1)).total!"seconds") == (dt - DateTime.init).total!"hnsecs");
9795 }
9796 
9797 
9798 /++
9799     Converts std time (which uses midnight, January 1st, 1 A.D. UTC as its epoch
9800     and hnsecs as its units) to unix time (which uses midnight, January 1st,
9801     1970 UTC as its epoch and seconds as its units).
9802 
9803     The C standard does not specify the representation of time_t, so it is
9804     implementation defined. On POSIX systems, unix time is equivalent to
9805     time_t, but that's not necessarily true on other systems (e.g. it is
9806     not true for the Digital Mars C runtime). So, be careful when using unix
9807     time with C functions on non-POSIX systems.
9808 
9809     "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO
9810     8601 and is what $(LREF SysTime) uses internally. However, holding the time
9811     as an integer in hnsecs since that epoch technically isn't actually part of
9812     the standard, much as it's based on it, so the name "std time" isn't
9813     particularly good, but there isn't an official name for it. C# uses "ticks"
9814     for the same thing, but they aren't actually clock ticks, and the term
9815     "ticks" $(I is) used for actual clock ticks for $(REF MonoTime, core,time),
9816     so it didn't make sense to use the term ticks here. So, for better or worse,
9817     std.datetime uses the term "std time" for this.
9818 
9819     By default, the return type is time_t (which is normally an alias for
9820     int on 32-bit systems and long on 64-bit systems), but if a different
9821     size is required than either int or long can be passed as a template
9822     argument to get the desired size.
9823 
9824     If the return type is int, and the result can't fit in an int, then the
9825     closest value that can be held in 32 bits will be used (so `int.max`
9826     if it goes over and `int.min` if it goes under). However, no attempt
9827     is made to deal with integer overflow if the return type is long.
9828 
9829     Params:
9830         T = The return type (int or long). It defaults to time_t, which is
9831             normally 32 bits on a 32-bit system and 64 bits on a 64-bit
9832             system.
9833         stdTime = The std time to convert.
9834 
9835     Returns:
9836         A signed integer representing the unix time which is equivalent to
9837         the given std time.
9838 
9839     See_Also:
9840         SysTime.toUnixTime
9841   +/
9842 T stdTimeToUnixTime(T = time_t)(long stdTime) @safe pure nothrow
9843 if (is(T == int) || is(T == long))
9844 {
9845     immutable unixTime = convert!("hnsecs", "seconds")(stdTime - 621_355_968_000_000_000L);
9846 
9847     static assert(is(time_t == int) || is(time_t == long),
9848                   "Currently, std.datetime only supports systems where time_t is int or long");
9849 
9850     static if (is(T == long))
9851         return unixTime;
9852     else static if (is(T == int))
9853     {
9854         if (unixTime > int.max)
9855             return int.max;
9856         return unixTime < int.min ? int.min : cast(int) unixTime;
9857     }
9858     else
9859         static assert(0, "Bug in template constraint. Only int and long allowed.");
9860 }
9861 
9862 ///
9863 @safe unittest
9864 {
9865     // Midnight, January 1st, 1970 UTC
9866     assert(stdTimeToUnixTime(621_355_968_000_000_000L) == 0);
9867 
9868     // 2038-01-19 03:14:07 UTC
9869     assert(stdTimeToUnixTime(642_830_804_470_000_000L) == int.max);
9870 }
9871 
9872 @safe unittest
9873 {
9874     enum unixEpochAsStdTime = (Date(1970, 1, 1) - Date.init).total!"hnsecs";
9875 
9876     assert(stdTimeToUnixTime(unixEpochAsStdTime) == 0);  // Midnight, January 1st, 1970
9877     assert(stdTimeToUnixTime(unixEpochAsStdTime + 864_000_000_000L) == 86_400);  // Midnight, January 2nd, 1970
9878     assert(stdTimeToUnixTime(unixEpochAsStdTime - 864_000_000_000L) == -86_400);  // Midnight, December 31st, 1969
9879 
9880     assert(stdTimeToUnixTime((Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs") == 0);
9881     assert(stdTimeToUnixTime((DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs") == 0);
9882 
9883     foreach (dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)])
9884         assert(stdTimeToUnixTime((dt - DateTime.init).total!"hnsecs") == (dt - DateTime(1970, 1, 1)).total!"seconds");
9885 
9886     enum max = convert!("seconds", "hnsecs")(int.max);
9887     enum min = convert!("seconds", "hnsecs")(int.min);
9888     enum one = convert!("seconds", "hnsecs")(1);
9889 
9890     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max) == int.max);
9891     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max) == int.max);
9892 
9893     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + one) == int.max + 1L);
9894     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + one) == int.max);
9895     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + 9_999_999) == int.max);
9896     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + 9_999_999) == int.max);
9897 
9898     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min) == int.min);
9899     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min) == int.min);
9900 
9901     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - one) == int.min - 1L);
9902     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - one) == int.min);
9903     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - 9_999_999) == int.min);
9904     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - 9_999_999) == int.min);
9905 }
9906 
9907 
9908 version (StdDdoc)
9909 {
9910     version (Windows)
9911     {}
9912     else
9913     {
9914         alias SYSTEMTIME = void*;
9915         alias FILETIME = void*;
9916     }
9917 
9918     /++
9919         $(BLUE This function is Windows-Only.)
9920 
9921         Converts a `SYSTEMTIME` struct to a $(LREF SysTime).
9922 
9923         Params:
9924             st = The `SYSTEMTIME` struct to convert.
9925             tz = The time zone that the time in the `SYSTEMTIME` struct is
9926                  assumed to be (if the `SYSTEMTIME` was supplied by a Windows
9927                  system call, the `SYSTEMTIME` will either be in local time
9928                  or UTC, depending on the call).
9929 
9930         Throws:
9931             $(REF DateTimeException,std,datetime,date) if the given
9932             `SYSTEMTIME` will not fit in a $(LREF SysTime), which is highly
9933             unlikely to happen given that `SysTime.max` is in 29,228 A.D. and
9934             the maximum `SYSTEMTIME` is in 30,827 A.D.
9935       +/
9936     SysTime SYSTEMTIMEToSysTime(const scope SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe;
9937 
9938 
9939     /++
9940         $(BLUE This function is Windows-Only.)
9941 
9942         Converts a $(LREF SysTime) to a `SYSTEMTIME` struct.
9943 
9944         The `SYSTEMTIME` which is returned will be set using the given
9945         $(LREF SysTime)'s time zone, so to get the `SYSTEMTIME` in
9946         UTC, set the $(LREF SysTime)'s time zone to UTC.
9947 
9948         Params:
9949             sysTime = The $(LREF SysTime) to convert.
9950 
9951         Throws:
9952             $(REF DateTimeException,std,datetime,date) if the given
9953             $(LREF SysTime) will not fit in a `SYSTEMTIME`. This will only
9954             happen if the $(LREF SysTime)'s date is prior to 1601 A.D.
9955       +/
9956     SYSTEMTIME SysTimeToSYSTEMTIME(scope SysTime sysTime) @safe;
9957 
9958 
9959     /++
9960         $(BLUE This function is Windows-Only.)
9961 
9962         Converts a `FILETIME` struct to the number of hnsecs since midnight,
9963         January 1st, 1 A.D.
9964 
9965         Params:
9966             ft = The `FILETIME` struct to convert.
9967 
9968         Throws:
9969             $(REF DateTimeException,std,datetime,date) if the given
9970             `FILETIME` cannot be represented as the return value.
9971       +/
9972     long FILETIMEToStdTime(scope const FILETIME* ft) @safe;
9973 
9974 
9975     /++
9976         $(BLUE This function is Windows-Only.)
9977 
9978         Converts a `FILETIME` struct to a $(LREF SysTime).
9979 
9980         Params:
9981             ft = The `FILETIME` struct to convert.
9982             tz = The time zone that the $(LREF SysTime) will be in
9983                  (`FILETIME`s are in UTC).
9984 
9985         Throws:
9986             $(REF DateTimeException,std,datetime,date) if the given
9987             `FILETIME` will not fit in a $(LREF SysTime).
9988       +/
9989     SysTime FILETIMEToSysTime(scope const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe;
9990 
9991 
9992     /++
9993         $(BLUE This function is Windows-Only.)
9994 
9995         Converts a number of hnsecs since midnight, January 1st, 1 A.D. to a
9996         `FILETIME` struct.
9997 
9998         Params:
9999             stdTime = The number of hnsecs since midnight, January 1st, 1 A.D.
10000                       UTC.
10001 
10002         Throws:
10003             $(REF DateTimeException,std,datetime,date) if the given value will
10004             not fit in a `FILETIME`.
10005       +/
10006     FILETIME stdTimeToFILETIME(long stdTime) @safe;
10007 
10008 
10009     /++
10010         $(BLUE This function is Windows-Only.)
10011 
10012         Converts a $(LREF SysTime) to a `FILETIME` struct.
10013 
10014         `FILETIME`s are always in UTC.
10015 
10016         Params:
10017             sysTime = The $(LREF SysTime) to convert.
10018 
10019         Throws:
10020             $(REF DateTimeException,std,datetime,date) if the given
10021             $(LREF SysTime) will not fit in a `FILETIME`.
10022       +/
10023     FILETIME SysTimeToFILETIME(scope SysTime sysTime) @safe;
10024 }
10025 else version (Windows)
10026 {
10027     SysTime SYSTEMTIMEToSysTime(const scope SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe
10028     {
10029         const max = SysTime.max;
10030 
10031         static void throwLaterThanMax()
10032         {
10033             throw new DateTimeException("The given SYSTEMTIME is for a date greater than SysTime.max.");
10034         }
10035 
10036         if (st.wYear > max.year)
10037             throwLaterThanMax();
10038         else if (st.wYear == max.year)
10039         {
10040             if (st.wMonth > max.month)
10041                 throwLaterThanMax();
10042             else if (st.wMonth == max.month)
10043             {
10044                 if (st.wDay > max.day)
10045                     throwLaterThanMax();
10046                 else if (st.wDay == max.day)
10047                 {
10048                     if (st.wHour > max.hour)
10049                         throwLaterThanMax();
10050                     else if (st.wHour == max.hour)
10051                     {
10052                         if (st.wMinute > max.minute)
10053                             throwLaterThanMax();
10054                         else if (st.wMinute == max.minute)
10055                         {
10056                             if (st.wSecond > max.second)
10057                                 throwLaterThanMax();
10058                             else if (st.wSecond == max.second)
10059                             {
10060                                 if (st.wMilliseconds > max.fracSecs.total!"msecs")
10061                                     throwLaterThanMax();
10062                             }
10063                         }
10064                     }
10065                 }
10066             }
10067         }
10068 
10069         auto dt = DateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
10070 
10071         import core.time : msecs;
10072         return SysTime(dt, msecs(st.wMilliseconds), tz);
10073     }
10074 
10075     @system unittest
10076     {
10077         auto sysTime = Clock.currTime(UTC());
10078         SYSTEMTIME st = void;
10079         GetSystemTime(&st);
10080         auto converted = SYSTEMTIMEToSysTime(&st, UTC());
10081         import core.time : abs;
10082         assert(abs((converted - sysTime)) <= dur!"seconds"(2));
10083 
10084         static void testScope(scope SYSTEMTIME* st) @safe
10085         {
10086             auto result = SYSTEMTIMEToSysTime(st);
10087         }
10088     }
10089 
10090 
10091     SYSTEMTIME SysTimeToSYSTEMTIME(scope SysTime sysTime) @safe
10092     {
10093         immutable dt = cast(DateTime) sysTime;
10094 
10095         if (dt.year < 1601)
10096             throw new DateTimeException("SYSTEMTIME cannot hold dates prior to the year 1601.");
10097 
10098         SYSTEMTIME st;
10099 
10100         st.wYear = dt.year;
10101         st.wMonth = dt.month;
10102         st.wDayOfWeek = dt.dayOfWeek;
10103         st.wDay = dt.day;
10104         st.wHour = dt.hour;
10105         st.wMinute = dt.minute;
10106         st.wSecond = dt.second;
10107         st.wMilliseconds = cast(ushort) sysTime.fracSecs.total!"msecs";
10108 
10109         return st;
10110     }
10111 
10112     @system unittest
10113     {
10114         SYSTEMTIME st = void;
10115         GetSystemTime(&st);
10116         auto sysTime = SYSTEMTIMEToSysTime(&st, UTC());
10117 
10118         SYSTEMTIME result = SysTimeToSYSTEMTIME(sysTime);
10119 
10120         assert(st.wYear == result.wYear);
10121         assert(st.wMonth == result.wMonth);
10122         assert(st.wDayOfWeek == result.wDayOfWeek);
10123         assert(st.wDay == result.wDay);
10124         assert(st.wHour == result.wHour);
10125         assert(st.wMinute == result.wMinute);
10126         assert(st.wSecond == result.wSecond);
10127         assert(st.wMilliseconds == result.wMilliseconds);
10128 
10129         static void testScope(scope ref SysTime st) @safe
10130         {
10131             auto localResult = SysTimeToSYSTEMTIME(st);
10132         }
10133     }
10134 
10135     private enum hnsecsFrom1601 = 504_911_232_000_000_000L;
10136 
10137     long FILETIMEToStdTime(scope const FILETIME* ft) @safe
10138     {
10139         ULARGE_INTEGER ul;
10140         ul.HighPart = ft.dwHighDateTime;
10141         ul.LowPart = ft.dwLowDateTime;
10142         ulong tempHNSecs = ul.QuadPart;
10143 
10144         if (tempHNSecs > long.max - hnsecsFrom1601)
10145             throw new DateTimeException("The given FILETIME cannot be represented as a stdTime value.");
10146 
10147         return cast(long) tempHNSecs + hnsecsFrom1601;
10148     }
10149 
10150     SysTime FILETIMEToSysTime(scope const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe
10151     {
10152         auto sysTime = SysTime(FILETIMEToStdTime(ft), UTC());
10153         sysTime.timezone = tz;
10154         return sysTime;
10155     }
10156 
10157     @system unittest
10158     {
10159         auto sysTime = Clock.currTime(UTC());
10160         SYSTEMTIME st = void;
10161         GetSystemTime(&st);
10162 
10163         FILETIME ft = void;
10164         SystemTimeToFileTime(&st, &ft);
10165 
10166         auto converted = FILETIMEToSysTime(&ft);
10167 
10168         import core.time : abs;
10169         assert(abs((converted - sysTime)) <= dur!"seconds"(2));
10170 
10171         static void testScope(scope FILETIME* ft) @safe
10172         {
10173             auto result = FILETIMEToSysTime(ft);
10174         }
10175     }
10176 
10177 
10178     FILETIME stdTimeToFILETIME(long stdTime) @safe
10179     {
10180         if (stdTime < hnsecsFrom1601)
10181             throw new DateTimeException("The given stdTime value cannot be represented as a FILETIME.");
10182 
10183         ULARGE_INTEGER ul;
10184         ul.QuadPart = cast(ulong) stdTime - hnsecsFrom1601;
10185 
10186         FILETIME ft;
10187         ft.dwHighDateTime = ul.HighPart;
10188         ft.dwLowDateTime = ul.LowPart;
10189 
10190         return ft;
10191     }
10192 
10193     FILETIME SysTimeToFILETIME(scope SysTime sysTime) @safe
10194     {
10195         return stdTimeToFILETIME(sysTime.stdTime);
10196     }
10197 
10198     @system unittest
10199     {
10200         SYSTEMTIME st = void;
10201         GetSystemTime(&st);
10202 
10203         FILETIME ft = void;
10204         SystemTimeToFileTime(&st, &ft);
10205         auto sysTime = FILETIMEToSysTime(&ft, UTC());
10206 
10207         FILETIME result = SysTimeToFILETIME(sysTime);
10208 
10209         assert(ft.dwLowDateTime == result.dwLowDateTime);
10210         assert(ft.dwHighDateTime == result.dwHighDateTime);
10211 
10212         static void testScope(scope ref SysTime st) @safe
10213         {
10214             auto local_result = SysTimeToFILETIME(st);
10215         }
10216     }
10217 }
10218 
10219 
10220 /++
10221     Type representing the DOS file date/time format.
10222   +/
10223 alias DosFileTime = uint;
10224 
10225 /++
10226     Converts from DOS file date/time to $(LREF SysTime).
10227 
10228     Params:
10229         dft = The DOS file time to convert.
10230         tz  = The time zone which the DOS file time is assumed to be in.
10231 
10232     Throws:
10233         $(REF DateTimeException,std,datetime,date) if the `DosFileTime` is
10234         invalid.
10235   +/
10236 SysTime DosFileTimeToSysTime(DosFileTime dft, immutable TimeZone tz = LocalTime()) @safe
10237 {
10238     uint dt = cast(uint) dft;
10239 
10240     if (dt == 0)
10241         throw new DateTimeException("Invalid DosFileTime.");
10242 
10243     int year = ((dt >> 25) & 0x7F) + 1980;
10244     int month = ((dt >> 21) & 0x0F);       // 1 .. 12
10245     int dayOfMonth = ((dt >> 16) & 0x1F);  // 1 .. 31
10246     int hour = (dt >> 11) & 0x1F;          // 0 .. 23
10247     int minute = (dt >> 5) & 0x3F;         // 0 .. 59
10248     int second = (dt << 1) & 0x3E;         // 0 .. 58 (in 2 second increments)
10249 
10250     try
10251         return SysTime(DateTime(year, month, dayOfMonth, hour, minute, second), tz);
10252     catch (DateTimeException dte)
10253         throw new DateTimeException("Invalid DosFileTime", __FILE__, __LINE__, dte);
10254 }
10255 
10256 ///
10257 @safe unittest
10258 {
10259     import std.datetime.date : DateTime;
10260 
10261     assert(DosFileTimeToSysTime(0b00000000001000010000000000000000) == SysTime(DateTime(1980, 1, 1, 0, 0, 0)));
10262     assert(DosFileTimeToSysTime(0b11111111100111111011111101111101) == SysTime(DateTime(2107, 12, 31, 23, 59, 58)));
10263     assert(DosFileTimeToSysTime(0x3E3F8456) == SysTime(DateTime(2011, 1, 31, 16, 34, 44)));
10264 }
10265 
10266 @safe unittest
10267 {
10268     static void testScope(scope ref DosFileTime dft) @safe
10269     {
10270         auto result = DosFileTimeToSysTime(dft);
10271     }
10272 }
10273 
10274 
10275 /++
10276     Converts from $(LREF SysTime) to DOS file date/time.
10277 
10278     Params:
10279         sysTime = The $(LREF SysTime) to convert.
10280 
10281     Throws:
10282         $(REF DateTimeException,std,datetime,date) if the given
10283         $(LREF SysTime) cannot be converted to a `DosFileTime`.
10284   +/
10285 DosFileTime SysTimeToDosFileTime(scope SysTime sysTime) @safe
10286 {
10287     auto dateTime = cast(DateTime) sysTime;
10288 
10289     if (dateTime.year < 1980)
10290         throw new DateTimeException("DOS File Times cannot hold dates prior to 1980.");
10291 
10292     if (dateTime.year > 2107)
10293         throw new DateTimeException("DOS File Times cannot hold dates past 2107.");
10294 
10295     uint retval = 0;
10296     retval = (dateTime.year - 1980) << 25;
10297     retval |= (dateTime.month & 0x0F) << 21;
10298     retval |= (dateTime.day & 0x1F) << 16;
10299     retval |= (dateTime.hour & 0x1F) << 11;
10300     retval |= (dateTime.minute & 0x3F) << 5;
10301     retval |= (dateTime.second >> 1) & 0x1F;
10302 
10303     return cast(DosFileTime) retval;
10304 }
10305 
10306 ///
10307 @safe unittest
10308 {
10309     import std.datetime.date : DateTime;
10310 
10311     assert(SysTimeToDosFileTime(SysTime(DateTime(1980, 1, 1, 0, 0, 0))) == 0b00000000001000010000000000000000);
10312     assert(SysTimeToDosFileTime(SysTime(DateTime(2107, 12, 31, 23, 59, 58))) == 0b11111111100111111011111101111101);
10313     assert(SysTimeToDosFileTime(SysTime(DateTime(2011, 1, 31, 16, 34, 44))) == 0x3E3F8456);
10314 }
10315 
10316 @safe unittest
10317 {
10318     static void testScope(scope ref SysTime st) @safe
10319     {
10320         auto result = SysTimeToDosFileTime(st);
10321     }
10322 }
10323 
10324 
10325 /++
10326     The given array of `char` or random-access range of `char` or
10327     `ubyte` is expected to be in the format specified in
10328     $(HTTP tools.ietf.org/html/rfc5322, RFC 5322) section 3.3 with the
10329     grammar rule $(I date-time). It is the date-time format commonly used in
10330     internet messages such as e-mail and HTTP. The corresponding
10331     $(LREF SysTime) will be returned.
10332 
10333     RFC 822 was the original spec (hence the function's name), whereas RFC 5322
10334     is the current spec.
10335 
10336     The day of the week is ignored beyond verifying that it's a valid day of the
10337     week, as the day of the week can be inferred from the date. It is not
10338     checked whether the given day of the week matches the actual day of the week
10339     of the given date (though it is technically invalid per the spec if the
10340     day of the week doesn't match the actual day of the week of the given date).
10341 
10342     If the time zone is `"-0000"` (or considered to be equivalent to
10343     `"-0000"` by section 4.3 of the spec), a
10344     $(REF SimpleTimeZone,std,datetime,timezone) with a utc offset of `0` is
10345     used rather than $(REF UTC,std,datetime,timezone), whereas `"+0000"` uses
10346     $(REF UTC,std,datetime,timezone).
10347 
10348     Note that because $(LREF SysTime) does not currently support having a second
10349     value of 60 (as is sometimes done for leap seconds), if the date-time value
10350     does have a value of 60 for the seconds, it is treated as 59.
10351 
10352     The one area in which this function violates RFC 5322 is that it accepts
10353     `"\n"` in folding whitespace in the place of `"\r\n"`, because the
10354     HTTP spec requires it.
10355 
10356     Throws:
10357         $(REF DateTimeException,std,datetime,date) if the given string doesn't
10358         follow the grammar for a date-time field or if the resulting
10359         $(LREF SysTime) is invalid.
10360   +/
10361 SysTime parseRFC822DateTime()(scope const char[] value) @safe
10362 {
10363     import std.string : representation;
10364     return parseRFC822DateTime(value.representation);
10365 }
10366 
10367 /++ Ditto +/
10368 SysTime parseRFC822DateTime(R)(scope R value)
10369 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
10370     (is(immutable ElementType!R == immutable char) || is(immutable ElementType!R == immutable ubyte)))
10371 {
10372     import std.algorithm.searching : find, all;
10373     import std.ascii : isDigit, isAlpha, isPrintable;
10374     import std.conv : to;
10375     import std.functional : not;
10376     import std.string : capitalize, format;
10377     import std.traits : EnumMembers, isArray;
10378     import std.typecons : Rebindable;
10379 
10380     void stripAndCheckLen(R valueBefore, size_t minLen, size_t line = __LINE__)
10381     {
10382         value = _stripCFWS(valueBefore);
10383         if (value.length < minLen)
10384             throw new DateTimeException("date-time value too short", __FILE__, line);
10385     }
10386     stripAndCheckLen(value, "7Dec1200:00A".length);
10387 
10388     static if (isArray!R && (is(ElementEncodingType!R == char) || is(ElementEncodingType!R == ubyte)))
10389     {
10390         static string sliceAsString(R str) @trusted
10391         {
10392             return cast(string) str;
10393         }
10394     }
10395     else
10396     {
10397         char[4] temp;
10398         char[] sliceAsString(R str) @trusted
10399         {
10400             size_t i = 0;
10401             foreach (c; str)
10402                 temp[i++] = cast(char) c;
10403             return temp[0 .. str.length];
10404         }
10405     }
10406 
10407     // day-of-week
10408     if (isAlpha(value[0]))
10409     {
10410         auto dowStr = sliceAsString(value[0 .. 3]);
10411         switch (dowStr)
10412         {
10413             foreach (dow; EnumMembers!DayOfWeek)
10414             {
10415                 enum dowC = capitalize(to!string(dow));
10416                 case dowC:
10417                     goto afterDoW;
10418             }
10419             default: throw new DateTimeException(format("Invalid day-of-week: %s", dowStr));
10420         }
10421 afterDoW: stripAndCheckLen(value[3 .. value.length], ",7Dec1200:00A".length);
10422         if (value[0] != ',')
10423             throw new DateTimeException("day-of-week missing comma");
10424         stripAndCheckLen(value[1 .. value.length], "7Dec1200:00A".length);
10425     }
10426 
10427     // day
10428     immutable digits = isDigit(value[1]) ? 2 : 1;
10429     immutable day = _convDigits!short(value[0 .. digits]);
10430     if (day == -1)
10431         throw new DateTimeException("Invalid day");
10432     stripAndCheckLen(value[digits .. value.length], "Dec1200:00A".length);
10433 
10434     // month
10435     Month month;
10436     {
10437         auto monStr = sliceAsString(value[0 .. 3]);
10438         switch (monStr)
10439         {
10440             foreach (mon; EnumMembers!Month)
10441             {
10442                 enum monC = capitalize(to!string(mon));
10443                 case monC:
10444                 {
10445                     month = mon;
10446                     goto afterMon;
10447                 }
10448             }
10449             default: throw new DateTimeException(format("Invalid month: %s", monStr));
10450         }
10451 afterMon: stripAndCheckLen(value[3 .. value.length], "1200:00A".length);
10452     }
10453 
10454     // year
10455     auto found = value[2 .. value.length].find!(not!(isDigit))();
10456     size_t yearLen = value.length - found.length;
10457     if (found.length == 0)
10458         throw new DateTimeException("Invalid year");
10459     if (found[0] == ':')
10460         yearLen -= 2;
10461     auto year = _convDigits!short(value[0 .. yearLen]);
10462     if (year < 1900)
10463     {
10464         if (year == -1)
10465             throw new DateTimeException("Invalid year");
10466         if (yearLen < 4)
10467         {
10468             if (yearLen == 3)
10469                 year += 1900;
10470             else if (yearLen == 2)
10471                 year += year < 50 ? 2000 : 1900;
10472             else
10473                 throw new DateTimeException("Invalid year. Too few digits.");
10474         }
10475         else
10476             throw new DateTimeException("Invalid year. Cannot be earlier than 1900.");
10477     }
10478     stripAndCheckLen(value[yearLen .. value.length], "00:00A".length);
10479 
10480     // hour
10481     immutable hour = _convDigits!short(value[0 .. 2]);
10482     stripAndCheckLen(value[2 .. value.length], ":00A".length);
10483     if (value[0] != ':')
10484         throw new DateTimeException("Invalid hour");
10485     stripAndCheckLen(value[1 .. value.length], "00A".length);
10486 
10487     // minute
10488     immutable minute = _convDigits!short(value[0 .. 2]);
10489     stripAndCheckLen(value[2 .. value.length], "A".length);
10490 
10491     // second
10492     short second;
10493     if (value[0] == ':')
10494     {
10495         stripAndCheckLen(value[1 .. value.length], "00A".length);
10496         second = _convDigits!short(value[0 .. 2]);
10497         // this is just if/until SysTime is sorted out to fully support leap seconds
10498         if (second == 60)
10499             second = 59;
10500         stripAndCheckLen(value[2 .. value.length], "A".length);
10501     }
10502 
10503     immutable(TimeZone) parseTZ(int sign)
10504     {
10505         if (value.length < 5)
10506             throw new DateTimeException("Invalid timezone");
10507         immutable zoneHours = _convDigits!short(value[1 .. 3]);
10508         immutable zoneMinutes = _convDigits!short(value[3 .. 5]);
10509         if (zoneHours == -1 || zoneMinutes == -1 || zoneMinutes > 59)
10510             throw new DateTimeException("Invalid timezone");
10511         value = value[5 .. value.length];
10512         immutable utcOffset = (dur!"hours"(zoneHours) + dur!"minutes"(zoneMinutes)) * sign;
10513         if (utcOffset == Duration.zero)
10514         {
10515             return sign == 1 ? cast(immutable(TimeZone))UTC()
10516                              : cast(immutable(TimeZone))new immutable SimpleTimeZone(Duration.zero);
10517         }
10518         return new immutable(SimpleTimeZone)(utcOffset);
10519     }
10520 
10521     // zone
10522     Rebindable!(immutable TimeZone) tz;
10523     if (value[0] == '-')
10524         tz = parseTZ(-1);
10525     else if (value[0] == '+')
10526         tz = parseTZ(1);
10527     else
10528     {
10529         // obs-zone
10530         immutable tzLen = value.length - find(value, ' ', '\t', '(')[0].length;
10531         switch (sliceAsString(value[0 .. tzLen <= 4 ? tzLen : 4]))
10532         {
10533             case "UT": case "GMT": tz = UTC(); break;
10534             case "EST": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
10535             case "EDT": tz = new immutable SimpleTimeZone(dur!"hours"(-4)); break;
10536             case "CST": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
10537             case "CDT": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
10538             case "MST": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
10539             case "MDT": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
10540             case "PST": tz = new immutable SimpleTimeZone(dur!"hours"(-8)); break;
10541             case "PDT": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
10542             case "J": case "j": throw new DateTimeException("Invalid timezone");
10543             default:
10544             {
10545                 if (all!(isAlpha)(value[0 .. tzLen]))
10546                 {
10547                     tz = new immutable SimpleTimeZone(Duration.zero);
10548                     break;
10549                 }
10550                 throw new DateTimeException("Invalid timezone");
10551             }
10552         }
10553         value = value[tzLen .. value.length];
10554     }
10555 
10556     // This is kind of arbitrary. Technically, nothing but CFWS is legal past
10557     // the end of the timezone, but we don't want to be picky about that in a
10558     // function that's just parsing rather than validating. So, the idea here is
10559     // that if the next character is printable (and not part of CFWS), then it
10560     // might be part of the timezone and thus affect what the timezone was
10561     // supposed to be, so we'll throw, but otherwise, we'll just ignore it.
10562     if (!value.empty && isPrintable(value[0]) && value[0] != ' ' && value[0] != '(')
10563         throw new DateTimeException("Invalid timezone");
10564 
10565     try
10566         return SysTime(DateTime(year, month, day, hour, minute, second), tz);
10567     catch (DateTimeException dte)
10568         throw new DateTimeException("date-time format is correct, but the resulting SysTime is invalid.", dte);
10569 }
10570 
10571 ///
10572 @safe unittest
10573 {
10574     import core.time : hours;
10575     import std.datetime.date : DateTime, DateTimeException;
10576     import std.datetime.timezone : SimpleTimeZone, UTC;
10577     import std.exception : assertThrown;
10578 
10579     auto tz = new immutable SimpleTimeZone(hours(-8));
10580     assert(parseRFC822DateTime("Sat, 6 Jan 1990 12:14:19 -0800") ==
10581            SysTime(DateTime(1990, 1, 6, 12, 14, 19), tz));
10582 
10583     assert(parseRFC822DateTime("9 Jul 2002 13:11 +0000") ==
10584            SysTime(DateTime(2002, 7, 9, 13, 11, 0), UTC()));
10585 
10586     auto badStr = "29 Feb 2001 12:17:16 +0200";
10587     assertThrown!DateTimeException(parseRFC822DateTime(badStr));
10588 }
10589 
10590 version (StdUnittest) private void testParse822(alias cr)(string str, SysTime expected, size_t line = __LINE__)
10591 {
10592     import std.format : format;
10593     auto value = cr(str);
10594     auto result = parseRFC822DateTime(value);
10595     if (result != expected)
10596         throw new AssertError(format("wrong result. expected [%s], actual[%s]", expected, result), __FILE__, line);
10597 }
10598 
10599 version (StdUnittest) private void testBadParse822(alias cr)(string str, size_t line = __LINE__)
10600 {
10601     try
10602         parseRFC822DateTime(cr(str));
10603     catch (DateTimeException)
10604         return;
10605     throw new AssertError("No DateTimeException was thrown", __FILE__, line);
10606 }
10607 
10608 @system unittest
10609 {
10610     import core.time;
10611     import std.algorithm.iteration : filter, map;
10612     import std.algorithm.searching : canFind;
10613     import std.array : array;
10614     import std.ascii : letters;
10615     import std.format : format;
10616     import std.meta : AliasSeq;
10617     import std.range : chain, iota, take;
10618     import std.stdio : writefln, writeln;
10619     import std.string : representation;
10620 
10621     static struct Rand3Letters
10622     {
10623         enum empty = false;
10624         @property auto front() { return _mon; }
10625         void popFront()
10626         {
10627             import std.exception : assumeUnique;
10628             import std.random : rndGen;
10629             _mon = rndGen.map!(a => letters[a % letters.length])().take(3).array().assumeUnique();
10630         }
10631         string _mon;
10632         static auto start() { Rand3Letters retval; retval.popFront(); return retval; }
10633     }
10634 
10635     static foreach (cr; AliasSeq!(function(string a){return cast(char[]) a;},
10636                            function(string a){return cast(ubyte[]) a;},
10637                            function(string a){return a;},
10638                            function(string a){return map!(b => cast(char) b)(a.representation);}))
10639     {(){ // workaround slow optimizations for large functions
10640          // https://issues.dlang.org/show_bug.cgi?id=2396
10641         scope(failure) writeln(typeof(cr).stringof);
10642         alias test = testParse822!cr;
10643         alias testBad = testBadParse822!cr;
10644 
10645         immutable std1 = DateTime(2012, 12, 21, 13, 14, 15);
10646         immutable std2 = DateTime(2012, 12, 21, 13, 14, 0);
10647         immutable dst1 = DateTime(1976, 7, 4, 5, 4, 22);
10648         immutable dst2 = DateTime(1976, 7, 4, 5, 4, 0);
10649 
10650         test("21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
10651         test("21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
10652         test("Fri, 21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
10653         test("Fri, 21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
10654 
10655         test("04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10656         test("04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10657         test("Sun, 04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10658         test("Sun, 04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10659 
10660         test("4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10661         test("4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10662         test("Sun, 4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10663         test("Sun, 4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10664 
10665         auto badTZ = new immutable SimpleTimeZone(Duration.zero);
10666         test("21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
10667         test("21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
10668         test("Fri, 21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
10669         test("Fri, 21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
10670 
10671         test("04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10672         test("04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10673         test("Sun, 04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10674         test("Sun, 04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10675 
10676         test("4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10677         test("4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10678         test("Sun, 4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10679         test("Sun, 4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10680 
10681         auto pst = new immutable SimpleTimeZone(dur!"hours"(-8));
10682         auto pdt = new immutable SimpleTimeZone(dur!"hours"(-7));
10683         test("21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
10684         test("21 Dec 2012 13:14 -0800", SysTime(std2, pst));
10685         test("Fri, 21 Dec 2012 13:14 -0800", SysTime(std2, pst));
10686         test("Fri, 21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
10687 
10688         test("04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10689         test("04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10690         test("Sun, 04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10691         test("Sun, 04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10692 
10693         test("4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10694         test("4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10695         test("Sun, 4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10696         test("Sun, 4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10697 
10698         auto cet = new immutable SimpleTimeZone(dur!"hours"(1));
10699         auto cest = new immutable SimpleTimeZone(dur!"hours"(2));
10700         test("21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
10701         test("21 Dec 2012 13:14 +0100", SysTime(std2, cet));
10702         test("Fri, 21 Dec 2012 13:14 +0100", SysTime(std2, cet));
10703         test("Fri, 21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
10704 
10705         test("04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10706         test("04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10707         test("Sun, 04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10708         test("Sun, 04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10709 
10710         test("4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10711         test("4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10712         test("Sun, 4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10713         test("Sun, 4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10714 
10715         // dst and std times are switched in the Southern Hemisphere which is why the
10716         // time zone names and DateTime variables don't match.
10717         auto cstStd = new immutable SimpleTimeZone(dur!"hours"(9) + dur!"minutes"(30));
10718         auto cstDST = new immutable SimpleTimeZone(dur!"hours"(10) + dur!"minutes"(30));
10719         test("21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
10720         test("21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
10721         test("Fri, 21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
10722         test("Fri, 21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
10723 
10724         test("04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10725         test("04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10726         test("Sun, 04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10727         test("Sun, 04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10728 
10729         test("4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10730         test("4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10731         test("Sun, 4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10732         test("Sun, 4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10733 
10734         foreach (int i, mon; _monthNames)
10735         {
10736             test(format("17 %s 2012 00:05:02 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 2), UTC()));
10737             test(format("17 %s 2012 00:05 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 0), UTC()));
10738         }
10739 
10740         import std.uni : toLower, toUpper;
10741         foreach (mon; chain(_monthNames[].map!(a => toLower(a))(),
10742                             _monthNames[].map!(a => toUpper(a))(),
10743                             ["Jam", "Jen", "Fec", "Fdb", "Mas", "Mbr", "Aps", "Aqr", "Mai", "Miy",
10744                              "Jum", "Jbn", "Jup", "Jal", "Aur", "Apg", "Sem", "Sap", "Ocm", "Odt",
10745                              "Nom", "Nav", "Dem", "Dac"],
10746                             Rand3Letters.start().filter!(a => !_monthNames[].canFind(a)).take(20)))
10747         {
10748             scope(failure) writefln("Month: %s", mon);
10749             testBad(format("17 %s 2012 00:05:02 +0000", mon));
10750             testBad(format("17 %s 2012 00:05 +0000", mon));
10751         }
10752 
10753         immutable string[7] daysOfWeekNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
10754 
10755         {
10756             auto start = SysTime(DateTime(2012, 11, 11, 9, 42, 0), UTC());
10757             int day = 11;
10758 
10759             foreach (int i, dow; daysOfWeekNames)
10760             {
10761                 auto curr = start + dur!"days"(i);
10762                 test(format("%s, %s Nov 2012 09:42:00 +0000", dow, day), curr);
10763                 test(format("%s, %s Nov 2012 09:42 +0000", dow, day++), curr);
10764 
10765                 // Whether the day of the week matches the date is ignored.
10766                 test(format("%s, 11 Nov 2012 09:42:00 +0000", dow), start);
10767                 test(format("%s, 11 Nov 2012 09:42 +0000", dow), start);
10768             }
10769         }
10770 
10771         foreach (dow; chain(daysOfWeekNames[].map!(a => toLower(a))(),
10772                             daysOfWeekNames[].map!(a => toUpper(a))(),
10773                             ["Sum", "Spn", "Mom", "Man", "Tuf", "Tae", "Wem", "Wdd", "The", "Tur",
10774                              "Fro", "Fai", "San", "Sut"],
10775                             Rand3Letters.start().filter!(a => !daysOfWeekNames[].canFind(a)).take(20)))
10776         {
10777             scope(failure) writefln("Day of Week: %s", dow);
10778             testBad(format("%s, 11 Nov 2012 09:42:00 +0000", dow));
10779             testBad(format("%s, 11 Nov 2012 09:42 +0000", dow));
10780         }
10781 
10782         testBad("31 Dec 1899 23:59:59 +0000");
10783         test("01 Jan 1900 00:00:00 +0000", SysTime(Date(1900, 1, 1), UTC()));
10784         test("01 Jan 1900 00:00:00 -0000", SysTime(Date(1900, 1, 1),
10785                                                    new immutable SimpleTimeZone(Duration.zero)));
10786         test("01 Jan 1900 00:00:00 -0700", SysTime(Date(1900, 1, 1),
10787                                                    new immutable SimpleTimeZone(dur!"hours"(-7))));
10788 
10789         {
10790             auto st1 = SysTime(Date(1900, 1, 1), UTC());
10791             auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
10792             foreach (i; 1900 .. 2102)
10793             {
10794                 test(format("1 Jan %05d 00:00 +0000", i), st1);
10795                 test(format("1 Jan %05d 00:00 -1100", i), st2);
10796                 st1.add!"years"(1);
10797                 st2.add!"years"(1);
10798             }
10799             st1.year = 9998;
10800             st2.year = 9998;
10801             foreach (i; 9998 .. 11_002)
10802             {
10803                 test(format("1 Jan %05d 00:00 +0000", i), st1);
10804                 test(format("1 Jan %05d 00:00 -1100", i), st2);
10805                 st1.add!"years"(1);
10806                 st2.add!"years"(1);
10807             }
10808         }
10809 
10810         testBad("12 Feb 1907 23:17:09 0000");
10811         testBad("12 Feb 1907 23:17:09 +000");
10812         testBad("12 Feb 1907 23:17:09 -000");
10813         testBad("12 Feb 1907 23:17:09 +00000");
10814         testBad("12 Feb 1907 23:17:09 -00000");
10815         testBad("12 Feb 1907 23:17:09 +A");
10816         testBad("12 Feb 1907 23:17:09 +PST");
10817         testBad("12 Feb 1907 23:17:09 -A");
10818         testBad("12 Feb 1907 23:17:09 -PST");
10819 
10820         // test trailing stuff that gets ignored
10821         {
10822             foreach (c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
10823             {
10824                 scope(failure) writefln("c: %d", c);
10825                 test(format("21 Dec 2012 13:14:15 +0000%c", cast(char) c), SysTime(std1, UTC()));
10826                 test(format("21 Dec 2012 13:14:15 +0000%c  ", cast(char) c), SysTime(std1, UTC()));
10827                 test(format("21 Dec 2012 13:14:15 +0000%chello", cast(char) c), SysTime(std1, UTC()));
10828             }
10829         }
10830 
10831         // test trailing stuff that doesn't get ignored
10832         {
10833             foreach (c; chain(iota(33, '('), iota('(' + 1, 127)))
10834             {
10835                 scope(failure) writefln("c: %d", c);
10836                 testBad(format("21 Dec 2012 13:14:15 +0000%c", cast(char) c));
10837                 testBad(format("21 Dec 2012 13:14:15 +0000%c   ", cast(char) c));
10838                 testBad(format("21 Dec 2012 13:14:15 +0000%chello", cast(char) c));
10839             }
10840         }
10841 
10842         testBad("32 Jan 2012 12:13:14 -0800");
10843         testBad("31 Jan 2012 24:13:14 -0800");
10844         testBad("31 Jan 2012 12:60:14 -0800");
10845         testBad("31 Jan 2012 12:13:61 -0800");
10846         testBad("31 Jan 2012 12:13:14 -0860");
10847         test("31 Jan 2012 12:13:14 -0859",
10848              SysTime(DateTime(2012, 1, 31, 12, 13, 14),
10849                      new immutable SimpleTimeZone(dur!"hours"(-8) + dur!"minutes"(-59))));
10850 
10851         // leap-seconds
10852         test("21 Dec 2012 15:59:60 -0800", SysTime(DateTime(2012, 12, 21, 15, 59, 59), pst));
10853 
10854         // FWS
10855         test("Sun,4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10856         test("Sun,4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10857         test("Sun,4 Jul 1976 05:04 +0930 (foo)", SysTime(dst2, cstStd));
10858         test("Sun,4 Jul 1976 05:04:22 +0930 (foo)", SysTime(dst1, cstStd));
10859         test("Sun,4  \r\n  Jul  \r\n  1976  \r\n  05:04  \r\n  +0930  \r\n  (foo)", SysTime(dst2, cstStd));
10860         test("Sun,4  \r\n  Jul  \r\n  1976  \r\n  05:04:22  \r\n  +0930  \r\n  (foo)", SysTime(dst1, cstStd));
10861 
10862         auto str = "01 Jan 2012 12:13:14 -0800 ";
10863         test(str, SysTime(DateTime(2012, 1, 1, 12, 13, 14), new immutable SimpleTimeZone(hours(-8))));
10864         foreach (i; 0 .. str.length)
10865         {
10866             auto currStr = str.dup;
10867             currStr[i] = 'x';
10868             scope(failure) writefln("failed: %s", currStr);
10869             testBad(cast(string) currStr);
10870         }
10871         foreach (i; 2 .. str.length)
10872         {
10873             auto currStr = str[0 .. $ - i];
10874             scope(failure) writefln("failed: %s", currStr);
10875             testBad(cast(string) currStr);
10876             testBad((cast(string) currStr) ~ "                                    ");
10877         }
10878     }();}
10879 
10880     static void testScope(scope ref string str) @safe
10881     {
10882         auto result = parseRFC822DateTime(str);
10883     }
10884 }
10885 
10886 // Obsolete Format per section 4.3 of RFC 5322.
10887 @system unittest
10888 {
10889     import std.algorithm.iteration : filter, map;
10890     import std.ascii : letters;
10891     import std.exception : collectExceptionMsg;
10892     import std.format : format;
10893     import std.meta : AliasSeq;
10894     import std.range : chain, iota;
10895     import std.stdio : writefln, writeln;
10896     import std.string : representation;
10897 
10898     auto std1 = SysTime(DateTime(2012, 12, 21, 13, 14, 15), UTC());
10899     auto std2 = SysTime(DateTime(2012, 12, 21, 13, 14, 0), UTC());
10900     auto std3 = SysTime(DateTime(1912, 12, 21, 13, 14, 15), UTC());
10901     auto std4 = SysTime(DateTime(1912, 12, 21, 13, 14, 0), UTC());
10902     auto dst1 = SysTime(DateTime(1976, 7, 4, 5, 4, 22), UTC());
10903     auto dst2 = SysTime(DateTime(1976, 7, 4, 5, 4, 0), UTC());
10904     auto tooLate1 = SysTime(Date(10_000, 1, 1), UTC());
10905     auto tooLate2 = SysTime(DateTime(12_007, 12, 31, 12, 22, 19), UTC());
10906 
10907     static foreach (cr; AliasSeq!(function(string a){return cast(char[]) a;},
10908                            function(string a){return cast(ubyte[]) a;},
10909                            function(string a){return a;},
10910                            function(string a){return map!(b => cast(char) b)(a.representation);}))
10911     {(){ // workaround slow optimizations for large functions
10912          // https://issues.dlang.org/show_bug.cgi?id=2396
10913         scope(failure) writeln(typeof(cr).stringof);
10914         alias test = testParse822!cr;
10915         {
10916             auto list = ["", " ", " \r\n\t", "\t\r\n (hello world( frien(dog)) silly \r\n )  \t\t \r\n ()",
10917                          " \n ", "\t\n\t", " \n\t (foo) \n (bar) \r\n (baz) \n "];
10918 
10919             foreach (i, cfws; list)
10920             {
10921                 scope(failure) writefln("i: %s", i);
10922 
10923                 test(format("%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10924                 test(format("%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
10925                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
10926                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10927 
10928                 test(format("%1$s04%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10929                 test(format("%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10930                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10931                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04:22 +0000%1$s", cfws), dst1);
10932 
10933                 test(format("%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10934                 test(format("%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10935                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10936                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10937 
10938                 test(format("%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10939                 test(format("%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
10940                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
10941                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10942 
10943                 test(format("%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10944                 test(format("%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10945                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10946                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10947 
10948                 test(format("%1$s4%1$sJul%1$s76 05:04:22%1$s+0000%1$s", cfws), dst1);
10949                 test(format("%1$s4%1$sJul%1$s76 05:04%1$s+0000%1$s", cfws), dst2);
10950                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10951                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10952 
10953                 test(format("%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
10954                 test(format("%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
10955                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
10956                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
10957 
10958                 test(format("%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10959                 test(format("%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10960                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10961                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10962 
10963                 test(format("%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10964                 test(format("%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10965                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10966                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10967 
10968                 test(format("%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
10969                 test(format("%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
10970                 test(format("%1$sSat%1$s,%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
10971                 test(format("%1$sSun%1$s,%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
10972             }
10973         }
10974 
10975         // test years of 1, 2, and 3 digits.
10976         {
10977             auto st1 = SysTime(Date(2000, 1, 1), UTC());
10978             auto st2 = SysTime(Date(2000, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
10979             foreach (i; 0 .. 50)
10980             {
10981                 test(format("1 Jan %02d 00:00 GMT", i), st1);
10982                 test(format("1 Jan %02d 00:00 -1200", i), st2);
10983                 st1.add!"years"(1);
10984                 st2.add!"years"(1);
10985             }
10986         }
10987 
10988         {
10989             auto st1 = SysTime(Date(1950, 1, 1), UTC());
10990             auto st2 = SysTime(Date(1950, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
10991             foreach (i; 50 .. 100)
10992             {
10993                 test(format("1 Jan %02d 00:00 GMT", i), st1);
10994                 test(format("1 Jan %02d 00:00 -1200", i), st2);
10995                 st1.add!"years"(1);
10996                 st2.add!"years"(1);
10997             }
10998         }
10999 
11000         {
11001             auto st1 = SysTime(Date(1900, 1, 1), UTC());
11002             auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
11003             foreach (i; 0 .. 1000)
11004             {
11005                 test(format("1 Jan %03d 00:00 GMT", i), st1);
11006                 test(format("1 Jan %03d 00:00 -1100", i), st2);
11007                 st1.add!"years"(1);
11008                 st2.add!"years"(1);
11009             }
11010         }
11011 
11012         foreach (i; 0 .. 10)
11013         {
11014             auto str1 = cr(format("1 Jan %d 00:00 GMT", i));
11015             auto str2 = cr(format("1 Jan %d 00:00 -1200", i));
11016             assertThrown!DateTimeException(parseRFC822DateTime(str1));
11017             assertThrown!DateTimeException(parseRFC822DateTime(str1));
11018         }
11019 
11020         // test time zones
11021         {
11022             auto dt = DateTime(1982, 5, 3, 12, 22, 4);
11023             test("Wed, 03 May 1982 12:22:04 UT", SysTime(dt, UTC()));
11024             test("Wed, 03 May 1982 12:22:04 GMT", SysTime(dt, UTC()));
11025             test("Wed, 03 May 1982 12:22:04 EST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
11026             test("Wed, 03 May 1982 12:22:04 EDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-4))));
11027             test("Wed, 03 May 1982 12:22:04 CST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
11028             test("Wed, 03 May 1982 12:22:04 CDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
11029             test("Wed, 03 May 1982 12:22:04 MST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
11030             test("Wed, 03 May 1982 12:22:04 MDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
11031             test("Wed, 03 May 1982 12:22:04 PST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-8))));
11032             test("Wed, 03 May 1982 12:22:04 PDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
11033 
11034             auto badTZ = new immutable SimpleTimeZone(Duration.zero);
11035             foreach (dchar c; filter!(a => a != 'j' && a != 'J')(letters))
11036             {
11037                 scope(failure) writefln("c: %s", c);
11038                 test(format("Wed, 03 May 1982 12:22:04 %s", c), SysTime(dt, badTZ));
11039                 test(format("Wed, 03 May 1982 12:22:04%s", c), SysTime(dt, badTZ));
11040             }
11041 
11042             foreach (dchar c; ['j', 'J'])
11043             {
11044                 scope(failure) writefln("c: %s", c);
11045                 assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04 %s", c))));
11046                 assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04%s", c))));
11047             }
11048 
11049             foreach (string s; ["AAA", "GQW", "DDT", "PDA", "GT", "GM"])
11050             {
11051                 scope(failure) writefln("s: %s", s);
11052                 test(format("Wed, 03 May 1982 12:22:04 %s", s), SysTime(dt, badTZ));
11053             }
11054 
11055             // test trailing stuff that gets ignored
11056             {
11057                 foreach (c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
11058                 {
11059                     scope(failure) writefln("c: %d", c);
11060                     test(format("21Dec1213:14:15+0000%c", cast(char) c), std1);
11061                     test(format("21Dec1213:14:15+0000%c  ", cast(char) c), std1);
11062                     test(format("21Dec1213:14:15+0000%chello", cast(char) c), std1);
11063                 }
11064             }
11065 
11066             // test trailing stuff that doesn't get ignored
11067             {
11068                 foreach (c; chain(iota(33, '('), iota('(' + 1, 127)))
11069                 {
11070                     scope(failure) writefln("c: %d", c);
11071                     assertThrown!DateTimeException(
11072                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c", cast(char) c))));
11073                     assertThrown!DateTimeException(
11074                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c  ", cast(char) c))));
11075                     assertThrown!DateTimeException(
11076                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%chello", cast(char) c))));
11077                 }
11078             }
11079         }
11080 
11081         // test that the checks for minimum length work correctly and avoid
11082         // any RangeErrors.
11083         test("7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11084                                      new immutable SimpleTimeZone(Duration.zero)));
11085         test("Fri,7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11086                                          new immutable SimpleTimeZone(Duration.zero)));
11087         test("7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11088                                         new immutable SimpleTimeZone(Duration.zero)));
11089         test("Fri,7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11090                                             new immutable SimpleTimeZone(Duration.zero)));
11091 
11092         auto tooShortMsg = collectExceptionMsg!DateTimeException(parseRFC822DateTime(""));
11093         foreach (str; ["Fri,7Dec1200:00:00", "7Dec1200:00:00"])
11094         {
11095             foreach (i; 0 .. str.length)
11096             {
11097                 auto value = str[0 .. $ - i];
11098                 scope(failure) writeln(value);
11099                 assert(collectExceptionMsg!DateTimeException(parseRFC822DateTime(value)) == tooShortMsg);
11100             }
11101         }
11102     }();}
11103 }
11104 
11105 
11106 private:
11107 
11108 /+
11109     Returns the given hnsecs as an ISO string of fractional seconds.
11110   +/
11111 string fracSecsToISOString(int hnsecs, int prec = -1) @safe pure nothrow
11112 {
11113     import std.array : appender;
11114     auto w = appender!string();
11115     try
11116         fracSecsToISOString(w, hnsecs, prec);
11117     catch (Exception e)
11118         assert(0, "fracSecsToISOString() threw.");
11119     return w.data;
11120 }
11121 
11122 void fracSecsToISOString(W)(ref W writer, int hnsecs, int prec = -1)
11123 {
11124     import std.conv : toChars;
11125     import std.range : padLeft;
11126 
11127     assert(hnsecs >= 0);
11128 
11129     if (prec == 0)
11130         return;
11131 
11132     if (hnsecs == 0)
11133         return;
11134 
11135     put(writer, '.');
11136     auto chars = hnsecs.toChars.padLeft('0', 7);
11137 
11138     if (prec == -1)
11139     {
11140         while (chars.back == '0')
11141             chars.popBack();
11142         put(writer, chars);
11143     }
11144     else
11145         put(writer, chars[0 .. prec]);
11146 }
11147 
11148 @safe unittest
11149 {
11150     assert(fracSecsToISOString(0) == "");
11151     assert(fracSecsToISOString(1) == ".0000001");
11152     assert(fracSecsToISOString(10) == ".000001");
11153     assert(fracSecsToISOString(100) == ".00001");
11154     assert(fracSecsToISOString(1000) == ".0001");
11155     assert(fracSecsToISOString(10_000) == ".001");
11156     assert(fracSecsToISOString(100_000) == ".01");
11157     assert(fracSecsToISOString(1_000_000) == ".1");
11158     assert(fracSecsToISOString(1_000_001) == ".1000001");
11159     assert(fracSecsToISOString(1_001_001) == ".1001001");
11160     assert(fracSecsToISOString(1_071_601) == ".1071601");
11161     assert(fracSecsToISOString(1_271_641) == ".1271641");
11162     assert(fracSecsToISOString(9_999_999) == ".9999999");
11163     assert(fracSecsToISOString(9_999_990) == ".999999");
11164     assert(fracSecsToISOString(9_999_900) == ".99999");
11165     assert(fracSecsToISOString(9_999_000) == ".9999");
11166     assert(fracSecsToISOString(9_990_000) == ".999");
11167     assert(fracSecsToISOString(9_900_000) == ".99");
11168     assert(fracSecsToISOString(9_000_000) == ".9");
11169     assert(fracSecsToISOString(999) == ".0000999");
11170     assert(fracSecsToISOString(9990) == ".000999");
11171     assert(fracSecsToISOString(99_900) == ".00999");
11172     assert(fracSecsToISOString(999_000) == ".0999");
11173 }
11174 
11175 
11176 /+
11177     Returns a Duration corresponding to to the given ISO string of
11178     fractional seconds.
11179   +/
11180 static Duration fracSecsFromISOString(S)(scope const S isoString) @safe pure
11181 if (isSomeString!S)
11182 {
11183     import std.algorithm.searching : all;
11184     import std.ascii : isDigit;
11185     import std.conv : to;
11186     import std.format : format;
11187     import std.string : representation;
11188 
11189     if (isoString.empty)
11190         return Duration.zero;
11191 
11192     auto str = isoString.representation;
11193 
11194     enforce!DateTimeException(str[0] == '.', format("Invalid format for fracSecsFromISOString: %s", isoString));
11195     str.popFront();
11196 
11197     enforce!DateTimeException(!str.empty && all!isDigit(str),
11198                               format("Invalid format for fracSecsFromISOString: %s", isoString));
11199 
11200     dchar[7] fullISOString = void;
11201     foreach (i, ref dchar c; fullISOString)
11202     {
11203         if (i < str.length)
11204             c = str[i];
11205         else
11206             c = '0';
11207     }
11208 
11209     return hnsecs(to!int(fullISOString[]));
11210 }
11211 
11212 @safe unittest
11213 {
11214     import core.time;
11215     static void testFSInvalid(string isoString)
11216     {
11217         fracSecsFromISOString(isoString);
11218     }
11219 
11220     assertThrown!DateTimeException(testFSInvalid("."));
11221     assertThrown!DateTimeException(testFSInvalid("0."));
11222     assertThrown!DateTimeException(testFSInvalid("0"));
11223     assertThrown!DateTimeException(testFSInvalid("0000000"));
11224     assertThrown!DateTimeException(testFSInvalid("T"));
11225     assertThrown!DateTimeException(testFSInvalid("T."));
11226     assertThrown!DateTimeException(testFSInvalid(".T"));
11227     assertThrown!DateTimeException(testFSInvalid(".00000Q0"));
11228     assertThrown!DateTimeException(testFSInvalid(".000000Q"));
11229     assertThrown!DateTimeException(testFSInvalid(".0000000Q"));
11230     assertThrown!DateTimeException(testFSInvalid(".0000000000Q"));
11231 
11232     assert(fracSecsFromISOString("") == Duration.zero);
11233     assert(fracSecsFromISOString(".0000001") == hnsecs(1));
11234     assert(fracSecsFromISOString(".000001") == hnsecs(10));
11235     assert(fracSecsFromISOString(".00001") == hnsecs(100));
11236     assert(fracSecsFromISOString(".0001") == hnsecs(1000));
11237     assert(fracSecsFromISOString(".001") == hnsecs(10_000));
11238     assert(fracSecsFromISOString(".01") == hnsecs(100_000));
11239     assert(fracSecsFromISOString(".1") == hnsecs(1_000_000));
11240     assert(fracSecsFromISOString(".1000001") == hnsecs(1_000_001));
11241     assert(fracSecsFromISOString(".1001001") == hnsecs(1_001_001));
11242     assert(fracSecsFromISOString(".1071601") == hnsecs(1_071_601));
11243     assert(fracSecsFromISOString(".1271641") == hnsecs(1_271_641));
11244     assert(fracSecsFromISOString(".9999999") == hnsecs(9_999_999));
11245     assert(fracSecsFromISOString(".9999990") == hnsecs(9_999_990));
11246     assert(fracSecsFromISOString(".999999") == hnsecs(9_999_990));
11247     assert(fracSecsFromISOString(".9999900") == hnsecs(9_999_900));
11248     assert(fracSecsFromISOString(".99999") == hnsecs(9_999_900));
11249     assert(fracSecsFromISOString(".9999000") == hnsecs(9_999_000));
11250     assert(fracSecsFromISOString(".9999") == hnsecs(9_999_000));
11251     assert(fracSecsFromISOString(".9990000") == hnsecs(9_990_000));
11252     assert(fracSecsFromISOString(".999") == hnsecs(9_990_000));
11253     assert(fracSecsFromISOString(".9900000") == hnsecs(9_900_000));
11254     assert(fracSecsFromISOString(".9900") == hnsecs(9_900_000));
11255     assert(fracSecsFromISOString(".99") == hnsecs(9_900_000));
11256     assert(fracSecsFromISOString(".9000000") == hnsecs(9_000_000));
11257     assert(fracSecsFromISOString(".9") == hnsecs(9_000_000));
11258     assert(fracSecsFromISOString(".0000999") == hnsecs(999));
11259     assert(fracSecsFromISOString(".0009990") == hnsecs(9990));
11260     assert(fracSecsFromISOString(".000999") == hnsecs(9990));
11261     assert(fracSecsFromISOString(".0099900") == hnsecs(99_900));
11262     assert(fracSecsFromISOString(".00999") == hnsecs(99_900));
11263     assert(fracSecsFromISOString(".0999000") == hnsecs(999_000));
11264     assert(fracSecsFromISOString(".0999") == hnsecs(999_000));
11265     assert(fracSecsFromISOString(".00000000") == Duration.zero);
11266     assert(fracSecsFromISOString(".00000001") == Duration.zero);
11267     assert(fracSecsFromISOString(".00000009") == Duration.zero);
11268     assert(fracSecsFromISOString(".1234567890") == hnsecs(1_234_567));
11269     assert(fracSecsFromISOString(".12345678901234567890") == hnsecs(1_234_567));
11270 }
11271 
11272 
11273 /+
11274     This function is used to split out the units without getting the remaining
11275     hnsecs.
11276 
11277     Params:
11278         units  = The units to split out.
11279         hnsecs = The current total hnsecs.
11280 
11281     Returns:
11282         The split out value.
11283   +/
11284 long getUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
11285 if (validTimeUnits(units) &&
11286     CmpTimeUnits!(units, "months") < 0)
11287 {
11288     return convert!("hnsecs", units)(hnsecs);
11289 }
11290 
11291 @safe unittest
11292 {
11293     auto hnsecs = 2595000000007L;
11294     immutable days = getUnitsFromHNSecs!"days"(hnsecs);
11295     assert(days == 3);
11296     assert(hnsecs == 2595000000007L);
11297 }
11298 
11299 
11300 /+
11301     This function is used to split out the units without getting the units but
11302     just the remaining hnsecs.
11303 
11304     Params:
11305         units  = The units to split out.
11306         hnsecs = The current total hnsecs.
11307 
11308     Returns:
11309         The remaining hnsecs.
11310   +/
11311 long removeUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
11312 if (validTimeUnits(units) &&
11313     CmpTimeUnits!(units, "months") < 0)
11314 {
11315     immutable value = convert!("hnsecs", units)(hnsecs);
11316     return hnsecs - convert!(units, "hnsecs")(value);
11317 }
11318 
11319 @safe unittest
11320 {
11321     auto hnsecs = 2595000000007L;
11322     auto returned = removeUnitsFromHNSecs!"days"(hnsecs);
11323     assert(returned == 3000000007);
11324     assert(hnsecs == 2595000000007L);
11325 }
11326 
11327 
11328 /+
11329     Strips what RFC 5322, section 3.2.2 refers to as CFWS from the left-hand
11330     side of the given range (it strips comments delimited by $(D '(') and
11331     `'`') as well as folding whitespace).
11332 
11333     It is assumed that the given range contains the value of a header field and
11334     no terminating CRLF for the line (though the CRLF for folding whitespace is
11335     of course expected and stripped) and thus that the only case of CR or LF is
11336     in folding whitespace.
11337 
11338     If a comment does not terminate correctly (e.g. mismatched parens) or if the
11339     the FWS is malformed, then the range will be empty when stripCWFS is done.
11340     However, only minimal validation of the content is done (e.g. quoted pairs
11341     within a comment aren't validated beyond \$LPAREN or \$RPAREN, because
11342     they're inside a comment, and thus their value doesn't matter anyway). It's
11343     only when the content does not conform to the grammar rules for FWS and thus
11344     literally cannot be parsed that content is considered invalid, and an empty
11345     range is returned.
11346 
11347     Note that _stripCFWS is eager, not lazy. It does not create a new range.
11348     Rather, it pops off the CFWS from the range and returns it.
11349   +/
11350 R _stripCFWS(R)(R range)
11351 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
11352     (is(immutable ElementType!R == immutable char) || is(immutable ElementType!R == immutable ubyte)))
11353 {
11354     immutable e = range.length;
11355     outer: for (size_t i = 0; i < e; )
11356     {
11357         switch (range[i])
11358         {
11359             case ' ': case '\t':
11360             {
11361                 ++i;
11362                 break;
11363             }
11364             case '\r':
11365             {
11366                 if (i + 2 < e && range[i + 1] == '\n' && (range[i + 2] == ' ' || range[i + 2] == '\t'))
11367                 {
11368                     i += 3;
11369                     break;
11370                 }
11371                 break outer;
11372             }
11373             case '\n':
11374             {
11375                 if (i + 1 < e && (range[i + 1] == ' ' || range[i + 1] == '\t'))
11376                 {
11377                     i += 2;
11378                     break;
11379                 }
11380                 break outer;
11381             }
11382             case '(':
11383             {
11384                 ++i;
11385                 size_t commentLevel = 1;
11386                 while (i < e)
11387                 {
11388                     if (range[i] == '(')
11389                         ++commentLevel;
11390                     else if (range[i] == ')')
11391                     {
11392                         ++i;
11393                         if (--commentLevel == 0)
11394                             continue outer;
11395                         continue;
11396                     }
11397                     else if (range[i] == '\\')
11398                     {
11399                         if (++i == e)
11400                             break outer;
11401                     }
11402                     ++i;
11403                 }
11404                 break outer;
11405             }
11406             default: return range[i .. e];
11407         }
11408     }
11409     return range[e .. e];
11410 }
11411 
11412 @system unittest
11413 {
11414     import std.algorithm.comparison : equal;
11415     import std.algorithm.iteration : map;
11416     import std.meta : AliasSeq;
11417     import std.stdio : writeln;
11418     import std.string : representation;
11419 
11420     static foreach (cr; AliasSeq!(function(string a){return cast(ubyte[]) a;},
11421                            function(string a){return map!(b => cast(char) b)(a.representation);}))
11422     {
11423         scope(failure) writeln(typeof(cr).stringof);
11424 
11425         assert(_stripCFWS(cr("")).empty);
11426         assert(_stripCFWS(cr("\r")).empty);
11427         assert(_stripCFWS(cr("\r\n")).empty);
11428         assert(_stripCFWS(cr("\r\n ")).empty);
11429         assert(_stripCFWS(cr(" \t\r\n")).empty);
11430         assert(equal(_stripCFWS(cr(" \t\r\n hello")), cr("hello")));
11431         assert(_stripCFWS(cr(" \t\r\nhello")).empty);
11432         assert(_stripCFWS(cr(" \t\r\n\v")).empty);
11433         assert(equal(_stripCFWS(cr("\v \t\r\n\v")), cr("\v \t\r\n\v")));
11434         assert(_stripCFWS(cr("()")).empty);
11435         assert(_stripCFWS(cr("(hello world)")).empty);
11436         assert(_stripCFWS(cr("(hello world)(hello world)")).empty);
11437         assert(_stripCFWS(cr("(hello world\r\n foo\r where's\nwaldo)")).empty);
11438         assert(_stripCFWS(cr(" \t (hello \tworld\r\n foo\r where's\nwaldo)\t\t ")).empty);
11439         assert(_stripCFWS(cr("      ")).empty);
11440         assert(_stripCFWS(cr("\t\t\t")).empty);
11441         assert(_stripCFWS(cr("\t \r\n\r \n")).empty);
11442         assert(_stripCFWS(cr("(hello world) (can't find waldo) (he's lost)")).empty);
11443         assert(_stripCFWS(cr("(hello\\) world) (can't \\(find waldo) (he's \\(\\)lost)")).empty);
11444         assert(_stripCFWS(cr("(((((")).empty);
11445         assert(_stripCFWS(cr("(((()))")).empty);
11446         assert(_stripCFWS(cr("(((())))")).empty);
11447         assert(equal(_stripCFWS(cr("(((()))))")), cr(")")));
11448         assert(equal(_stripCFWS(cr(")))))")), cr(")))))")));
11449         assert(equal(_stripCFWS(cr("()))))")), cr("))))")));
11450         assert(equal(_stripCFWS(cr(" hello hello ")), cr("hello hello ")));
11451         assert(equal(_stripCFWS(cr("\thello (world)")), cr("hello (world)")));
11452         assert(equal(_stripCFWS(cr(" \r\n \\((\\))  foo")), cr("\\((\\))  foo")));
11453         assert(equal(_stripCFWS(cr(" \r\n (\\((\\)))  foo")), cr("foo")));
11454         assert(equal(_stripCFWS(cr(" \r\n (\\(()))  foo")), cr(")  foo")));
11455         assert(_stripCFWS(cr(" \r\n (((\\)))  foo")).empty);
11456 
11457         assert(_stripCFWS(cr("(hello)(hello)")).empty);
11458         assert(_stripCFWS(cr(" \r\n (hello)\r\n (hello)")).empty);
11459         assert(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n ")).empty);
11460         assert(_stripCFWS(cr("\t\t\t\t(hello)\t\t\t\t(hello)\t\t\t\t")).empty);
11461         assert(equal(_stripCFWS(cr(" \r\n (hello)\r\n (hello) \r\n hello")), cr("hello")));
11462         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n hello")), cr("hello")));
11463         assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\r\n\t(hello)\t\r\n hello")), cr("hello")));
11464         assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\t\r\n\t(hello)\t\r\n hello")), cr("hello")));
11465         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n \r\n (hello) \r\n hello")), cr("hello")));
11466         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n \r\n hello")), cr("hello")));
11467         assert(equal(_stripCFWS(cr(" \r\n \r\n (hello)\t\r\n (hello) \r\n hello")), cr("hello")));
11468         assert(equal(_stripCFWS(cr(" \r\n\t\r\n\t(hello)\t\r\n (hello) \r\n hello")), cr("hello")));
11469 
11470         assert(equal(_stripCFWS(cr(" (\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
11471         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) foo")), cr("foo")));
11472         assert(equal(_stripCFWS(cr(" (\t\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
11473         assert(equal(_stripCFWS(cr(" (\r\n\t( \r\n ) \r\n ) foo")), cr("foo")));
11474         assert(equal(_stripCFWS(cr(" ( \r\n (\t\r\n ) \r\n ) foo")), cr("foo")));
11475         assert(equal(_stripCFWS(cr(" ( \r\n (\r\n ) \r\n ) foo")), cr("foo")));
11476         assert(equal(_stripCFWS(cr(" ( \r\n (\r\n\t) \r\n ) foo")), cr("foo")));
11477         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n) \r\n ) foo")), cr("foo")));
11478         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\t\r\n ) foo")), cr("foo")));
11479         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\r\n ) foo")), cr("foo")));
11480         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n) foo")), cr("foo")));
11481         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n\t) foo")), cr("foo")));
11482         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) \r\n foo")), cr("foo")));
11483         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\t\r\n foo")), cr("foo")));
11484         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\r\n foo")), cr("foo")));
11485 
11486         assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11487         assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11488         assert(equal(_stripCFWS(cr(" (\t\r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11489         assert(equal(_stripCFWS(cr(" (\r\n \r\n\t( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11490         assert(equal(_stripCFWS(cr(" (\r\n \r\n( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11491         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n\t) \r\n ) foo")), cr("foo")));
11492         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\t\r\n ) foo")), cr("foo")));
11493         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\r\n ) foo")), cr("foo")));
11494 
11495         assert(equal(_stripCFWS(cr(" ( \r\n bar \r\n ( \r\n bar \r\n ) \r\n ) foo")), cr("foo")));
11496         assert(equal(_stripCFWS(cr(" ( \r\n () \r\n ( \r\n () \r\n ) \r\n ) foo")), cr("foo")));
11497         assert(equal(_stripCFWS(cr(" ( \r\n \\\\ \r\n ( \r\n \\\\ \r\n ) \r\n ) foo")), cr("foo")));
11498 
11499         assert(_stripCFWS(cr("(hello)(hello)")).empty);
11500         assert(_stripCFWS(cr(" \n (hello)\n (hello) \n ")).empty);
11501         assert(_stripCFWS(cr(" \n (hello) \n (hello) \n ")).empty);
11502         assert(equal(_stripCFWS(cr(" \n (hello)\n (hello) \n hello")), cr("hello")));
11503         assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n hello")), cr("hello")));
11504         assert(equal(_stripCFWS(cr("\t\n\t(hello)\n\t(hello)\t\n hello")), cr("hello")));
11505         assert(equal(_stripCFWS(cr("\t\n\t(hello)\t\n\t(hello)\t\n hello")), cr("hello")));
11506         assert(equal(_stripCFWS(cr(" \n (hello) \n \n (hello) \n hello")), cr("hello")));
11507         assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n \n hello")), cr("hello")));
11508         assert(equal(_stripCFWS(cr(" \n \n (hello)\t\n (hello) \n hello")), cr("hello")));
11509         assert(equal(_stripCFWS(cr(" \n\t\n\t(hello)\t\n (hello) \n hello")), cr("hello")));
11510     }
11511 }
11512 
11513 // This is so that we don't have to worry about std.conv.to throwing. It also
11514 // doesn't have to worry about quite as many cases as std.conv.to, since it
11515 // doesn't have to worry about a sign on the value or about whether it fits.
11516 T _convDigits(T, R)(R str)
11517 if (isIntegral!T && isSigned!T) // The constraints on R were already covered by parseRFC822DateTime.
11518 {
11519     import std.ascii : isDigit;
11520 
11521     assert(!str.empty);
11522     T num = 0;
11523     foreach (i; 0 .. str.length)
11524     {
11525         if (i != 0)
11526             num *= 10;
11527         if (!isDigit(str[i]))
11528             return -1;
11529         num += str[i] - '0';
11530     }
11531     return num;
11532 }
11533 
11534 @safe unittest
11535 {
11536     import std.conv : to;
11537     import std.range : chain, iota;
11538     foreach (i; chain(iota(0, 101), [250, 999, 1000, 1001, 2345, 9999]))
11539     {
11540         assert(_convDigits!int(to!string(i)) == i, i.to!string);
11541     }
11542     foreach (str; ["-42", "+42", "1a", "1 ", " ", " 42 "])
11543     {
11544         assert(_convDigits!int(str) == -1, str);
11545     }
11546 }
11547 
11548 
11549 // NOTE: all the non-simple array literals are wrapped in functions, because
11550 // otherwise importing causes re-evaluation of the static initializers using
11551 // CTFE with unittests enabled
11552 version (StdUnittest)
11553 {
11554 private @safe:
11555     // Variables to help in testing.
11556     Duration currLocalDiffFromUTC;
11557     immutable (TimeZone)[] testTZs;
11558 
11559     // All of these helper arrays are sorted in ascending order.
11560     auto testYearsBC = [-1999, -1200, -600, -4, -1, 0];
11561     auto testYearsAD = [1, 4, 1000, 1999, 2000, 2012];
11562 
11563     // I'd use a Tuple, but I get forward reference errors if I try.
11564     struct MonthDay
11565     {
11566         Month month;
11567         short day;
11568 
11569         this(int m, short d)
11570         {
11571             month = cast(Month) m;
11572             day = d;
11573         }
11574     }
11575 
11576     MonthDay[] testMonthDays()
11577     {
11578        static result = [MonthDay(1, 1),
11579                                 MonthDay(1, 2),
11580                                 MonthDay(3, 17),
11581                                 MonthDay(7, 4),
11582                                 MonthDay(10, 27),
11583                                 MonthDay(12, 30),
11584                                 MonthDay(12, 31)];
11585        return result;
11586     }
11587 
11588     auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31];
11589 
11590     TimeOfDay[] testTODs()
11591     {
11592        static result = [TimeOfDay(0, 0, 0),
11593                      TimeOfDay(0, 0, 1),
11594                      TimeOfDay(0, 1, 0),
11595                      TimeOfDay(1, 0, 0),
11596                      TimeOfDay(13, 13, 13),
11597                      TimeOfDay(23, 59, 59)];
11598        return result;
11599     }
11600 
11601     auto testHours = [0, 1, 12, 22, 23];
11602     auto testMinSecs = [0, 1, 30, 58, 59];
11603 
11604     // Throwing exceptions is incredibly expensive, so we want to use a smaller
11605     // set of values for tests using assertThrown.
11606     TimeOfDay[] testTODsThrown()
11607     {
11608        static result = [TimeOfDay(0, 0, 0),
11609                            TimeOfDay(13, 13, 13),
11610                            TimeOfDay(23, 59, 59)];
11611        return result;
11612     }
11613 
11614     Date[] testDatesBC;
11615     Date[] testDatesAD;
11616 
11617     DateTime[] testDateTimesBC;
11618     DateTime[] testDateTimesAD;
11619 
11620     Duration[] testFracSecs;
11621 
11622     SysTime[] testSysTimesBC;
11623     SysTime[] testSysTimesAD;
11624 
11625     // I'd use a Tuple, but I get forward reference errors if I try.
11626     struct GregDay { int day; Date date; }
11627     GregDay[] testGregDaysBC()
11628     {
11629        static result = [GregDay(-1_373_427, Date(-3760, 9, 7)), // Start of the Hebrew Calendar
11630                            GregDay(-735_233, Date(-2012, 1, 1)),
11631                            GregDay(-735_202, Date(-2012, 2, 1)),
11632                            GregDay(-735_175, Date(-2012, 2, 28)),
11633                            GregDay(-735_174, Date(-2012, 2, 29)),
11634                            GregDay(-735_173, Date(-2012, 3, 1)),
11635                            GregDay(-734_502, Date(-2010, 1, 1)),
11636                            GregDay(-734_472, Date(-2010, 1, 31)),
11637                            GregDay(-734_471, Date(-2010, 2, 1)),
11638                            GregDay(-734_444, Date(-2010, 2, 28)),
11639                            GregDay(-734_443, Date(-2010, 3, 1)),
11640                            GregDay(-734_413, Date(-2010, 3, 31)),
11641                            GregDay(-734_412, Date(-2010, 4, 1)),
11642                            GregDay(-734_383, Date(-2010, 4, 30)),
11643                            GregDay(-734_382, Date(-2010, 5, 1)),
11644                            GregDay(-734_352, Date(-2010, 5, 31)),
11645                            GregDay(-734_351, Date(-2010, 6, 1)),
11646                            GregDay(-734_322, Date(-2010, 6, 30)),
11647                            GregDay(-734_321, Date(-2010, 7, 1)),
11648                            GregDay(-734_291, Date(-2010, 7, 31)),
11649                            GregDay(-734_290, Date(-2010, 8, 1)),
11650                            GregDay(-734_260, Date(-2010, 8, 31)),
11651                            GregDay(-734_259, Date(-2010, 9, 1)),
11652                            GregDay(-734_230, Date(-2010, 9, 30)),
11653                            GregDay(-734_229, Date(-2010, 10, 1)),
11654                            GregDay(-734_199, Date(-2010, 10, 31)),
11655                            GregDay(-734_198, Date(-2010, 11, 1)),
11656                            GregDay(-734_169, Date(-2010, 11, 30)),
11657                            GregDay(-734_168, Date(-2010, 12, 1)),
11658                            GregDay(-734_139, Date(-2010, 12, 30)),
11659                            GregDay(-734_138, Date(-2010, 12, 31)),
11660                            GregDay(-731_215, Date(-2001, 1, 1)),
11661                            GregDay(-730_850, Date(-2000, 1, 1)),
11662                            GregDay(-730_849, Date(-2000, 1, 2)),
11663                            GregDay(-730_486, Date(-2000, 12, 30)),
11664                            GregDay(-730_485, Date(-2000, 12, 31)),
11665                            GregDay(-730_484, Date(-1999, 1, 1)),
11666                            GregDay(-694_690, Date(-1901, 1, 1)),
11667                            GregDay(-694_325, Date(-1900, 1, 1)),
11668                            GregDay(-585_118, Date(-1601, 1, 1)),
11669                            GregDay(-584_753, Date(-1600, 1, 1)),
11670                            GregDay(-584_388, Date(-1600, 12, 31)),
11671                            GregDay(-584_387, Date(-1599, 1, 1)),
11672                            GregDay(-365_972, Date(-1001, 1, 1)),
11673                            GregDay(-365_607, Date(-1000, 1, 1)),
11674                            GregDay(-183_351, Date(-501, 1, 1)),
11675                            GregDay(-182_986, Date(-500, 1, 1)),
11676                            GregDay(-182_621, Date(-499, 1, 1)),
11677                            GregDay(-146_827, Date(-401, 1, 1)),
11678                            GregDay(-146_462, Date(-400, 1, 1)),
11679                            GregDay(-146_097, Date(-400, 12, 31)),
11680                            GregDay(-110_302, Date(-301, 1, 1)),
11681                            GregDay(-109_937, Date(-300, 1, 1)),
11682                            GregDay(-73_778, Date(-201, 1, 1)),
11683                            GregDay(-73_413, Date(-200, 1, 1)),
11684                            GregDay(-38_715, Date(-105, 1, 1)),
11685                            GregDay(-37_254, Date(-101, 1, 1)),
11686                            GregDay(-36_889, Date(-100, 1, 1)),
11687                            GregDay(-36_524, Date(-99, 1, 1)),
11688                            GregDay(-36_160, Date(-99, 12, 31)),
11689                            GregDay(-35_794, Date(-97, 1, 1)),
11690                            GregDay(-18_627, Date(-50, 1, 1)),
11691                            GregDay(-18_262, Date(-49, 1, 1)),
11692                            GregDay(-3652, Date(-9, 1, 1)),
11693                            GregDay(-2191, Date(-5, 1, 1)),
11694                            GregDay(-1827, Date(-5, 12, 31)),
11695                            GregDay(-1826, Date(-4, 1, 1)),
11696                            GregDay(-1825, Date(-4, 1, 2)),
11697                            GregDay(-1462, Date(-4, 12, 30)),
11698                            GregDay(-1461, Date(-4, 12, 31)),
11699                            GregDay(-1460, Date(-3, 1, 1)),
11700                            GregDay(-1096, Date(-3, 12, 31)),
11701                            GregDay(-1095, Date(-2, 1, 1)),
11702                            GregDay(-731, Date(-2, 12, 31)),
11703                            GregDay(-730, Date(-1, 1, 1)),
11704                            GregDay(-367, Date(-1, 12, 30)),
11705                            GregDay(-366, Date(-1, 12, 31)),
11706                            GregDay(-365, Date(0, 1, 1)),
11707                            GregDay(-31, Date(0, 11, 30)),
11708                            GregDay(-30, Date(0, 12, 1)),
11709                            GregDay(-1, Date(0, 12, 30)),
11710                            GregDay(0, Date(0, 12, 31))];
11711        return result;
11712     }
11713 
11714     GregDay[] testGregDaysAD()
11715     {
11716        static result = [GregDay(1, Date(1, 1, 1)),
11717                            GregDay(2, Date(1, 1, 2)),
11718                            GregDay(32, Date(1, 2, 1)),
11719                            GregDay(365, Date(1, 12, 31)),
11720                            GregDay(366, Date(2, 1, 1)),
11721                            GregDay(731, Date(3, 1, 1)),
11722                            GregDay(1096, Date(4, 1, 1)),
11723                            GregDay(1097, Date(4, 1, 2)),
11724                            GregDay(1460, Date(4, 12, 30)),
11725                            GregDay(1461, Date(4, 12, 31)),
11726                            GregDay(1462, Date(5, 1, 1)),
11727                            GregDay(17_898, Date(50, 1, 1)),
11728                            GregDay(35_065, Date(97, 1, 1)),
11729                            GregDay(36_160, Date(100, 1, 1)),
11730                            GregDay(36_525, Date(101, 1, 1)),
11731                            GregDay(37_986, Date(105, 1, 1)),
11732                            GregDay(72_684, Date(200, 1, 1)),
11733                            GregDay(73_049, Date(201, 1, 1)),
11734                            GregDay(109_208, Date(300, 1, 1)),
11735                            GregDay(109_573, Date(301, 1, 1)),
11736                            GregDay(145_732, Date(400, 1, 1)),
11737                            GregDay(146_098, Date(401, 1, 1)),
11738                            GregDay(182_257, Date(500, 1, 1)),
11739                            GregDay(182_622, Date(501, 1, 1)),
11740                            GregDay(364_878, Date(1000, 1, 1)),
11741                            GregDay(365_243, Date(1001, 1, 1)),
11742                            GregDay(584_023, Date(1600, 1, 1)),
11743                            GregDay(584_389, Date(1601, 1, 1)),
11744                            GregDay(693_596, Date(1900, 1, 1)),
11745                            GregDay(693_961, Date(1901, 1, 1)),
11746                            GregDay(729_755, Date(1999, 1, 1)),
11747                            GregDay(730_120, Date(2000, 1, 1)),
11748                            GregDay(730_121, Date(2000, 1, 2)),
11749                            GregDay(730_484, Date(2000, 12, 30)),
11750                            GregDay(730_485, Date(2000, 12, 31)),
11751                            GregDay(730_486, Date(2001, 1, 1)),
11752                            GregDay(733_773, Date(2010, 1, 1)),
11753                            GregDay(733_774, Date(2010, 1, 2)),
11754                            GregDay(733_803, Date(2010, 1, 31)),
11755                            GregDay(733_804, Date(2010, 2, 1)),
11756                            GregDay(733_831, Date(2010, 2, 28)),
11757                            GregDay(733_832, Date(2010, 3, 1)),
11758                            GregDay(733_862, Date(2010, 3, 31)),
11759                            GregDay(733_863, Date(2010, 4, 1)),
11760                            GregDay(733_892, Date(2010, 4, 30)),
11761                            GregDay(733_893, Date(2010, 5, 1)),
11762                            GregDay(733_923, Date(2010, 5, 31)),
11763                            GregDay(733_924, Date(2010, 6, 1)),
11764                            GregDay(733_953, Date(2010, 6, 30)),
11765                            GregDay(733_954, Date(2010, 7, 1)),
11766                            GregDay(733_984, Date(2010, 7, 31)),
11767                            GregDay(733_985, Date(2010, 8, 1)),
11768                            GregDay(734_015, Date(2010, 8, 31)),
11769                            GregDay(734_016, Date(2010, 9, 1)),
11770                            GregDay(734_045, Date(2010, 9, 30)),
11771                            GregDay(734_046, Date(2010, 10, 1)),
11772                            GregDay(734_076, Date(2010, 10, 31)),
11773                            GregDay(734_077, Date(2010, 11, 1)),
11774                            GregDay(734_106, Date(2010, 11, 30)),
11775                            GregDay(734_107, Date(2010, 12, 1)),
11776                            GregDay(734_136, Date(2010, 12, 30)),
11777                            GregDay(734_137, Date(2010, 12, 31)),
11778                            GregDay(734_503, Date(2012, 1, 1)),
11779                            GregDay(734_534, Date(2012, 2, 1)),
11780                            GregDay(734_561, Date(2012, 2, 28)),
11781                            GregDay(734_562, Date(2012, 2, 29)),
11782                            GregDay(734_563, Date(2012, 3, 1)),
11783                            GregDay(734_858, Date(2012, 12, 21))];
11784        return result;
11785     }
11786 
11787     // I'd use a Tuple, but I get forward reference errors if I try.
11788     struct DayOfYear { int day; MonthDay md; }
11789     DayOfYear[] testDaysOfYear()
11790     {
11791        static result = [DayOfYear(1, MonthDay(1, 1)),
11792                            DayOfYear(2, MonthDay(1, 2)),
11793                            DayOfYear(3, MonthDay(1, 3)),
11794                            DayOfYear(31, MonthDay(1, 31)),
11795                            DayOfYear(32, MonthDay(2, 1)),
11796                            DayOfYear(59, MonthDay(2, 28)),
11797                            DayOfYear(60, MonthDay(3, 1)),
11798                            DayOfYear(90, MonthDay(3, 31)),
11799                            DayOfYear(91, MonthDay(4, 1)),
11800                            DayOfYear(120, MonthDay(4, 30)),
11801                            DayOfYear(121, MonthDay(5, 1)),
11802                            DayOfYear(151, MonthDay(5, 31)),
11803                            DayOfYear(152, MonthDay(6, 1)),
11804                            DayOfYear(181, MonthDay(6, 30)),
11805                            DayOfYear(182, MonthDay(7, 1)),
11806                            DayOfYear(212, MonthDay(7, 31)),
11807                            DayOfYear(213, MonthDay(8, 1)),
11808                            DayOfYear(243, MonthDay(8, 31)),
11809                            DayOfYear(244, MonthDay(9, 1)),
11810                            DayOfYear(273, MonthDay(9, 30)),
11811                            DayOfYear(274, MonthDay(10, 1)),
11812                            DayOfYear(304, MonthDay(10, 31)),
11813                            DayOfYear(305, MonthDay(11, 1)),
11814                            DayOfYear(334, MonthDay(11, 30)),
11815                            DayOfYear(335, MonthDay(12, 1)),
11816                            DayOfYear(363, MonthDay(12, 29)),
11817                            DayOfYear(364, MonthDay(12, 30)),
11818                            DayOfYear(365, MonthDay(12, 31))];
11819        return result;
11820     }
11821 
11822     DayOfYear[] testDaysOfLeapYear()
11823     {
11824        static result = [DayOfYear(1, MonthDay(1, 1)),
11825                                DayOfYear(2, MonthDay(1, 2)),
11826                                DayOfYear(3, MonthDay(1, 3)),
11827                                DayOfYear(31, MonthDay(1, 31)),
11828                                DayOfYear(32, MonthDay(2, 1)),
11829                                DayOfYear(59, MonthDay(2, 28)),
11830                                DayOfYear(60, MonthDay(2, 29)),
11831                                DayOfYear(61, MonthDay(3, 1)),
11832                                DayOfYear(91, MonthDay(3, 31)),
11833                                DayOfYear(92, MonthDay(4, 1)),
11834                                DayOfYear(121, MonthDay(4, 30)),
11835                                DayOfYear(122, MonthDay(5, 1)),
11836                                DayOfYear(152, MonthDay(5, 31)),
11837                                DayOfYear(153, MonthDay(6, 1)),
11838                                DayOfYear(182, MonthDay(6, 30)),
11839                                DayOfYear(183, MonthDay(7, 1)),
11840                                DayOfYear(213, MonthDay(7, 31)),
11841                                DayOfYear(214, MonthDay(8, 1)),
11842                                DayOfYear(244, MonthDay(8, 31)),
11843                                DayOfYear(245, MonthDay(9, 1)),
11844                                DayOfYear(274, MonthDay(9, 30)),
11845                                DayOfYear(275, MonthDay(10, 1)),
11846                                DayOfYear(305, MonthDay(10, 31)),
11847                                DayOfYear(306, MonthDay(11, 1)),
11848                                DayOfYear(335, MonthDay(11, 30)),
11849                                DayOfYear(336, MonthDay(12, 1)),
11850                                DayOfYear(364, MonthDay(12, 29)),
11851                                DayOfYear(365, MonthDay(12, 30)),
11852                                DayOfYear(366, MonthDay(12, 31))];
11853        return result;
11854     }
11855 
11856     void initializeTests()
11857     {
11858         import std.algorithm.sorting : sort;
11859         import std.typecons : Rebindable;
11860         immutable lt = LocalTime().utcToTZ(0);
11861         currLocalDiffFromUTC = dur!"hnsecs"(lt);
11862 
11863         version (Posix)
11864         {
11865             import std.datetime.timezone : PosixTimeZone;
11866             immutable otherTZ = lt < 0 ? PosixTimeZone.getTimeZone("Australia/Sydney")
11867                                        : PosixTimeZone.getTimeZone("America/Denver");
11868         }
11869         else version (Windows)
11870         {
11871             import std.datetime.timezone : WindowsTimeZone;
11872             immutable otherTZ = lt < 0 ? WindowsTimeZone.getTimeZone("AUS Eastern Standard Time")
11873                                        : WindowsTimeZone.getTimeZone("Mountain Standard Time");
11874         }
11875 
11876         immutable ot = otherTZ.utcToTZ(0);
11877 
11878         auto diffs = [0L, lt, ot];
11879         auto diffAA = [0L : Rebindable!(immutable TimeZone)(UTC())];
11880         diffAA[lt] = Rebindable!(immutable TimeZone)(LocalTime());
11881         diffAA[ot] = Rebindable!(immutable TimeZone)(otherTZ);
11882 
11883         sort(diffs);
11884         testTZs = [diffAA[diffs[0]], diffAA[diffs[1]], diffAA[diffs[2]]];
11885 
11886         testFracSecs = [Duration.zero, hnsecs(1), hnsecs(5007), hnsecs(9_999_999)];
11887 
11888         foreach (year; testYearsBC)
11889         {
11890             foreach (md; testMonthDays)
11891                 testDatesBC ~= Date(year, md.month, md.day);
11892         }
11893 
11894         foreach (year; testYearsAD)
11895         {
11896             foreach (md; testMonthDays)
11897                 testDatesAD ~= Date(year, md.month, md.day);
11898         }
11899 
11900         foreach (dt; testDatesBC)
11901         {
11902             foreach (tod; testTODs)
11903                 testDateTimesBC ~= DateTime(dt, tod);
11904         }
11905 
11906         foreach (dt; testDatesAD)
11907         {
11908             foreach (tod; testTODs)
11909                 testDateTimesAD ~= DateTime(dt, tod);
11910         }
11911 
11912         foreach (dt; testDateTimesBC)
11913         {
11914             foreach (tz; testTZs)
11915             {
11916                 foreach (fs; testFracSecs)
11917                     testSysTimesBC ~= SysTime(dt, fs, tz);
11918             }
11919         }
11920 
11921         foreach (dt; testDateTimesAD)
11922         {
11923             foreach (tz; testTZs)
11924             {
11925                 foreach (fs; testFracSecs)
11926                     testSysTimesAD ~= SysTime(dt, fs, tz);
11927             }
11928         }
11929     }
11930 }