The OpenD Programming Language

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         )
6305 
6306         Params:
6307             duration = The $(REF Duration, core,time) to add to or subtract from
6308                        this $(LREF SysTime).
6309       +/
6310     SysTime opBinary(string op)(Duration duration) @safe const pure nothrow return scope
6311         if (op == "+" || op == "-")
6312     {
6313         SysTime retval = SysTime(this._stdTime, this._timezone);
6314         immutable hnsecs = duration.total!"hnsecs";
6315         mixin("retval._stdTime " ~ op ~ "= hnsecs;");
6316         return retval;
6317     }
6318 
6319     ///
6320     @safe unittest
6321     {
6322         import core.time : hours, seconds;
6323         import std.datetime.date : DateTime;
6324 
6325         assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + seconds(1) ==
6326                SysTime(DateTime(2016, 1, 1, 0, 0, 0)));
6327 
6328         assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + hours(1) ==
6329                SysTime(DateTime(2016, 1, 1, 0, 59, 59)));
6330 
6331         assert(SysTime(DateTime(2016, 1, 1, 0, 0, 0)) - seconds(1) ==
6332                SysTime(DateTime(2015, 12, 31, 23, 59, 59)));
6333 
6334         assert(SysTime(DateTime(2016, 1, 1, 0, 59, 59)) - hours(1) ==
6335                SysTime(DateTime(2015, 12, 31, 23, 59, 59)));
6336     }
6337 
6338     @safe unittest
6339     {
6340         import core.time;
6341         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_678));
6342 
6343         assert(st + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
6344         assert(st + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
6345         assert(st + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
6346         assert(st + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
6347         assert(st + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
6348         assert(st + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
6349         assert(st + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
6350         assert(st + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
6351         assert(st + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
6352         assert(st + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
6353         assert(st + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
6354         assert(st + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
6355         assert(st + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
6356         assert(st + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
6357         assert(st + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
6358         assert(st + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671)));
6359 
6360         assert(st - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
6361         assert(st - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
6362         assert(st - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
6363         assert(st - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
6364         assert(st - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
6365         assert(st - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
6366         assert(st - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
6367         assert(st - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
6368         assert(st - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
6369         assert(st - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
6370         assert(st - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
6371         assert(st - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
6372         assert(st - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
6373         assert(st - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
6374         assert(st - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
6375         assert(st - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671)));
6376 
6377         static void testST(SysTime orig, long hnsecs, SysTime expected, size_t line = __LINE__) @safe
6378         {
6379             auto result = orig + dur!"hnsecs"(hnsecs);
6380             if (result != expected)
6381                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", result, expected), __FILE__, line);
6382         }
6383 
6384         // Test A.D.
6385         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
6386         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
6387         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
6388         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
6389         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
6390         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
6391         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
6392         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6393         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6394         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6395         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6396         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6397         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6398         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6399         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6400         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6401         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6402         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
6403         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
6404         testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
6405         testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
6406 
6407         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
6408         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
6409         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
6410         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
6411         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
6412         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6413         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6414         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6415         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6416         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6417         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6418         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6419         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6420         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6421         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
6422         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
6423         testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
6424         testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
6425 
6426         // Test B.C.
6427         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
6428         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
6429         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
6430         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
6431         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
6432         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
6433         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
6434         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6435         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6436         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6437         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6438         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6439         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6440         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6441         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6442         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6443         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6444         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
6445         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
6446         testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
6447         testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
6448 
6449         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
6450         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
6451         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
6452         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
6453         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6454         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6455         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6456         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6457         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6458         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6459         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6460         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6461         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6462         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6463         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
6464         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
6465         testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
6466         testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
6467 
6468         // Test Both
6469         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6470         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6471         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6472         testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6473         testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6474         testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
6475         testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
6476         testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
6477         testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
6478         testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
6479         testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
6480         testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6481         testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
6482         testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
6483 
6484         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6485         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6486         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6487         testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6488         testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6489         testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
6490         testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
6491         testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
6492         testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
6493         testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
6494         testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
6495         testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6496         testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
6497         testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887)));
6498 
6499         auto duration = dur!"seconds"(12);
6500         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6501         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6502         assert(cst + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45)));
6503         assert(ist + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45)));
6504         assert(cst - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21)));
6505         assert(ist - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21)));
6506 
6507         static void testScope(scope ref SysTime st, scope ref Duration d) @safe
6508         {
6509             auto result = st + d;
6510         }
6511     }
6512 
6513 
6514     /++
6515         Gives the result of adding or subtracting a $(REF Duration, core,time) from
6516         this $(LREF SysTime), as well as assigning the result to this
6517         $(LREF SysTime).
6518 
6519         The legal types of arithmetic for $(LREF SysTime) using this operator are
6520 
6521         $(BOOKTABLE,
6522         $(TR $(TD SysTime) $(TD +) $(TD Duration) $(TD -->) $(TD SysTime))
6523         $(TR $(TD SysTime) $(TD -) $(TD Duration) $(TD -->) $(TD SysTime))
6524         )
6525 
6526         Params:
6527             duration = The $(REF Duration, core,time) to add to or subtract from
6528                        this $(LREF SysTime).
6529       +/
6530     ref SysTime opOpAssign(string op)(Duration duration) @safe pure nothrow scope
6531         if (op == "+" || op == "-")
6532     {
6533         immutable hnsecs = duration.total!"hnsecs";
6534         mixin("_stdTime " ~ op ~ "= hnsecs;");
6535         return this;
6536     }
6537 
6538     @safe unittest
6539     {
6540         import core.time;
6541         auto before = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6542         assert(before + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
6543         assert(before + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
6544         assert(before + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
6545         assert(before + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
6546 
6547         assert(before + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
6548         assert(before + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
6549         assert(before + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
6550         assert(before + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
6551         assert(before + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
6552         assert(before + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
6553         assert(before + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
6554         assert(before + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
6555         assert(before + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
6556         assert(before + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
6557         assert(before + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
6558         assert(before + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
6559 
6560         assert(before - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
6561         assert(before - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
6562         assert(before - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
6563         assert(before - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
6564 
6565         assert(before - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
6566         assert(before - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
6567         assert(before - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
6568         assert(before - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
6569         assert(before - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
6570         assert(before - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
6571         assert(before - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
6572         assert(before - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
6573         assert(before - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
6574         assert(before - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
6575         assert(before - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
6576         assert(before - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
6577 
6578         static void testST(SysTime orig, long hnsecs, SysTime expected, size_t line = __LINE__) @safe
6579         {
6580             auto r = orig += dur!"hnsecs"(hnsecs);
6581             if (orig != expected)
6582                 throw new AssertError(format("Failed 1. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
6583             if (r != expected)
6584                 throw new AssertError(format("Failed 2. actual [%s] != expected [%s]", r, expected), __FILE__, line);
6585         }
6586 
6587         // Test A.D.
6588         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
6589         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
6590         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
6591         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
6592         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
6593         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
6594         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
6595         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6596         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6597         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6598         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6599         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6600         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6601         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6602         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6603         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6604         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6605         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
6606         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
6607         testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
6608         testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
6609 
6610         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
6611         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
6612         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
6613         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
6614         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
6615         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6616         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6617         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6618         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6619         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6620         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6621         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6622         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6623         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6624         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
6625         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
6626         testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
6627         testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
6628 
6629         // Test B.C.
6630         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
6631         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
6632         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
6633         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
6634         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
6635         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
6636         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
6637         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6638         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6639         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6640         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6641         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6642         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6643         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6644         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6645         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6646         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6647         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
6648         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
6649         testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
6650         testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
6651 
6652         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
6653         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
6654         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
6655         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
6656         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6657         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6658         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6659         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6660         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6661         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6662         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6663         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6664         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6665         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6666         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
6667         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
6668         testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
6669         testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
6670 
6671         // Test Both
6672         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6673         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6674         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6675         testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6676         testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6677         testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
6678         testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
6679         testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
6680         testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
6681         testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
6682         testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
6683         testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6684         testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
6685         testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
6686 
6687         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6688         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6689         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6690         testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6691         testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6692         testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
6693         testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
6694         testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
6695         testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
6696         testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
6697         testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
6698         testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6699         testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
6700         testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887)));
6701 
6702         {
6703             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6704             (st += dur!"hnsecs"(52)) += dur!"seconds"(-907);
6705             assert(st == SysTime(DateTime(0, 12, 31, 23, 44, 53), hnsecs(51)));
6706         }
6707 
6708         auto duration = dur!"seconds"(12);
6709         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6710         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6711         static assert(!__traits(compiles, cst += duration));
6712         static assert(!__traits(compiles, ist += duration));
6713         static assert(!__traits(compiles, cst -= duration));
6714         static assert(!__traits(compiles, ist -= duration));
6715 
6716         static void testScope(scope ref SysTime st, scope ref Duration d) @safe
6717         {
6718             auto result1 = st += d;
6719             auto result2 = st -= d;
6720         }
6721     }
6722 
6723 
6724     /++
6725         Gives the difference between two $(LREF SysTime)s.
6726 
6727         The legal types of arithmetic for $(LREF SysTime) using this operator
6728         are
6729 
6730         $(BOOKTABLE,
6731         $(TR $(TD SysTime) $(TD -) $(TD SysTime) $(TD -->) $(TD duration))
6732         )
6733       +/
6734     Duration opBinary(string op)(SysTime rhs) @safe const pure nothrow scope
6735         if (op == "-")
6736     {
6737         return dur!"hnsecs"(_stdTime - rhs._stdTime);
6738     }
6739 
6740     @safe unittest
6741     {
6742         import core.time;
6743         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1998, 7, 6, 12, 30, 33)) ==
6744                dur!"seconds"(31_536_000));
6745         assert(SysTime(DateTime(1998, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6746                dur!"seconds"(-31_536_000));
6747 
6748         assert(SysTime(DateTime(1999, 8, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6749                dur!"seconds"(26_78_400));
6750         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 8, 6, 12, 30, 33)) ==
6751                dur!"seconds"(-26_78_400));
6752 
6753         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 5, 12, 30, 33)) ==
6754                dur!"seconds"(86_400));
6755         assert(SysTime(DateTime(1999, 7, 5, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6756                dur!"seconds"(-86_400));
6757 
6758         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 11, 30, 33)) ==
6759                dur!"seconds"(3600));
6760         assert(SysTime(DateTime(1999, 7, 6, 11, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6761                dur!"seconds"(-3600));
6762 
6763         assert(SysTime(DateTime(1999, 7, 6, 12, 31, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6764                dur!"seconds"(60));
6765         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 31, 33)) ==
6766                dur!"seconds"(-60));
6767 
6768         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 34)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6769                dur!"seconds"(1));
6770         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 34)) ==
6771                dur!"seconds"(-1));
6772 
6773         {
6774             auto dt = DateTime(1999, 7, 6, 12, 30, 33);
6775             assert(SysTime(dt, msecs(532)) - SysTime(dt) == msecs(532));
6776             assert(SysTime(dt) - SysTime(dt, msecs(532)) == msecs(-532));
6777 
6778             assert(SysTime(dt, usecs(333_347)) - SysTime(dt) == usecs(333_347));
6779             assert(SysTime(dt) - SysTime(dt, usecs(333_347)) == usecs(-333_347));
6780 
6781             assert(SysTime(dt, hnsecs(1_234_567)) - SysTime(dt) == hnsecs(1_234_567));
6782             assert(SysTime(dt) - SysTime(dt, hnsecs(1_234_567)) == hnsecs(-1_234_567));
6783         }
6784 
6785         assert(SysTime(DateTime(1, 1, 1, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(45033));
6786         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(1, 1, 1, 12, 30, 33)) == dur!"seconds"(-45033));
6787         assert(SysTime(DateTime(0, 12, 31, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(-41367));
6788         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 12, 30, 33)) == dur!"seconds"(41367));
6789 
6790         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) ==
6791                dur!"hnsecs"(1));
6792         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) ==
6793                dur!"hnsecs"(-1));
6794 
6795         version (Posix)
6796         {
6797             import std.datetime.timezone : PosixTimeZone;
6798             immutable tz = PosixTimeZone.getTimeZone("America/Los_Angeles");
6799         }
6800         else version (Windows)
6801         {
6802             import std.datetime.timezone : WindowsTimeZone;
6803             immutable tz = WindowsTimeZone.getTimeZone("Pacific Standard Time");
6804         }
6805 
6806         {
6807             auto dt = DateTime(2011, 1, 13, 8, 17, 2);
6808             auto d = msecs(296);
6809             assert(SysTime(dt, d, tz) - SysTime(dt, d, tz) == Duration.zero);
6810             assert(SysTime(dt, d, tz) - SysTime(dt, d, UTC()) == hours(8));
6811             assert(SysTime(dt, d, UTC()) - SysTime(dt, d, tz) == hours(-8));
6812         }
6813 
6814         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6815         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6816         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6817         assert(st - st == Duration.zero);
6818         assert(cst - st == Duration.zero);
6819         assert(ist - st == Duration.zero);
6820 
6821         assert(st - cst == Duration.zero);
6822         assert(cst - cst == Duration.zero);
6823         assert(ist - cst == Duration.zero);
6824 
6825         assert(st - ist == Duration.zero);
6826         assert(cst - ist == Duration.zero);
6827         assert(ist - ist == Duration.zero);
6828 
6829         static void testScope(scope ref SysTime left, scope ref SysTime right) @safe
6830         {
6831             auto result = left - right;
6832         }
6833     }
6834 
6835 
6836     /++
6837         Returns the difference between the two $(LREF SysTime)s in months.
6838 
6839         To get the difference in years, subtract the year property
6840         of two $(LREF SysTime)s. To get the difference in days or weeks,
6841         subtract the $(LREF SysTime)s themselves and use the
6842         $(REF Duration, core,time) that results. Because converting between
6843         months and smaller units requires a specific date (which
6844         $(REF Duration, core,time)s don't have), getting the difference in
6845         months requires some math using both the year and month properties, so
6846         this is a convenience function for getting the difference in months.
6847 
6848         Note that the number of days in the months or how far into the month
6849         either date is is irrelevant. It is the difference in the month property
6850         combined with the difference in years * 12. So, for instance,
6851         December 31st and January 1st are one month apart just as December 1st
6852         and January 31st are one month apart.
6853 
6854         Params:
6855             rhs = The $(LREF SysTime) to subtract from this one.
6856       +/
6857     int diffMonths(scope SysTime rhs) @safe const nothrow scope
6858     {
6859         return (cast(Date) this).diffMonths(cast(Date) rhs);
6860     }
6861 
6862     ///
6863     @safe unittest
6864     {
6865         import core.time;
6866         import std.datetime.date : Date;
6867 
6868         assert(SysTime(Date(1999, 2, 1)).diffMonths(
6869                    SysTime(Date(1999, 1, 31))) == 1);
6870 
6871         assert(SysTime(Date(1999, 1, 31)).diffMonths(
6872                    SysTime(Date(1999, 2, 1))) == -1);
6873 
6874         assert(SysTime(Date(1999, 3, 1)).diffMonths(
6875                    SysTime(Date(1999, 1, 1))) == 2);
6876 
6877         assert(SysTime(Date(1999, 1, 1)).diffMonths(
6878                    SysTime(Date(1999, 3, 31))) == -2);
6879     }
6880 
6881     @safe unittest
6882     {
6883         import core.time;
6884         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6885         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6886         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6887         assert(st.diffMonths(st) == 0);
6888         assert(cst.diffMonths(st) == 0);
6889         assert(ist.diffMonths(st) == 0);
6890 
6891         assert(st.diffMonths(cst) == 0);
6892         assert(cst.diffMonths(cst) == 0);
6893         assert(ist.diffMonths(cst) == 0);
6894 
6895         assert(st.diffMonths(ist) == 0);
6896         assert(cst.diffMonths(ist) == 0);
6897         assert(ist.diffMonths(ist) == 0);
6898 
6899         static void testScope(scope ref SysTime left, scope ref SysTime right) @safe
6900         {
6901             auto result = left.diffMonths(right);
6902         }
6903     }
6904 
6905 
6906     /++
6907         Whether this $(LREF SysTime) is in a leap year.
6908      +/
6909     @property bool isLeapYear() @safe const nothrow scope
6910     {
6911         return (cast(Date) this).isLeapYear;
6912     }
6913 
6914     @safe unittest
6915     {
6916         import core.time;
6917         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6918         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6919         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6920         assert(!st.isLeapYear);
6921         assert(!cst.isLeapYear);
6922         assert(!ist.isLeapYear);
6923 
6924         static void testScope(scope ref SysTime st) @safe
6925         {
6926             auto result = st.isLeapYear;
6927         }
6928     }
6929 
6930 
6931     /++
6932         Day of the week this $(LREF SysTime) is on.
6933       +/
6934     @property DayOfWeek dayOfWeek() @safe const nothrow scope
6935     {
6936         return getDayOfWeek(dayOfGregorianCal);
6937     }
6938 
6939     @safe unittest
6940     {
6941         import core.time;
6942         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6943         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6944         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6945         assert(st.dayOfWeek == DayOfWeek.tue);
6946         assert(cst.dayOfWeek == DayOfWeek.tue);
6947         assert(ist.dayOfWeek == DayOfWeek.tue);
6948 
6949         static void testScope(scope ref SysTime st) @safe
6950         {
6951             auto result = st.dayOfWeek;
6952         }
6953     }
6954 
6955 
6956     /++
6957         Day of the year this $(LREF SysTime) is on.
6958       +/
6959     @property ushort dayOfYear() @safe const nothrow scope
6960     {
6961         return (cast(Date) this).dayOfYear;
6962     }
6963 
6964     ///
6965     @safe unittest
6966     {
6967         import core.time;
6968         import std.datetime.date : DateTime;
6969 
6970         assert(SysTime(DateTime(1999, 1, 1, 12, 22, 7)).dayOfYear == 1);
6971         assert(SysTime(DateTime(1999, 12, 31, 7, 2, 59)).dayOfYear == 365);
6972         assert(SysTime(DateTime(2000, 12, 31, 21, 20, 0)).dayOfYear == 366);
6973     }
6974 
6975     @safe unittest
6976     {
6977         import core.time;
6978         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6979         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6980         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6981         assert(st.dayOfYear == 187);
6982         assert(cst.dayOfYear == 187);
6983         assert(ist.dayOfYear == 187);
6984 
6985         static void testScope(scope ref SysTime st) @safe
6986         {
6987             auto result = st.dayOfYear;
6988         }
6989     }
6990 
6991 
6992     /++
6993         Day of the year.
6994 
6995         Params:
6996             day = The day of the year to set which day of the year this
6997                   $(LREF SysTime) is on.
6998       +/
6999     @property void dayOfYear(int day) @safe scope
7000     {
7001         immutable hnsecs = adjTime;
7002         immutable days = convert!("hnsecs", "days")(hnsecs);
7003         immutable theRest = hnsecs - convert!("days", "hnsecs")(days);
7004 
7005         auto date = Date(cast(int) days);
7006         date.dayOfYear = day;
7007 
7008         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
7009 
7010         adjTime = newDaysHNSecs + theRest;
7011     }
7012 
7013     @safe unittest
7014     {
7015         import core.time;
7016         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7017         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7018         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7019         st.dayOfYear = 12;
7020         assert(st.dayOfYear == 12);
7021         static assert(!__traits(compiles, cst.dayOfYear = 12));
7022         static assert(!__traits(compiles, ist.dayOfYear = 12));
7023 
7024         static void testScope(scope ref SysTime st) @safe
7025         {
7026             st.dayOfYear = 42;
7027         }
7028     }
7029 
7030 
7031     /++
7032         The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on.
7033      +/
7034     @property int dayOfGregorianCal() @safe const nothrow scope
7035     {
7036         immutable adjustedTime = adjTime;
7037 
7038         // We have to add one because 0 would be midnight, January 1st, 1 A.D.,
7039         // which would be the 1st day of the Gregorian Calendar, not the 0th. So,
7040         // simply casting to days is one day off.
7041         if (adjustedTime > 0)
7042             return cast(int) getUnitsFromHNSecs!"days"(adjustedTime) + 1;
7043 
7044         long hnsecs = adjustedTime;
7045         immutable days = cast(int) splitUnitsFromHNSecs!"days"(hnsecs);
7046 
7047         return hnsecs == 0 ? days + 1 : days;
7048     }
7049 
7050     ///
7051     @safe unittest
7052     {
7053         import core.time;
7054         import std.datetime.date : DateTime;
7055 
7056         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
7057         assert(SysTime(DateTime(1, 12, 31, 23, 59, 59)).dayOfGregorianCal == 365);
7058         assert(SysTime(DateTime(2, 1, 1, 2, 2, 2)).dayOfGregorianCal == 366);
7059 
7060         assert(SysTime(DateTime(0, 12, 31, 7, 7, 7)).dayOfGregorianCal == 0);
7061         assert(SysTime(DateTime(0, 1, 1, 19, 30, 0)).dayOfGregorianCal == -365);
7062         assert(SysTime(DateTime(-1, 12, 31, 4, 7, 0)).dayOfGregorianCal == -366);
7063 
7064         assert(SysTime(DateTime(2000, 1, 1, 9, 30, 20)).dayOfGregorianCal == 730_120);
7065         assert(SysTime(DateTime(2010, 12, 31, 15, 45, 50)).dayOfGregorianCal == 734_137);
7066     }
7067 
7068     @safe unittest
7069     {
7070         import core.time;
7071         // Test A.D.
7072         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
7073         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 1);
7074         assert(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 1);
7075 
7076         assert(SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1);
7077         assert(SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)).dayOfGregorianCal == 2);
7078         assert(SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 32);
7079         assert(SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 366);
7080         assert(SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 731);
7081         assert(SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1096);
7082         assert(SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1462);
7083         assert(SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 17_898);
7084         assert(SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 35_065);
7085         assert(SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_160);
7086         assert(SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_525);
7087         assert(SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 37_986);
7088         assert(SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 72_684);
7089         assert(SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 73_049);
7090         assert(SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_208);
7091         assert(SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_573);
7092         assert(SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 145_732);
7093         assert(SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 146_098);
7094         assert(SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_257);
7095         assert(SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_622);
7096         assert(SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 364_878);
7097         assert(SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 365_243);
7098         assert(SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_023);
7099         assert(SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_389);
7100         assert(SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_596);
7101         assert(SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_961);
7102         assert(SysTime(DateTime(1945, 11, 12, 12, 2, 9), msecs(212)).dayOfGregorianCal == 710_347);
7103         assert(SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 729_755);
7104         assert(SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_120);
7105         assert(SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_486);
7106 
7107         assert(SysTime(DateTime(2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_773);
7108         assert(SysTime(DateTime(2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_803);
7109         assert(SysTime(DateTime(2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_804);
7110         assert(SysTime(DateTime(2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_831);
7111         assert(SysTime(DateTime(2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_832);
7112         assert(SysTime(DateTime(2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_862);
7113         assert(SysTime(DateTime(2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_863);
7114         assert(SysTime(DateTime(2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_892);
7115         assert(SysTime(DateTime(2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_893);
7116         assert(SysTime(DateTime(2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_923);
7117         assert(SysTime(DateTime(2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_924);
7118         assert(SysTime(DateTime(2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_953);
7119         assert(SysTime(DateTime(2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_954);
7120         assert(SysTime(DateTime(2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_984);
7121         assert(SysTime(DateTime(2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_985);
7122         assert(SysTime(DateTime(2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_015);
7123         assert(SysTime(DateTime(2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_016);
7124         assert(SysTime(DateTime(2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_045);
7125         assert(SysTime(DateTime(2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_046);
7126         assert(SysTime(DateTime(2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_076);
7127         assert(SysTime(DateTime(2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_077);
7128         assert(SysTime(DateTime(2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_106);
7129         assert(SysTime(DateTime(2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_107);
7130         assert(SysTime(DateTime(2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_137);
7131 
7132         assert(SysTime(DateTime(2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == 734_534);
7133         assert(SysTime(DateTime(2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == 734_561);
7134         assert(SysTime(DateTime(2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == 734_562);
7135         assert(SysTime(DateTime(2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == 734_563);
7136 
7137         // Test B.C.
7138         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 0);
7139         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == 0);
7140         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59)).dayOfGregorianCal == 0);
7141         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 0);
7142         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).dayOfGregorianCal == 0);
7143 
7144         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == -366);
7145         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == -366);
7146         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59)).dayOfGregorianCal == -366);
7147         assert(SysTime(DateTime(-1, 12, 31, 0, 0, 0)).dayOfGregorianCal == -366);
7148 
7149         assert(SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == 0);
7150         assert(SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1);
7151         assert(SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -30);
7152         assert(SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -31);
7153 
7154         assert(SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -366);
7155         assert(SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -367);
7156         assert(SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730);
7157         assert(SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731);
7158         assert(SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1095);
7159         assert(SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1096);
7160         assert(SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1460);
7161         assert(SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1461);
7162         assert(SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1826);
7163         assert(SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1827);
7164         assert(SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -2191);
7165         assert(SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -3652);
7166 
7167         assert(SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_262);
7168         assert(SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_627);
7169         assert(SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -35_794);
7170         assert(SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_160);
7171         assert(SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_524);
7172         assert(SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_889);
7173         assert(SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -37_254);
7174         assert(SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -38_715);
7175         assert(SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_413);
7176         assert(SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_778);
7177         assert(SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -109_937);
7178         assert(SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -110_302);
7179         assert(SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_097);
7180         assert(SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_462);
7181         assert(SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_827);
7182         assert(SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_621);
7183         assert(SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_986);
7184         assert(SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -183_351);
7185         assert(SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_607);
7186         assert(SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_972);
7187         assert(SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_387);
7188         assert(SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_388);
7189         assert(SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_753);
7190         assert(SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -585_118);
7191         assert(SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_325);
7192         assert(SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_690);
7193         assert(SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_484);
7194         assert(SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_485);
7195         assert(SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_850);
7196         assert(SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731_215);
7197 
7198         assert(SysTime(DateTime(-2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_502);
7199         assert(SysTime(DateTime(-2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_472);
7200         assert(SysTime(DateTime(-2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_471);
7201         assert(SysTime(DateTime(-2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_444);
7202         assert(SysTime(DateTime(-2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_443);
7203         assert(SysTime(DateTime(-2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_413);
7204         assert(SysTime(DateTime(-2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_412);
7205         assert(SysTime(DateTime(-2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_383);
7206         assert(SysTime(DateTime(-2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_382);
7207         assert(SysTime(DateTime(-2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_352);
7208         assert(SysTime(DateTime(-2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_351);
7209         assert(SysTime(DateTime(-2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_322);
7210         assert(SysTime(DateTime(-2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_321);
7211         assert(SysTime(DateTime(-2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_291);
7212         assert(SysTime(DateTime(-2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_290);
7213         assert(SysTime(DateTime(-2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_260);
7214         assert(SysTime(DateTime(-2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_259);
7215         assert(SysTime(DateTime(-2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_230);
7216         assert(SysTime(DateTime(-2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_229);
7217         assert(SysTime(DateTime(-2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_199);
7218         assert(SysTime(DateTime(-2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_198);
7219         assert(SysTime(DateTime(-2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_169);
7220         assert(SysTime(DateTime(-2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_168);
7221         assert(SysTime(DateTime(-2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_138);
7222 
7223         assert(SysTime(DateTime(-2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == -735_202);
7224         assert(SysTime(DateTime(-2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == -735_175);
7225         assert(SysTime(DateTime(-2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == -735_174);
7226         assert(SysTime(DateTime(-2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == -735_173);
7227 
7228         // Start of Hebrew Calendar
7229         assert(SysTime(DateTime(-3760, 9, 7, 0, 0, 0)).dayOfGregorianCal == -1_373_427);
7230 
7231         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7232         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7233         assert(cst.dayOfGregorianCal == 729_941);
7234         assert(ist.dayOfGregorianCal == 729_941);
7235 
7236         static void testScope(scope ref SysTime st) @safe
7237         {
7238             auto result = st.dayOfGregorianCal;
7239         }
7240     }
7241 
7242 
7243     // Test that the logic for the day of the Gregorian Calendar is consistent
7244     // between Date and SysTime.
7245     @safe unittest
7246     {
7247         import core.time;
7248         void test(Date date, SysTime st, size_t line = __LINE__)
7249         {
7250             if (date.dayOfGregorianCal != st.dayOfGregorianCal)
7251             {
7252                 throw new AssertError(format("Date [%s] SysTime [%s]", date.dayOfGregorianCal, st.dayOfGregorianCal),
7253                                       __FILE__, line);
7254             }
7255         }
7256 
7257         // Test A.D.
7258         test(Date(1, 1, 1), SysTime(DateTime(1, 1, 1, 0, 0, 0)));
7259         test(Date(1, 1, 2), SysTime(DateTime(1, 1, 2, 0, 0, 0), hnsecs(500)));
7260         test(Date(1, 2, 1), SysTime(DateTime(1, 2, 1, 0, 0, 0), hnsecs(50_000)));
7261         test(Date(2, 1, 1), SysTime(DateTime(2, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7262         test(Date(3, 1, 1), SysTime(DateTime(3, 1, 1, 12, 13, 14)));
7263         test(Date(4, 1, 1), SysTime(DateTime(4, 1, 1, 12, 13, 14), hnsecs(500)));
7264         test(Date(5, 1, 1), SysTime(DateTime(5, 1, 1, 12, 13, 14), hnsecs(50_000)));
7265         test(Date(50, 1, 1), SysTime(DateTime(50, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7266         test(Date(97, 1, 1), SysTime(DateTime(97, 1, 1, 23, 59, 59)));
7267         test(Date(100, 1, 1), SysTime(DateTime(100, 1, 1, 23, 59, 59), hnsecs(500)));
7268         test(Date(101, 1, 1), SysTime(DateTime(101, 1, 1, 23, 59, 59), hnsecs(50_000)));
7269         test(Date(105, 1, 1), SysTime(DateTime(105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7270         test(Date(200, 1, 1), SysTime(DateTime(200, 1, 1, 0, 0, 0)));
7271         test(Date(201, 1, 1), SysTime(DateTime(201, 1, 1, 0, 0, 0), hnsecs(500)));
7272         test(Date(300, 1, 1), SysTime(DateTime(300, 1, 1, 0, 0, 0), hnsecs(50_000)));
7273         test(Date(301, 1, 1), SysTime(DateTime(301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7274         test(Date(400, 1, 1), SysTime(DateTime(400, 1, 1, 12, 13, 14)));
7275         test(Date(401, 1, 1), SysTime(DateTime(401, 1, 1, 12, 13, 14), hnsecs(500)));
7276         test(Date(500, 1, 1), SysTime(DateTime(500, 1, 1, 12, 13, 14), hnsecs(50_000)));
7277         test(Date(501, 1, 1), SysTime(DateTime(501, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7278         test(Date(1000, 1, 1), SysTime(DateTime(1000, 1, 1, 23, 59, 59)));
7279         test(Date(1001, 1, 1), SysTime(DateTime(1001, 1, 1, 23, 59, 59), hnsecs(500)));
7280         test(Date(1600, 1, 1), SysTime(DateTime(1600, 1, 1, 23, 59, 59), hnsecs(50_000)));
7281         test(Date(1601, 1, 1), SysTime(DateTime(1601, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7282         test(Date(1900, 1, 1), SysTime(DateTime(1900, 1, 1, 0, 0, 0)));
7283         test(Date(1901, 1, 1), SysTime(DateTime(1901, 1, 1, 0, 0, 0), hnsecs(500)));
7284         test(Date(1945, 11, 12), SysTime(DateTime(1945, 11, 12, 0, 0, 0), hnsecs(50_000)));
7285         test(Date(1999, 1, 1), SysTime(DateTime(1999, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7286         test(Date(1999, 7, 6), SysTime(DateTime(1999, 7, 6, 12, 13, 14)));
7287         test(Date(2000, 1, 1), SysTime(DateTime(2000, 1, 1, 12, 13, 14), hnsecs(500)));
7288         test(Date(2001, 1, 1), SysTime(DateTime(2001, 1, 1, 12, 13, 14), hnsecs(50_000)));
7289 
7290         test(Date(2010, 1, 1), SysTime(DateTime(2010, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7291         test(Date(2010, 1, 31), SysTime(DateTime(2010, 1, 31, 23, 0, 0)));
7292         test(Date(2010, 2, 1), SysTime(DateTime(2010, 2, 1, 23, 59, 59), hnsecs(500)));
7293         test(Date(2010, 2, 28), SysTime(DateTime(2010, 2, 28, 23, 59, 59), hnsecs(50_000)));
7294         test(Date(2010, 3, 1), SysTime(DateTime(2010, 3, 1, 23, 59, 59), hnsecs(9_999_999)));
7295         test(Date(2010, 3, 31), SysTime(DateTime(2010, 3, 31, 0, 0, 0)));
7296         test(Date(2010, 4, 1), SysTime(DateTime(2010, 4, 1, 0, 0, 0), hnsecs(500)));
7297         test(Date(2010, 4, 30), SysTime(DateTime(2010, 4, 30, 0, 0, 0), hnsecs(50_000)));
7298         test(Date(2010, 5, 1), SysTime(DateTime(2010, 5, 1, 0, 0, 0), hnsecs(9_999_999)));
7299         test(Date(2010, 5, 31), SysTime(DateTime(2010, 5, 31, 12, 13, 14)));
7300         test(Date(2010, 6, 1), SysTime(DateTime(2010, 6, 1, 12, 13, 14), hnsecs(500)));
7301         test(Date(2010, 6, 30), SysTime(DateTime(2010, 6, 30, 12, 13, 14), hnsecs(50_000)));
7302         test(Date(2010, 7, 1), SysTime(DateTime(2010, 7, 1, 12, 13, 14), hnsecs(9_999_999)));
7303         test(Date(2010, 7, 31), SysTime(DateTime(2010, 7, 31, 23, 59, 59)));
7304         test(Date(2010, 8, 1), SysTime(DateTime(2010, 8, 1, 23, 59, 59), hnsecs(500)));
7305         test(Date(2010, 8, 31), SysTime(DateTime(2010, 8, 31, 23, 59, 59), hnsecs(50_000)));
7306         test(Date(2010, 9, 1), SysTime(DateTime(2010, 9, 1, 23, 59, 59), hnsecs(9_999_999)));
7307         test(Date(2010, 9, 30), SysTime(DateTime(2010, 9, 30, 12, 0, 0)));
7308         test(Date(2010, 10, 1), SysTime(DateTime(2010, 10, 1, 0, 12, 0), hnsecs(500)));
7309         test(Date(2010, 10, 31), SysTime(DateTime(2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
7310         test(Date(2010, 11, 1), SysTime(DateTime(2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
7311         test(Date(2010, 11, 30), SysTime(DateTime(2010, 11, 30, 0, 59, 0)));
7312         test(Date(2010, 12, 1), SysTime(DateTime(2010, 12, 1, 0, 0, 59), hnsecs(500)));
7313         test(Date(2010, 12, 31), SysTime(DateTime(2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
7314 
7315         test(Date(2012, 2, 1), SysTime(DateTime(2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
7316         test(Date(2012, 2, 28), SysTime(DateTime(2012, 2, 28, 23, 59, 0)));
7317         test(Date(2012, 2, 29), SysTime(DateTime(2012, 2, 29, 7, 7, 7), hnsecs(7)));
7318         test(Date(2012, 3, 1), SysTime(DateTime(2012, 3, 1, 7, 7, 7), hnsecs(7)));
7319 
7320         // Test B.C.
7321         test(Date(0, 12, 31), SysTime(DateTime(0, 12, 31, 0, 0, 0)));
7322         test(Date(0, 12, 30), SysTime(DateTime(0, 12, 30, 0, 0, 0), hnsecs(500)));
7323         test(Date(0, 12, 1), SysTime(DateTime(0, 12, 1, 0, 0, 0), hnsecs(50_000)));
7324         test(Date(0, 11, 30), SysTime(DateTime(0, 11, 30, 0, 0, 0), hnsecs(9_999_999)));
7325 
7326         test(Date(-1, 12, 31), SysTime(DateTime(-1, 12, 31, 12, 13, 14)));
7327         test(Date(-1, 12, 30), SysTime(DateTime(-1, 12, 30, 12, 13, 14), hnsecs(500)));
7328         test(Date(-1, 1, 1), SysTime(DateTime(-1, 1, 1, 12, 13, 14), hnsecs(50_000)));
7329         test(Date(-2, 12, 31), SysTime(DateTime(-2, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
7330         test(Date(-2, 1, 1), SysTime(DateTime(-2, 1, 1, 23, 59, 59)));
7331         test(Date(-3, 12, 31), SysTime(DateTime(-3, 12, 31, 23, 59, 59), hnsecs(500)));
7332         test(Date(-3, 1, 1), SysTime(DateTime(-3, 1, 1, 23, 59, 59), hnsecs(50_000)));
7333         test(Date(-4, 12, 31), SysTime(DateTime(-4, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7334         test(Date(-4, 1, 1), SysTime(DateTime(-4, 1, 1, 0, 0, 0)));
7335         test(Date(-5, 12, 31), SysTime(DateTime(-5, 12, 31, 0, 0, 0), hnsecs(500)));
7336         test(Date(-5, 1, 1), SysTime(DateTime(-5, 1, 1, 0, 0, 0), hnsecs(50_000)));
7337         test(Date(-9, 1, 1), SysTime(DateTime(-9, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7338 
7339         test(Date(-49, 1, 1), SysTime(DateTime(-49, 1, 1, 12, 13, 14)));
7340         test(Date(-50, 1, 1), SysTime(DateTime(-50, 1, 1, 12, 13, 14), hnsecs(500)));
7341         test(Date(-97, 1, 1), SysTime(DateTime(-97, 1, 1, 12, 13, 14), hnsecs(50_000)));
7342         test(Date(-99, 12, 31), SysTime(DateTime(-99, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
7343         test(Date(-99, 1, 1), SysTime(DateTime(-99, 1, 1, 23, 59, 59)));
7344         test(Date(-100, 1, 1), SysTime(DateTime(-100, 1, 1, 23, 59, 59), hnsecs(500)));
7345         test(Date(-101, 1, 1), SysTime(DateTime(-101, 1, 1, 23, 59, 59), hnsecs(50_000)));
7346         test(Date(-105, 1, 1), SysTime(DateTime(-105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7347         test(Date(-200, 1, 1), SysTime(DateTime(-200, 1, 1, 0, 0, 0)));
7348         test(Date(-201, 1, 1), SysTime(DateTime(-201, 1, 1, 0, 0, 0), hnsecs(500)));
7349         test(Date(-300, 1, 1), SysTime(DateTime(-300, 1, 1, 0, 0, 0), hnsecs(50_000)));
7350         test(Date(-301, 1, 1), SysTime(DateTime(-301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7351         test(Date(-400, 12, 31), SysTime(DateTime(-400, 12, 31, 12, 13, 14)));
7352         test(Date(-400, 1, 1), SysTime(DateTime(-400, 1, 1, 12, 13, 14), hnsecs(500)));
7353         test(Date(-401, 1, 1), SysTime(DateTime(-401, 1, 1, 12, 13, 14), hnsecs(50_000)));
7354         test(Date(-499, 1, 1), SysTime(DateTime(-499, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7355         test(Date(-500, 1, 1), SysTime(DateTime(-500, 1, 1, 23, 59, 59)));
7356         test(Date(-501, 1, 1), SysTime(DateTime(-501, 1, 1, 23, 59, 59), hnsecs(500)));
7357         test(Date(-1000, 1, 1), SysTime(DateTime(-1000, 1, 1, 23, 59, 59), hnsecs(50_000)));
7358         test(Date(-1001, 1, 1), SysTime(DateTime(-1001, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7359         test(Date(-1599, 1, 1), SysTime(DateTime(-1599, 1, 1, 0, 0, 0)));
7360         test(Date(-1600, 12, 31), SysTime(DateTime(-1600, 12, 31, 0, 0, 0), hnsecs(500)));
7361         test(Date(-1600, 1, 1), SysTime(DateTime(-1600, 1, 1, 0, 0, 0), hnsecs(50_000)));
7362         test(Date(-1601, 1, 1), SysTime(DateTime(-1601, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7363         test(Date(-1900, 1, 1), SysTime(DateTime(-1900, 1, 1, 12, 13, 14)));
7364         test(Date(-1901, 1, 1), SysTime(DateTime(-1901, 1, 1, 12, 13, 14), hnsecs(500)));
7365         test(Date(-1999, 1, 1), SysTime(DateTime(-1999, 1, 1, 12, 13, 14), hnsecs(50_000)));
7366         test(Date(-1999, 7, 6), SysTime(DateTime(-1999, 7, 6, 12, 13, 14), hnsecs(9_999_999)));
7367         test(Date(-2000, 12, 31), SysTime(DateTime(-2000, 12, 31, 23, 59, 59)));
7368         test(Date(-2000, 1, 1), SysTime(DateTime(-2000, 1, 1, 23, 59, 59), hnsecs(500)));
7369         test(Date(-2001, 1, 1), SysTime(DateTime(-2001, 1, 1, 23, 59, 59), hnsecs(50_000)));
7370 
7371         test(Date(-2010, 1, 1), SysTime(DateTime(-2010, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7372         test(Date(-2010, 1, 31), SysTime(DateTime(-2010, 1, 31, 0, 0, 0)));
7373         test(Date(-2010, 2, 1), SysTime(DateTime(-2010, 2, 1, 0, 0, 0), hnsecs(500)));
7374         test(Date(-2010, 2, 28), SysTime(DateTime(-2010, 2, 28, 0, 0, 0), hnsecs(50_000)));
7375         test(Date(-2010, 3, 1), SysTime(DateTime(-2010, 3, 1, 0, 0, 0), hnsecs(9_999_999)));
7376         test(Date(-2010, 3, 31), SysTime(DateTime(-2010, 3, 31, 12, 13, 14)));
7377         test(Date(-2010, 4, 1), SysTime(DateTime(-2010, 4, 1, 12, 13, 14), hnsecs(500)));
7378         test(Date(-2010, 4, 30), SysTime(DateTime(-2010, 4, 30, 12, 13, 14), hnsecs(50_000)));
7379         test(Date(-2010, 5, 1), SysTime(DateTime(-2010, 5, 1, 12, 13, 14), hnsecs(9_999_999)));
7380         test(Date(-2010, 5, 31), SysTime(DateTime(-2010, 5, 31, 23, 59, 59)));
7381         test(Date(-2010, 6, 1), SysTime(DateTime(-2010, 6, 1, 23, 59, 59), hnsecs(500)));
7382         test(Date(-2010, 6, 30), SysTime(DateTime(-2010, 6, 30, 23, 59, 59), hnsecs(50_000)));
7383         test(Date(-2010, 7, 1), SysTime(DateTime(-2010, 7, 1, 23, 59, 59), hnsecs(9_999_999)));
7384         test(Date(-2010, 7, 31), SysTime(DateTime(-2010, 7, 31, 0, 0, 0)));
7385         test(Date(-2010, 8, 1), SysTime(DateTime(-2010, 8, 1, 0, 0, 0), hnsecs(500)));
7386         test(Date(-2010, 8, 31), SysTime(DateTime(-2010, 8, 31, 0, 0, 0), hnsecs(50_000)));
7387         test(Date(-2010, 9, 1), SysTime(DateTime(-2010, 9, 1, 0, 0, 0), hnsecs(9_999_999)));
7388         test(Date(-2010, 9, 30), SysTime(DateTime(-2010, 9, 30, 12, 0, 0)));
7389         test(Date(-2010, 10, 1), SysTime(DateTime(-2010, 10, 1, 0, 12, 0), hnsecs(500)));
7390         test(Date(-2010, 10, 31), SysTime(DateTime(-2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
7391         test(Date(-2010, 11, 1), SysTime(DateTime(-2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
7392         test(Date(-2010, 11, 30), SysTime(DateTime(-2010, 11, 30, 0, 59, 0)));
7393         test(Date(-2010, 12, 1), SysTime(DateTime(-2010, 12, 1, 0, 0, 59), hnsecs(500)));
7394         test(Date(-2010, 12, 31), SysTime(DateTime(-2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
7395 
7396         test(Date(-2012, 2, 1), SysTime(DateTime(-2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
7397         test(Date(-2012, 2, 28), SysTime(DateTime(-2012, 2, 28, 23, 59, 0)));
7398         test(Date(-2012, 2, 29), SysTime(DateTime(-2012, 2, 29, 7, 7, 7), hnsecs(7)));
7399         test(Date(-2012, 3, 1), SysTime(DateTime(-2012, 3, 1, 7, 7, 7), hnsecs(7)));
7400 
7401         test(Date(-3760, 9, 7), SysTime(DateTime(-3760, 9, 7, 0, 0, 0)));
7402     }
7403 
7404 
7405     /++
7406         The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on.
7407         Setting this property does not affect the time portion of $(LREF SysTime).
7408 
7409         Params:
7410             days = The day of the Gregorian Calendar to set this $(LREF SysTime)
7411                    to.
7412      +/
7413     @property void dayOfGregorianCal(int days) @safe nothrow scope
7414     {
7415         auto hnsecs = adjTime;
7416         hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
7417 
7418         if (hnsecs < 0)
7419             hnsecs += convert!("hours", "hnsecs")(24);
7420 
7421         if (--days < 0)
7422         {
7423             hnsecs -= convert!("hours", "hnsecs")(24);
7424             ++days;
7425         }
7426 
7427         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
7428 
7429         adjTime = newDaysHNSecs + hnsecs;
7430     }
7431 
7432     ///
7433     @safe unittest
7434     {
7435         import core.time;
7436         import std.datetime.date : DateTime;
7437 
7438         auto st = SysTime(DateTime(0, 1, 1, 12, 0, 0));
7439         st.dayOfGregorianCal = 1;
7440         assert(st == SysTime(DateTime(1, 1, 1, 12, 0, 0)));
7441 
7442         st.dayOfGregorianCal = 365;
7443         assert(st == SysTime(DateTime(1, 12, 31, 12, 0, 0)));
7444 
7445         st.dayOfGregorianCal = 366;
7446         assert(st == SysTime(DateTime(2, 1, 1, 12, 0, 0)));
7447 
7448         st.dayOfGregorianCal = 0;
7449         assert(st == SysTime(DateTime(0, 12, 31, 12, 0, 0)));
7450 
7451         st.dayOfGregorianCal = -365;
7452         assert(st == SysTime(DateTime(-0, 1, 1, 12, 0, 0)));
7453 
7454         st.dayOfGregorianCal = -366;
7455         assert(st == SysTime(DateTime(-1, 12, 31, 12, 0, 0)));
7456 
7457         st.dayOfGregorianCal = 730_120;
7458         assert(st == SysTime(DateTime(2000, 1, 1, 12, 0, 0)));
7459 
7460         st.dayOfGregorianCal = 734_137;
7461         assert(st == SysTime(DateTime(2010, 12, 31, 12, 0, 0)));
7462     }
7463 
7464     @safe unittest
7465     {
7466         import core.time;
7467         void testST(SysTime orig, int day, SysTime expected, size_t line = __LINE__) @safe
7468         {
7469             orig.dayOfGregorianCal = day;
7470             if (orig != expected)
7471                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
7472         }
7473 
7474         // Test A.D.
7475         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
7476         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
7477         testST(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 1,
7478                SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7479 
7480         // Test B.C.
7481         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
7482         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 0,
7483                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7484         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(1)), 0,
7485                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
7486         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
7487 
7488         // Test Both.
7489         testST(SysTime(DateTime(-512, 7, 20, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
7490         testST(SysTime(DateTime(-513, 6, 6, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
7491         testST(SysTime(DateTime(-511, 5, 7, 23, 59, 59), hnsecs(9_999_999)), 1,
7492                SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7493 
7494         testST(SysTime(DateTime(1607, 4, 8, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
7495         testST(SysTime(DateTime(1500, 3, 9, 23, 59, 59), hnsecs(9_999_999)), 0,
7496                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7497         testST(SysTime(DateTime(999, 2, 10, 23, 59, 59), hnsecs(1)), 0,
7498                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
7499         testST(SysTime(DateTime(2007, 12, 11, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
7500 
7501 
7502         auto st = SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212));
7503 
7504         void testST2(int day, SysTime expected, size_t line = __LINE__) @safe
7505         {
7506             st.dayOfGregorianCal = day;
7507             if (st != expected)
7508                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", st, expected), __FILE__, line);
7509         }
7510 
7511         // Test A.D.
7512         testST2(1, SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)));
7513         testST2(2, SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)));
7514         testST2(32, SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)));
7515         testST2(366, SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)));
7516         testST2(731, SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)));
7517         testST2(1096, SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)));
7518         testST2(1462, SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)));
7519         testST2(17_898, SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)));
7520         testST2(35_065, SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)));
7521         testST2(36_160, SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)));
7522         testST2(36_525, SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)));
7523         testST2(37_986, SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)));
7524         testST2(72_684, SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)));
7525         testST2(73_049, SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)));
7526         testST2(109_208, SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)));
7527         testST2(109_573, SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)));
7528         testST2(145_732, SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)));
7529         testST2(146_098, SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)));
7530         testST2(182_257, SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)));
7531         testST2(182_622, SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)));
7532         testST2(364_878, SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)));
7533         testST2(365_243, SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)));
7534         testST2(584_023, SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)));
7535         testST2(584_389, SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)));
7536         testST2(693_596, SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)));
7537         testST2(693_961, SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)));
7538         testST2(729_755, SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)));
7539         testST2(730_120, SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)));
7540         testST2(730_486, SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)));
7541 
7542         testST2(733_773, SysTime(DateTime(2010, 1, 1, 12, 2, 9), msecs(212)));
7543         testST2(733_803, SysTime(DateTime(2010, 1, 31, 12, 2, 9), msecs(212)));
7544         testST2(733_804, SysTime(DateTime(2010, 2, 1, 12, 2, 9), msecs(212)));
7545         testST2(733_831, SysTime(DateTime(2010, 2, 28, 12, 2, 9), msecs(212)));
7546         testST2(733_832, SysTime(DateTime(2010, 3, 1, 12, 2, 9), msecs(212)));
7547         testST2(733_862, SysTime(DateTime(2010, 3, 31, 12, 2, 9), msecs(212)));
7548         testST2(733_863, SysTime(DateTime(2010, 4, 1, 12, 2, 9), msecs(212)));
7549         testST2(733_892, SysTime(DateTime(2010, 4, 30, 12, 2, 9), msecs(212)));
7550         testST2(733_893, SysTime(DateTime(2010, 5, 1, 12, 2, 9), msecs(212)));
7551         testST2(733_923, SysTime(DateTime(2010, 5, 31, 12, 2, 9), msecs(212)));
7552         testST2(733_924, SysTime(DateTime(2010, 6, 1, 12, 2, 9), msecs(212)));
7553         testST2(733_953, SysTime(DateTime(2010, 6, 30, 12, 2, 9), msecs(212)));
7554         testST2(733_954, SysTime(DateTime(2010, 7, 1, 12, 2, 9), msecs(212)));
7555         testST2(733_984, SysTime(DateTime(2010, 7, 31, 12, 2, 9), msecs(212)));
7556         testST2(733_985, SysTime(DateTime(2010, 8, 1, 12, 2, 9), msecs(212)));
7557         testST2(734_015, SysTime(DateTime(2010, 8, 31, 12, 2, 9), msecs(212)));
7558         testST2(734_016, SysTime(DateTime(2010, 9, 1, 12, 2, 9), msecs(212)));
7559         testST2(734_045, SysTime(DateTime(2010, 9, 30, 12, 2, 9), msecs(212)));
7560         testST2(734_046, SysTime(DateTime(2010, 10, 1, 12, 2, 9), msecs(212)));
7561         testST2(734_076, SysTime(DateTime(2010, 10, 31, 12, 2, 9), msecs(212)));
7562         testST2(734_077, SysTime(DateTime(2010, 11, 1, 12, 2, 9), msecs(212)));
7563         testST2(734_106, SysTime(DateTime(2010, 11, 30, 12, 2, 9), msecs(212)));
7564         testST2(734_107, SysTime(DateTime(2010, 12, 1, 12, 2, 9), msecs(212)));
7565         testST2(734_137, SysTime(DateTime(2010, 12, 31, 12, 2, 9), msecs(212)));
7566 
7567         testST2(734_534, SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
7568         testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
7569         testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
7570         testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
7571 
7572         testST2(734_534,  SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
7573 
7574         testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
7575         testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
7576         testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
7577 
7578         // Test B.C.
7579         testST2(0, SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)));
7580         testST2(-1, SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)));
7581         testST2(-30, SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)));
7582         testST2(-31, SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)));
7583 
7584         testST2(-366, SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)));
7585         testST2(-367, SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)));
7586         testST2(-730, SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)));
7587         testST2(-731, SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)));
7588         testST2(-1095, SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)));
7589         testST2(-1096, SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)));
7590         testST2(-1460, SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)));
7591         testST2(-1461, SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)));
7592         testST2(-1826, SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)));
7593         testST2(-1827, SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)));
7594         testST2(-2191, SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)));
7595         testST2(-3652, SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)));
7596 
7597         testST2(-18_262, SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)));
7598         testST2(-18_627, SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)));
7599         testST2(-35_794, SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)));
7600         testST2(-36_160, SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)));
7601         testST2(-36_524, SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)));
7602         testST2(-36_889, SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)));
7603         testST2(-37_254, SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)));
7604         testST2(-38_715, SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)));
7605         testST2(-73_413, SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)));
7606         testST2(-73_778, SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)));
7607         testST2(-109_937, SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)));
7608         testST2(-110_302, SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)));
7609         testST2(-146_097, SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)));
7610         testST2(-146_462, SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)));
7611         testST2(-146_827, SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)));
7612         testST2(-182_621, SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)));
7613         testST2(-182_986, SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)));
7614         testST2(-183_351, SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)));
7615         testST2(-365_607, SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)));
7616         testST2(-365_972, SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)));
7617         testST2(-584_387, SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)));
7618         testST2(-584_388, SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)));
7619         testST2(-584_753, SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)));
7620         testST2(-585_118, SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)));
7621         testST2(-694_325, SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)));
7622         testST2(-694_690, SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)));
7623         testST2(-730_484, SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)));
7624         testST2(-730_485, SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)));
7625         testST2(-730_850, SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)));
7626         testST2(-731_215, SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)));
7627 
7628         testST2(-734_502, SysTime(DateTime(-2010, 1, 1, 12, 2, 9), msecs(212)));
7629         testST2(-734_472, SysTime(DateTime(-2010, 1, 31, 12, 2, 9), msecs(212)));
7630         testST2(-734_471, SysTime(DateTime(-2010, 2, 1, 12, 2, 9), msecs(212)));
7631         testST2(-734_444, SysTime(DateTime(-2010, 2, 28, 12, 2, 9), msecs(212)));
7632         testST2(-734_443, SysTime(DateTime(-2010, 3, 1, 12, 2, 9), msecs(212)));
7633         testST2(-734_413, SysTime(DateTime(-2010, 3, 31, 12, 2, 9), msecs(212)));
7634         testST2(-734_412, SysTime(DateTime(-2010, 4, 1, 12, 2, 9), msecs(212)));
7635         testST2(-734_383, SysTime(DateTime(-2010, 4, 30, 12, 2, 9), msecs(212)));
7636         testST2(-734_382, SysTime(DateTime(-2010, 5, 1, 12, 2, 9), msecs(212)));
7637         testST2(-734_352, SysTime(DateTime(-2010, 5, 31, 12, 2, 9), msecs(212)));
7638         testST2(-734_351, SysTime(DateTime(-2010, 6, 1, 12, 2, 9), msecs(212)));
7639         testST2(-734_322, SysTime(DateTime(-2010, 6, 30, 12, 2, 9), msecs(212)));
7640         testST2(-734_321, SysTime(DateTime(-2010, 7, 1, 12, 2, 9), msecs(212)));
7641         testST2(-734_291, SysTime(DateTime(-2010, 7, 31, 12, 2, 9), msecs(212)));
7642         testST2(-734_290, SysTime(DateTime(-2010, 8, 1, 12, 2, 9), msecs(212)));
7643         testST2(-734_260, SysTime(DateTime(-2010, 8, 31, 12, 2, 9), msecs(212)));
7644         testST2(-734_259, SysTime(DateTime(-2010, 9, 1, 12, 2, 9), msecs(212)));
7645         testST2(-734_230, SysTime(DateTime(-2010, 9, 30, 12, 2, 9), msecs(212)));
7646         testST2(-734_229, SysTime(DateTime(-2010, 10, 1, 12, 2, 9), msecs(212)));
7647         testST2(-734_199, SysTime(DateTime(-2010, 10, 31, 12, 2, 9), msecs(212)));
7648         testST2(-734_198, SysTime(DateTime(-2010, 11, 1, 12, 2, 9), msecs(212)));
7649         testST2(-734_169, SysTime(DateTime(-2010, 11, 30, 12, 2, 9), msecs(212)));
7650         testST2(-734_168, SysTime(DateTime(-2010, 12, 1, 12, 2, 9), msecs(212)));
7651         testST2(-734_138, SysTime(DateTime(-2010, 12, 31, 12, 2, 9), msecs(212)));
7652 
7653         testST2(-735_202, SysTime(DateTime(-2012, 2, 1, 12, 2, 9), msecs(212)));
7654         testST2(-735_175, SysTime(DateTime(-2012, 2, 28, 12, 2, 9), msecs(212)));
7655         testST2(-735_174, SysTime(DateTime(-2012, 2, 29, 12, 2, 9), msecs(212)));
7656         testST2(-735_173, SysTime(DateTime(-2012, 3, 1, 12, 2, 9), msecs(212)));
7657 
7658         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7659         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7660         static assert(!__traits(compiles, cst.dayOfGregorianCal = 7));
7661         static assert(!__traits(compiles, ist.dayOfGregorianCal = 7));
7662 
7663         static void testScope(scope ref SysTime st) @safe
7664         {
7665             st.dayOfGregorianCal = 42;
7666         }
7667     }
7668 
7669 
7670     /++
7671         The ISO 8601 week of the year that this $(LREF SysTime) is in.
7672 
7673         See_Also:
7674             $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date).
7675       +/
7676     @property ubyte isoWeek() @safe const nothrow scope
7677     {
7678         return (cast(Date) this).isoWeek;
7679     }
7680 
7681     ///
7682     @safe unittest
7683     {
7684         import core.time;
7685         import std.datetime.date : Date;
7686 
7687         auto st = SysTime(Date(1999, 7, 6));
7688         const cst = SysTime(Date(2010, 5, 1));
7689         immutable ist = SysTime(Date(2015, 10, 10));
7690 
7691         assert(st.isoWeek == 27);
7692         assert(cst.isoWeek == 17);
7693         assert(ist.isoWeek == 41);
7694     }
7695 
7696     @safe unittest
7697     {
7698         static void testScope(scope ref SysTime st) @safe
7699         {
7700             auto result = st.isoWeek;
7701         }
7702     }
7703 
7704 
7705     /++
7706         $(LREF SysTime) for the last day in the month that this Date is in.
7707         The time portion of endOfMonth is always 23:59:59.9999999.
7708       +/
7709     @property SysTime endOfMonth() @safe const nothrow return scope
7710     {
7711         immutable hnsecs = adjTime;
7712         immutable days = getUnitsFromHNSecs!"days"(hnsecs);
7713 
7714         auto date = Date(cast(int) days + 1).endOfMonth;
7715         auto newDays = date.dayOfGregorianCal - 1;
7716         long theTimeHNSecs;
7717 
7718         if (newDays < 0)
7719         {
7720             theTimeHNSecs = -1;
7721             ++newDays;
7722         }
7723         else
7724             theTimeHNSecs = convert!("days", "hnsecs")(1) - 1;
7725 
7726         immutable newDaysHNSecs = convert!("days", "hnsecs")(newDays);
7727 
7728         auto retval = SysTime(this._stdTime, this._timezone);
7729         retval.adjTime = newDaysHNSecs + theTimeHNSecs;
7730 
7731         return retval;
7732     }
7733 
7734     ///
7735     @safe unittest
7736     {
7737         import core.time : msecs, usecs, hnsecs;
7738         import std.datetime.date : DateTime;
7739 
7740         assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonth ==
7741                SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7742 
7743         assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0), msecs(24)).endOfMonth ==
7744                SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7745 
7746         assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27), usecs(5203)).endOfMonth ==
7747                SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7748 
7749         assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9), hnsecs(12345)).endOfMonth ==
7750                SysTime(DateTime(2000, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7751     }
7752 
7753     @safe unittest
7754     {
7755         import core.time;
7756         // Test A.D.
7757         assert(SysTime(Date(1999, 1, 1)).endOfMonth == SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7758         assert(SysTime(Date(1999, 2, 1)).endOfMonth == SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7759         assert(SysTime(Date(2000, 2, 1)).endOfMonth == SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7760         assert(SysTime(Date(1999, 3, 1)).endOfMonth == SysTime(DateTime(1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
7761         assert(SysTime(Date(1999, 4, 1)).endOfMonth == SysTime(DateTime(1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
7762         assert(SysTime(Date(1999, 5, 1)).endOfMonth == SysTime(DateTime(1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
7763         assert(SysTime(Date(1999, 6, 1)).endOfMonth == SysTime(DateTime(1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7764         assert(SysTime(Date(1999, 7, 1)).endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7765         assert(SysTime(Date(1999, 8, 1)).endOfMonth == SysTime(DateTime(1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
7766         assert(SysTime(Date(1999, 9, 1)).endOfMonth == SysTime(DateTime(1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
7767         assert(SysTime(Date(1999, 10, 1)).endOfMonth == SysTime(DateTime(1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
7768         assert(SysTime(Date(1999, 11, 1)).endOfMonth == SysTime(DateTime(1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
7769         assert(SysTime(Date(1999, 12, 1)).endOfMonth == SysTime(DateTime(1999, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7770 
7771         // Test B.C.
7772         assert(SysTime(Date(-1999, 1, 1)).endOfMonth == SysTime(DateTime(-1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7773         assert(SysTime(Date(-1999, 2, 1)).endOfMonth == SysTime(DateTime(-1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7774         assert(SysTime(Date(-2000, 2, 1)).endOfMonth == SysTime(DateTime(-2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7775         assert(SysTime(Date(-1999, 3, 1)).endOfMonth == SysTime(DateTime(-1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
7776         assert(SysTime(Date(-1999, 4, 1)).endOfMonth == SysTime(DateTime(-1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
7777         assert(SysTime(Date(-1999, 5, 1)).endOfMonth == SysTime(DateTime(-1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
7778         assert(SysTime(Date(-1999, 6, 1)).endOfMonth == SysTime(DateTime(-1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7779         assert(SysTime(Date(-1999, 7, 1)).endOfMonth == SysTime(DateTime(-1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7780         assert(SysTime(Date(-1999, 8, 1)).endOfMonth == SysTime(DateTime(-1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
7781         assert(SysTime(Date(-1999, 9, 1)).endOfMonth == SysTime(DateTime(-1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
7782         assert(SysTime(Date(-1999, 10, 1)).endOfMonth ==
7783                SysTime(DateTime(-1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
7784         assert(SysTime(Date(-1999, 11, 1)).endOfMonth ==
7785                SysTime(DateTime(-1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
7786         assert(SysTime(Date(-1999, 12, 1)).endOfMonth ==
7787                SysTime(DateTime(-1999, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7788 
7789         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7790         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7791         assert(cst.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7792         assert(ist.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7793 
7794         static void testScope(scope ref SysTime st) @safe
7795         {
7796             auto result = st.endOfMonth;
7797         }
7798     }
7799 
7800 
7801     /++
7802         The last day in the month that this $(LREF SysTime) is in.
7803       +/
7804     @property ubyte daysInMonth() @safe const nothrow scope
7805     {
7806         return Date(dayOfGregorianCal).daysInMonth;
7807     }
7808 
7809     ///
7810     @safe unittest
7811     {
7812         import core.time;
7813         import std.datetime.date : DateTime;
7814 
7815         assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).daysInMonth == 31);
7816         assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0)).daysInMonth == 28);
7817         assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27)).daysInMonth == 29);
7818         assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9)).daysInMonth == 30);
7819     }
7820 
7821     @safe unittest
7822     {
7823         import core.time;
7824         // Test A.D.
7825         assert(SysTime(DateTime(1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
7826         assert(SysTime(DateTime(1999, 2, 1, 17, 13, 12)).daysInMonth == 28);
7827         assert(SysTime(DateTime(2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
7828         assert(SysTime(DateTime(1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
7829         assert(SysTime(DateTime(1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
7830         assert(SysTime(DateTime(1999, 5, 1, 15, 13, 12)).daysInMonth == 31);
7831         assert(SysTime(DateTime(1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
7832         assert(SysTime(DateTime(1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
7833         assert(SysTime(DateTime(1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
7834         assert(SysTime(DateTime(1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
7835         assert(SysTime(DateTime(1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
7836         assert(SysTime(DateTime(1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
7837         assert(SysTime(DateTime(1999, 12, 1, 12, 52, 13)).daysInMonth == 31);
7838 
7839         // Test B.C.
7840         assert(SysTime(DateTime(-1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
7841         assert(SysTime(DateTime(-1999, 2, 1, 7, 13, 12)).daysInMonth == 28);
7842         assert(SysTime(DateTime(-2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
7843         assert(SysTime(DateTime(-1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
7844         assert(SysTime(DateTime(-1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
7845         assert(SysTime(DateTime(-1999, 5, 1, 5, 13, 12)).daysInMonth == 31);
7846         assert(SysTime(DateTime(-1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
7847         assert(SysTime(DateTime(-1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
7848         assert(SysTime(DateTime(-1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
7849         assert(SysTime(DateTime(-1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
7850         assert(SysTime(DateTime(-1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
7851         assert(SysTime(DateTime(-1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
7852         assert(SysTime(DateTime(-1999, 12, 1, 12, 52, 13)).daysInMonth == 31);
7853 
7854         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7855         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7856         assert(cst.daysInMonth == 31);
7857         assert(ist.daysInMonth == 31);
7858 
7859         static void testScope(scope ref SysTime st) @safe
7860         {
7861             auto result = st.daysInMonth;
7862         }
7863     }
7864 
7865 
7866     /++
7867         Whether the current year is a date in A.D.
7868       +/
7869     @property bool isAD() @safe const nothrow scope
7870     {
7871         return adjTime >= 0;
7872     }
7873 
7874     ///
7875     @safe unittest
7876     {
7877         import core.time;
7878         import std.datetime.date : DateTime;
7879 
7880         assert(SysTime(DateTime(1, 1, 1, 12, 7, 0)).isAD);
7881         assert(SysTime(DateTime(2010, 12, 31, 0, 0, 0)).isAD);
7882         assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
7883         assert(!SysTime(DateTime(-2010, 1, 1, 2, 2, 2)).isAD);
7884     }
7885 
7886     @safe unittest
7887     {
7888         import core.time;
7889         assert(SysTime(DateTime(2010, 7, 4, 12, 0, 9)).isAD);
7890         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).isAD);
7891         assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
7892         assert(!SysTime(DateTime(0, 1, 1, 23, 59, 59)).isAD);
7893         assert(!SysTime(DateTime(-1, 1, 1, 23 ,59 ,59)).isAD);
7894         assert(!SysTime(DateTime(-2010, 7, 4, 12, 2, 2)).isAD);
7895 
7896         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7897         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7898         assert(cst.isAD);
7899         assert(ist.isAD);
7900 
7901         static void testScope(scope ref SysTime st) @safe
7902         {
7903             auto result = st.isAD;
7904         }
7905     }
7906 
7907 
7908     /++
7909         The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day)
7910         for this $(LREF SysTime) at the given time. For example,
7911         prior to noon, 1996-03-31 would be the Julian day number 2_450_173, so
7912         this function returns 2_450_173, while from noon onward, the Julian
7913         day number would be 2_450_174, so this function returns 2_450_174.
7914       +/
7915     @property long julianDay() @safe const nothrow scope
7916     {
7917         immutable jd = dayOfGregorianCal + 1_721_425;
7918         return hour < 12 ? jd - 1 : jd;
7919     }
7920 
7921     @safe unittest
7922     {
7923         import core.time;
7924         assert(SysTime(DateTime(-4713, 11, 24, 0, 0, 0)).julianDay == -1);
7925         assert(SysTime(DateTime(-4713, 11, 24, 12, 0, 0)).julianDay == 0);
7926 
7927         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).julianDay == 1_721_424);
7928         assert(SysTime(DateTime(0, 12, 31, 12, 0, 0)).julianDay == 1_721_425);
7929 
7930         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).julianDay == 1_721_425);
7931         assert(SysTime(DateTime(1, 1, 1, 12, 0, 0)).julianDay == 1_721_426);
7932 
7933         assert(SysTime(DateTime(1582, 10, 15, 0, 0, 0)).julianDay == 2_299_160);
7934         assert(SysTime(DateTime(1582, 10, 15, 12, 0, 0)).julianDay == 2_299_161);
7935 
7936         assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).julianDay == 2_400_000);
7937         assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).julianDay == 2_400_001);
7938 
7939         assert(SysTime(DateTime(1982, 1, 4, 0, 0, 0)).julianDay == 2_444_973);
7940         assert(SysTime(DateTime(1982, 1, 4, 12, 0, 0)).julianDay == 2_444_974);
7941 
7942         assert(SysTime(DateTime(1996, 3, 31, 0, 0, 0)).julianDay == 2_450_173);
7943         assert(SysTime(DateTime(1996, 3, 31, 12, 0, 0)).julianDay == 2_450_174);
7944 
7945         assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).julianDay == 2_455_432);
7946         assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).julianDay == 2_455_433);
7947 
7948         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7949         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7950         assert(cst.julianDay == 2_451_366);
7951         assert(ist.julianDay == 2_451_366);
7952 
7953         static void testScope(scope ref SysTime st) @safe
7954         {
7955             auto result = st.julianDay;
7956         }
7957     }
7958 
7959 
7960     /++
7961         The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for
7962         any time on this date (since, the modified Julian day changes at
7963         midnight).
7964       +/
7965     @property long modJulianDay() @safe const nothrow scope
7966     {
7967         return dayOfGregorianCal + 1_721_425 - 2_400_001;
7968     }
7969 
7970     @safe unittest
7971     {
7972         import core.time;
7973         assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).modJulianDay == 0);
7974         assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).modJulianDay == 0);
7975 
7976         assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).modJulianDay == 55_432);
7977         assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).modJulianDay == 55_432);
7978 
7979         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7980         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7981         assert(cst.modJulianDay == 51_365);
7982         assert(ist.modJulianDay == 51_365);
7983 
7984         static void testScope(scope ref SysTime st) @safe
7985         {
7986             auto result = st.modJulianDay;
7987         }
7988     }
7989 
7990 
7991     /++
7992         Returns a $(REF Date,std,datetime,date) equivalent to this $(LREF SysTime).
7993       +/
7994     Date opCast(T)() @safe const nothrow scope
7995         if (is(immutable T == immutable Date))
7996     {
7997         return Date(dayOfGregorianCal);
7998     }
7999 
8000     @safe unittest
8001     {
8002         import core.time;
8003         assert(cast(Date) SysTime(Date(1999, 7, 6)) == Date(1999, 7, 6));
8004         assert(cast(Date) SysTime(Date(2000, 12, 31)) == Date(2000, 12, 31));
8005         assert(cast(Date) SysTime(Date(2001, 1, 1)) == Date(2001, 1, 1));
8006 
8007         assert(cast(Date) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == Date(1999, 7, 6));
8008         assert(cast(Date) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == Date(2000, 12, 31));
8009         assert(cast(Date) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == Date(2001, 1, 1));
8010 
8011         assert(cast(Date) SysTime(Date(-1999, 7, 6)) == Date(-1999, 7, 6));
8012         assert(cast(Date) SysTime(Date(-2000, 12, 31)) == Date(-2000, 12, 31));
8013         assert(cast(Date) SysTime(Date(-2001, 1, 1)) == Date(-2001, 1, 1));
8014 
8015         assert(cast(Date) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == Date(-1999, 7, 6));
8016         assert(cast(Date) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == Date(-2000, 12, 31));
8017         assert(cast(Date) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == Date(-2001, 1, 1));
8018 
8019         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8020         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8021         assert(cast(Date) cst != Date.init);
8022         assert(cast(Date) ist != Date.init);
8023 
8024         static void testScope(scope ref SysTime st) @safe
8025         {
8026             auto result = cast(Date) st;
8027         }
8028     }
8029 
8030 
8031     /++
8032         Returns a $(REF DateTime,std,datetime,date) equivalent to this
8033         $(LREF SysTime).
8034       +/
8035     DateTime opCast(T)() @safe const nothrow scope
8036         if (is(immutable T == immutable DateTime))
8037     {
8038         try
8039         {
8040             auto hnsecs = adjTime;
8041             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8042 
8043             if (hnsecs < 0)
8044             {
8045                 hnsecs += convert!("hours", "hnsecs")(24);
8046                 --days;
8047             }
8048 
8049             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8050             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8051             immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
8052 
8053             return DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour, cast(int) minute, cast(int) second));
8054         }
8055         catch (Exception e)
8056             assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw.");
8057     }
8058 
8059     @safe unittest
8060     {
8061         import core.time;
8062         assert(cast(DateTime) SysTime(DateTime(1, 1, 6, 7, 12, 22)) == DateTime(1, 1, 6, 7, 12, 22));
8063         assert(cast(DateTime) SysTime(DateTime(1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(1, 1, 6, 7, 12, 22));
8064         assert(cast(DateTime) SysTime(Date(1999, 7, 6)) == DateTime(1999, 7, 6, 0, 0, 0));
8065         assert(cast(DateTime) SysTime(Date(2000, 12, 31)) == DateTime(2000, 12, 31, 0, 0, 0));
8066         assert(cast(DateTime) SysTime(Date(2001, 1, 1)) == DateTime(2001, 1, 1, 0, 0, 0));
8067 
8068         assert(cast(DateTime) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == DateTime(1999, 7, 6, 12, 10, 9));
8069         assert(cast(DateTime) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == DateTime(2000, 12, 31, 13, 11, 10));
8070         assert(cast(DateTime) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == DateTime(2001, 1, 1, 14, 12, 11));
8071 
8072         assert(cast(DateTime) SysTime(DateTime(-1, 1, 6, 7, 12, 22)) == DateTime(-1, 1, 6, 7, 12, 22));
8073         assert(cast(DateTime) SysTime(DateTime(-1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(-1, 1, 6, 7, 12, 22));
8074         assert(cast(DateTime) SysTime(Date(-1999, 7, 6)) == DateTime(-1999, 7, 6, 0, 0, 0));
8075         assert(cast(DateTime) SysTime(Date(-2000, 12, 31)) == DateTime(-2000, 12, 31, 0, 0, 0));
8076         assert(cast(DateTime) SysTime(Date(-2001, 1, 1)) == DateTime(-2001, 1, 1, 0, 0, 0));
8077 
8078         assert(cast(DateTime) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == DateTime(-1999, 7, 6, 12, 10, 9));
8079         assert(cast(DateTime) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == DateTime(-2000, 12, 31, 13, 11, 10));
8080         assert(cast(DateTime) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == DateTime(-2001, 1, 1, 14, 12, 11));
8081 
8082         assert(cast(DateTime) SysTime(DateTime(2011, 1, 13, 8, 17, 2), msecs(296), LocalTime()) ==
8083                DateTime(2011, 1, 13, 8, 17, 2));
8084 
8085         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8086         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8087         assert(cast(DateTime) cst != DateTime.init);
8088         assert(cast(DateTime) ist != DateTime.init);
8089 
8090         static void testScope(scope ref SysTime st) @safe
8091         {
8092             auto result = cast(DateTime) st;
8093         }
8094     }
8095 
8096 
8097     /++
8098         Returns a $(REF TimeOfDay,std,datetime,date) equivalent to this
8099         $(LREF SysTime).
8100       +/
8101     TimeOfDay opCast(T)() @safe const nothrow scope
8102         if (is(immutable T == immutable TimeOfDay))
8103     {
8104         try
8105         {
8106             auto hnsecs = adjTime;
8107             hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
8108 
8109             if (hnsecs < 0)
8110                 hnsecs += convert!("hours", "hnsecs")(24);
8111 
8112             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8113             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8114             immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
8115 
8116             return TimeOfDay(cast(int) hour, cast(int) minute, cast(int) second);
8117         }
8118         catch (Exception e)
8119             assert(0, "TimeOfDay's constructor threw.");
8120     }
8121 
8122     @safe unittest
8123     {
8124         import core.time;
8125         assert(cast(TimeOfDay) SysTime(Date(1999, 7, 6)) == TimeOfDay(0, 0, 0));
8126         assert(cast(TimeOfDay) SysTime(Date(2000, 12, 31)) == TimeOfDay(0, 0, 0));
8127         assert(cast(TimeOfDay) SysTime(Date(2001, 1, 1)) == TimeOfDay(0, 0, 0));
8128 
8129         assert(cast(TimeOfDay) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
8130         assert(cast(TimeOfDay) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
8131         assert(cast(TimeOfDay) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11));
8132 
8133         assert(cast(TimeOfDay) SysTime(Date(-1999, 7, 6)) == TimeOfDay(0, 0, 0));
8134         assert(cast(TimeOfDay) SysTime(Date(-2000, 12, 31)) == TimeOfDay(0, 0, 0));
8135         assert(cast(TimeOfDay) SysTime(Date(-2001, 1, 1)) == TimeOfDay(0, 0, 0));
8136 
8137         assert(cast(TimeOfDay) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
8138         assert(cast(TimeOfDay) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
8139         assert(cast(TimeOfDay) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11));
8140 
8141         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8142         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8143         assert(cast(TimeOfDay) cst != TimeOfDay.init);
8144         assert(cast(TimeOfDay) ist != TimeOfDay.init);
8145 
8146         static void testScope(scope ref SysTime st) @safe
8147         {
8148             auto result = cast(TimeOfDay) st;
8149         }
8150     }
8151 
8152 
8153     // Temporary hack until bug https://issues.dlang.org/show_bug.cgi?id=4867 is fixed.
8154     // This allows assignment from const(SysTime) to SysTime.
8155     // It may be a good idea to keep it though, since casting from a type to itself
8156     // should be allowed, and it doesn't work without this opCast() since opCast()
8157     // has already been defined for other types.
8158     SysTime opCast(T)() @safe const pure nothrow scope
8159         if (is(immutable T == immutable SysTime))
8160     {
8161         return SysTime(_stdTime, _timezone);
8162     }
8163 
8164     @safe unittest
8165     {
8166         static void testScope(scope ref SysTime st) @safe
8167         {
8168             auto result = cast(SysTime) st;
8169         }
8170     }
8171 
8172 
8173     /++
8174         Converts this $(LREF SysTime) to a string with the format
8175         YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds and TZ is time
8176         zone).
8177 
8178         Note that the number of digits in the fractional seconds varies with the
8179         number of fractional seconds. It's a maximum of 7 (which would be
8180         hnsecs), but only has as many as are necessary to hold the correct value
8181         (so no trailing zeroes), and if there are no fractional seconds, then
8182         there is no decimal point.
8183 
8184         If this $(LREF SysTime)'s time zone is
8185         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
8186         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
8187         (e.g. +0100 or -0700). Note that the offset from UTC is $(I not) enough
8188         to uniquely identify the time zone.
8189 
8190         Time zone offsets will be in the form +HHMM or -HHMM.
8191 
8192         $(RED Warning:
8193             Previously, toISOString did the same as $(LREF toISOExtString) and
8194             generated +HH:MM or -HH:MM for the time zone when it was not
8195             $(REF LocalTime,std,datetime,timezone) or
8196             $(REF UTC,std,datetime,timezone), which is not in conformance with
8197             ISO 8601 for the non-extended string format. This has now been
8198             fixed. However, for now, fromISOString will continue to accept the
8199             extended format for the time zone so that any code which has been
8200             writing out the result of toISOString to read in later will continue
8201             to work. The current behavior will be kept until July 2019 at which
8202             point, fromISOString will be fixed to be standards compliant.)
8203 
8204         Params:
8205             writer = A `char` accepting
8206             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8207         Returns:
8208             A `string` when not using an output range; `void` otherwise.
8209       +/
8210     string toISOString() @safe const nothrow scope
8211     {
8212         import std.array : appender;
8213         auto app = appender!string();
8214         app.reserve(30);
8215         try
8216             toISOString(app);
8217         catch (Exception e)
8218             assert(0, "toISOString() threw.");
8219         return app.data;
8220     }
8221 
8222     /// ditto
8223     void toISOString(W)(ref W writer) const scope
8224     if (isOutputRange!(W, char))
8225     {
8226         immutable adjustedTime = adjTime;
8227         long hnsecs = adjustedTime;
8228 
8229         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8230 
8231         if (hnsecs < 0)
8232         {
8233             hnsecs += convert!("hours", "hnsecs")(24);
8234             --days;
8235         }
8236 
8237         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8238         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8239         immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
8240 
8241         auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
8242                                       cast(int) minute, cast(int) second));
8243 
8244         if (_timezone is LocalTime())
8245         {
8246             dateTime.toISOString(writer);
8247             fracSecsToISOString(writer, cast(int) hnsecs);
8248             return;
8249         }
8250 
8251         if (_timezone is UTC())
8252         {
8253             dateTime.toISOString(writer);
8254             fracSecsToISOString(writer, cast(int) hnsecs);
8255             put(writer, 'Z');
8256             return;
8257         }
8258 
8259         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
8260 
8261         dateTime.toISOString(writer);
8262         fracSecsToISOString(writer, cast(int) hnsecs);
8263         SimpleTimeZone.toISOExtString(writer, utcOffset);
8264     }
8265 
8266     ///
8267     @safe unittest
8268     {
8269         import core.time : msecs, hnsecs;
8270         import std.datetime.date : DateTime;
8271 
8272         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOString() ==
8273                "20100704T070612");
8274 
8275         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOString() ==
8276                "19981225T021500.024");
8277 
8278         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOString() ==
8279                "00000105T230959");
8280 
8281         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOString() ==
8282                "-00040105T000002.052092");
8283     }
8284 
8285     @safe unittest
8286     {
8287         import core.time;
8288         // Test A.D.
8289         assert(SysTime(DateTime.init, UTC()).toISOString() == "00010101T000000Z");
8290         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOString() == "00010101T000000.0000001Z");
8291 
8292         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOString() == "00091204T000000");
8293         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOString() == "00991204T050612");
8294         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOString() == "09991204T134459");
8295         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOString() == "99990704T235959");
8296         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOString() == "+100001020T010101");
8297 
8298         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "00091204T000000.042");
8299         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "00991204T050612.1");
8300         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "09991204T134459.04502");
8301         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "99990704T235959.0000012");
8302         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "+100001020T010101.050789");
8303 
8304         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8305                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOString() ==
8306                "20121221T121212-06:00");
8307 
8308         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8309                        new immutable SimpleTimeZone(dur!"minutes"(420))).toISOString() ==
8310                "20121221T121212+07:00");
8311 
8312         // Test B.C.
8313         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOString() ==
8314                "00001231T235959.9999999Z");
8315         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOString() == "00001231T235959.0000001Z");
8316         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOString() == "00001231T235959Z");
8317 
8318         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOString() == "00001204T001204");
8319         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOString() == "-00091204T000000");
8320         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOString() == "-00991204T050612");
8321         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOString() == "-09991204T134459");
8322         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOString() == "-99990704T235959");
8323         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOString() == "-100001020T010101");
8324 
8325         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOString() == "00001204T000000.007");
8326         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "-00091204T000000.042");
8327         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "-00991204T050612.1");
8328         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "-09991204T134459.04502");
8329         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "-99990704T235959.0000012");
8330         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "-100001020T010101.050789");
8331 
8332         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8333         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8334         assert(cst.toISOString() == "19990706T123033");
8335         assert(ist.toISOString() == "19990706T123033");
8336 
8337         static void testScope(scope ref SysTime st) @safe
8338         {
8339             auto result = st.toISOString();
8340         }
8341     }
8342 
8343 
8344 
8345     /++
8346         Converts this $(LREF SysTime) to a string with the format
8347         YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
8348         is the time zone).
8349 
8350         Default behaviour:
8351         Note that the number of digits in the fractional seconds varies with the
8352         number of fractional seconds. It's a maximum of 7 (which would be
8353         hnsecs), but only has as many as are necessary to hold the correct value
8354         (so no trailing zeroes), and if there are no fractional seconds, then
8355         there is no decimal point.
8356 
8357         The optional parameter "prec" allows to change the default behavior by
8358         specifying the precision of the fractional seconds. The accepted values
8359         are in the range [-1, 7], where -1 represents the default behavior.
8360 
8361         If this $(LREF SysTime)'s time zone is
8362         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
8363         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
8364         (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not)
8365         enough to uniquely identify the time zone.
8366 
8367         Time zone offsets will be in the form +HH:MM or -HH:MM.
8368 
8369         Params:
8370             writer = A `char` accepting
8371             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8372             prec = An `int` representing the desired precision. Acceptable values range from -1 to 7, where -1 represents the default behavior.
8373         Returns:
8374             A `string` when not using an output range; `void` otherwise.
8375       +/
8376     string toISOExtString(int prec = -1) @safe const nothrow scope
8377     {
8378         assert(prec >= -1 && prec <= 7, "Precision must be in the range [-1, 7]");
8379 
8380         import std.array : appender;
8381         auto app = appender!string();
8382         app.reserve(35);
8383         try
8384             toISOExtString(app, prec);
8385         catch (Exception e)
8386             assert(0, "toISOExtString() threw.");
8387         return app.data;
8388     }
8389 
8390     /// ditto
8391     void toISOExtString(W)(ref W writer, int prec = -1) const scope
8392     if (isOutputRange!(W, char))
8393     {
8394         assert(prec >= -1 && prec <= 7, "Precision must be in the range [-1, 7]");
8395 
8396         immutable adjustedTime = adjTime;
8397         long hnsecs = adjustedTime;
8398 
8399         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8400 
8401         if (hnsecs < 0)
8402         {
8403             hnsecs += convert!("hours", "hnsecs")(24);
8404             --days;
8405         }
8406 
8407         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8408         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8409         immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
8410 
8411         immutable dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
8412                                       cast(int) minute, cast(int) second));
8413 
8414         if (_timezone is LocalTime())
8415         {
8416             dateTime.toISOExtString(writer);
8417             fracSecsToISOString(writer, cast(int) hnsecs, prec);
8418             return;
8419         }
8420 
8421         if (_timezone is UTC())
8422         {
8423             dateTime.toISOExtString(writer);
8424             fracSecsToISOString(writer, cast(int) hnsecs, prec);
8425             put(writer, 'Z');
8426             return;
8427         }
8428 
8429         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
8430 
8431         dateTime.toISOExtString(writer);
8432         fracSecsToISOString(writer, cast(int) hnsecs, prec);
8433         SimpleTimeZone.toISOExtString(writer, utcOffset);
8434     }
8435 
8436     ///
8437     @safe unittest
8438     {
8439         import core.time : msecs, hnsecs;
8440         import std.datetime.date : DateTime;
8441 
8442         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOExtString() ==
8443                "2010-07-04T07:06:12");
8444 
8445         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOExtString() ==
8446                "1998-12-25T02:15:00.024");
8447 
8448         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOExtString() ==
8449                "0000-01-05T23:09:59");
8450 
8451         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString() ==
8452                "-0004-01-05T00:00:02.052092");
8453 
8454         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(4) ==
8455                "-0004-01-05T00:00:02.0520");
8456 
8457         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(2) ==
8458                "-0004-01-05T00:00:02.05");
8459 
8460         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(7) ==
8461                "-0004-01-05T00:00:02.0520920");
8462     }
8463 
8464     @safe unittest
8465     {
8466         import core.time;
8467         // Test A.D.
8468         assert(SysTime(DateTime.init, UTC()).toISOExtString() == "0001-01-01T00:00:00Z");
8469         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOExtString() ==
8470                "0001-01-01T00:00:00.0000001Z");
8471 
8472         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00");
8473         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12");
8474         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59");
8475         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59");
8476         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01");
8477 
8478         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "0009-12-04T00:00:00.042");
8479         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "0099-12-04T05:06:12.1");
8480         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() == "0999-12-04T13:44:59.04502");
8481         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() == "9999-07-04T23:59:59.0000012");
8482         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
8483                "+10000-10-20T01:01:01.050789");
8484 
8485         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8486                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOExtString() ==
8487                "2012-12-21T12:12:12-06:00");
8488 
8489         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8490                        new immutable SimpleTimeZone(dur!"minutes"(420))).toISOExtString() ==
8491                "2012-12-21T12:12:12+07:00");
8492 
8493         // Test B.C.
8494         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOExtString() ==
8495                "0000-12-31T23:59:59.9999999Z");
8496         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOExtString() ==
8497                "0000-12-31T23:59:59.0000001Z");
8498         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOExtString() == "0000-12-31T23:59:59Z");
8499 
8500         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04");
8501         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00");
8502         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12");
8503         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59");
8504         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59");
8505         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01");
8506 
8507         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOExtString() == "0000-12-04T00:00:00.007");
8508         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "-0009-12-04T00:00:00.042");
8509         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "-0099-12-04T05:06:12.1");
8510         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() ==
8511                "-0999-12-04T13:44:59.04502");
8512         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() ==
8513                "-9999-07-04T23:59:59.0000012");
8514         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
8515                "-10000-10-20T01:01:01.050789");
8516 
8517         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8518         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8519         assert(cst.toISOExtString() == "1999-07-06T12:30:33");
8520         assert(ist.toISOExtString() == "1999-07-06T12:30:33");
8521 
8522         static void testScope(scope ref SysTime st) @safe
8523         {
8524             auto result = st.toISOExtString();
8525         }
8526     }
8527 
8528     /++
8529         Converts this $(LREF SysTime) to a string with the format
8530         YYYY-Mon-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
8531         is the time zone).
8532 
8533         Note that the number of digits in the fractional seconds varies with the
8534         number of fractional seconds. It's a maximum of 7 (which would be
8535         hnsecs), but only has as many as are necessary to hold the correct value
8536         (so no trailing zeroes), and if there are no fractional seconds, then
8537         there is no decimal point.
8538 
8539         If this $(LREF SysTime)'s time zone is
8540         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
8541         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
8542         (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not)
8543         enough to uniquely identify the time zone.
8544 
8545         Time zone offsets will be in the form +HH:MM or -HH:MM.
8546 
8547         Params:
8548             writer = A `char` accepting
8549             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8550         Returns:
8551             A `string` when not using an output range; `void` otherwise.
8552       +/
8553     string toSimpleString() @safe const nothrow scope
8554     {
8555         import std.array : appender;
8556         auto app = appender!string();
8557         app.reserve(35);
8558         try
8559             toSimpleString(app);
8560         catch (Exception e)
8561             assert(0, "toSimpleString() threw.");
8562         return app.data;
8563     }
8564 
8565     /// ditto
8566     void toSimpleString(W)(ref W writer) const scope
8567     if (isOutputRange!(W, char))
8568     {
8569         immutable adjustedTime = adjTime;
8570         long hnsecs = adjustedTime;
8571 
8572         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8573 
8574         if (hnsecs < 0)
8575         {
8576             hnsecs += convert!("hours", "hnsecs")(24);
8577             --days;
8578         }
8579 
8580         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8581         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8582         immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
8583 
8584         immutable dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
8585                                       cast(int) minute, cast(int) second));
8586 
8587         if (_timezone is LocalTime())
8588         {
8589             dateTime.toSimpleString(writer);
8590             fracSecsToISOString(writer, cast(int) hnsecs);
8591             return;
8592         }
8593 
8594         if (_timezone is UTC())
8595         {
8596             dateTime.toSimpleString(writer);
8597             fracSecsToISOString(writer, cast(int) hnsecs);
8598             put(writer, 'Z');
8599             return;
8600         }
8601 
8602         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
8603 
8604         dateTime.toSimpleString(writer);
8605         fracSecsToISOString(writer, cast(int) hnsecs);
8606         SimpleTimeZone.toISOExtString(writer, utcOffset);
8607     }
8608 
8609     ///
8610     @safe unittest
8611     {
8612         import core.time : msecs, hnsecs;
8613         import std.datetime.date : DateTime;
8614 
8615         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toSimpleString() ==
8616                "2010-Jul-04 07:06:12");
8617 
8618         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toSimpleString() ==
8619                "1998-Dec-25 02:15:00.024");
8620 
8621         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toSimpleString() ==
8622                "0000-Jan-05 23:09:59");
8623 
8624         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toSimpleString() ==
8625                 "-0004-Jan-05 00:00:02.052092");
8626     }
8627 
8628     @safe unittest
8629     {
8630         import core.time;
8631         // Test A.D.
8632         assert(SysTime(DateTime.init, UTC()).toString() == "0001-Jan-01 00:00:00Z");
8633         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toString() == "0001-Jan-01 00:00:00.0000001Z");
8634 
8635         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00");
8636         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12");
8637         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59");
8638         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59");
8639         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01");
8640 
8641         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "0009-Dec-04 00:00:00.042");
8642         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "0099-Dec-04 05:06:12.1");
8643         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
8644                "0999-Dec-04 13:44:59.04502");
8645         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
8646                "9999-Jul-04 23:59:59.0000012");
8647         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() ==
8648                "+10000-Oct-20 01:01:01.050789");
8649 
8650         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8651                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toSimpleString() ==
8652                "2012-Dec-21 12:12:12-06:00");
8653 
8654         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8655                        new immutable SimpleTimeZone(dur!"minutes"(420))).toSimpleString() ==
8656                "2012-Dec-21 12:12:12+07:00");
8657 
8658         // Test B.C.
8659         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toSimpleString() ==
8660                "0000-Dec-31 23:59:59.9999999Z");
8661         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toSimpleString() ==
8662                "0000-Dec-31 23:59:59.0000001Z");
8663         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toSimpleString() == "0000-Dec-31 23:59:59Z");
8664 
8665         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04");
8666         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00");
8667         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12");
8668         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59");
8669         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59");
8670         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01");
8671 
8672         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toSimpleString() == "0000-Dec-04 00:00:00.007");
8673         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "-0009-Dec-04 00:00:00.042");
8674         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "-0099-Dec-04 05:06:12.1");
8675         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
8676                "-0999-Dec-04 13:44:59.04502");
8677         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
8678                "-9999-Jul-04 23:59:59.0000012");
8679         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() ==
8680                "-10000-Oct-20 01:01:01.050789");
8681 
8682         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8683         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8684         assert(cst.toSimpleString() == "1999-Jul-06 12:30:33");
8685         assert(ist.toSimpleString() == "1999-Jul-06 12:30:33");
8686 
8687         static void testScope(scope ref SysTime st) @safe
8688         {
8689             auto result = st.toSimpleString();
8690         }
8691     }
8692 
8693 
8694     /++
8695         Converts this $(LREF SysTime) to a string.
8696 
8697         This function exists to make it easy to convert a $(LREF SysTime) to a
8698         string for code that does not care what the exact format is - just that
8699         it presents the information in a clear manner. It also makes it easy to
8700         simply convert a $(LREF SysTime) to a string when using functions such
8701         as `to!string`, `format`, or `writeln` which use toString to convert
8702         user-defined types. So, it is unlikely that much code will call
8703         toString directly.
8704 
8705         The format of the string is purposefully unspecified, and code that
8706         cares about the format of the string should use `toISOString`,
8707         `toISOExtString`, `toSimpleString`, or some other custom formatting
8708         function that explicitly generates the format that the code needs. The
8709         reason is that the code is then clear about what format it's using,
8710         making it less error-prone to maintain the code and interact with other
8711         software that consumes the generated strings. It's for this same reason
8712         that $(LREF SysTime) has no `fromString` function, whereas it does have
8713         `fromISOString`, `fromISOExtString`, and `fromSimpleString`.
8714 
8715         The format returned by toString may or may not change in the future.
8716 
8717         Params:
8718             writer = A `char` accepting
8719             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8720         Returns:
8721             A `string` when not using an output range; `void` otherwise.
8722       +/
8723     string toString() @safe const nothrow scope
8724     {
8725         return toSimpleString();
8726     }
8727 
8728     /// ditto
8729     void toString(W)(ref W writer) const scope
8730     if (isOutputRange!(W, char))
8731     {
8732         toSimpleString(writer);
8733     }
8734 
8735     @safe unittest
8736     {
8737         import core.time;
8738         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8739         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8740         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8741         static assert(__traits(compiles, st.toString()));
8742         static assert(__traits(compiles, cst.toString()));
8743         static assert(__traits(compiles, ist.toString()));
8744 
8745         static void testScope(scope ref SysTime st) @safe
8746         {
8747             auto result = st.toString();
8748         }
8749     }
8750 
8751 
8752     /++
8753         Creates a $(LREF SysTime) from a string with the format
8754         YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds and TZ
8755         is the time zone). Whitespace is stripped from the given string.
8756 
8757         The exact format is exactly as described in $(LREF toISOString) except
8758         that trailing zeroes are permitted - including having fractional seconds
8759         with all zeroes. The time zone and fractional seconds are optional,
8760         however, a decimal point with nothing following it is invalid.
8761         Also, while $(LREF toISOString) will never generate a string
8762         with more than 7 digits in the fractional seconds (because that's the
8763         limit with hecto-nanosecond precision), it will allow more than 7 digits
8764         in order to read strings from other sources that have higher precision
8765         (however, any digits beyond 7 will be truncated).
8766 
8767         If there is no time zone in the string, then
8768         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
8769         then `UTC` is used. Otherwise, a
8770         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
8771         given offset from UTC is used. To get the returned $(LREF SysTime) to be
8772         a particular time zone, pass in that time zone and the $(LREF SysTime)
8773         to be returned will be converted to that time zone (though it will still
8774         be read in as whatever time zone is in its string).
8775 
8776         The accepted formats for time zone offsets are +HH, -HH, +HHMM, and
8777         -HHMM.
8778 
8779         $(RED Warning:
8780             Previously, $(LREF toISOString) did the same as
8781             $(LREF toISOExtString) and generated +HH:MM or -HH:MM for the time
8782             zone when it was not $(REF LocalTime,std,datetime,timezone) or
8783             $(REF UTC,std,datetime,timezone), which is not in conformance with
8784             ISO 8601 for the non-extended string format. This has now been
8785             fixed. However, for now, fromISOString will continue to accept the
8786             extended format for the time zone so that any code which has been
8787             writing out the result of toISOString to read in later will continue
8788             to work. The current behavior will be kept until July 2019 at which
8789             point, fromISOString will be fixed to be standards compliant.)
8790 
8791         Params:
8792             isoString = A string formatted in the ISO format for dates and times.
8793             tz        = The time zone to convert the given time to (no
8794                         conversion occurs if null).
8795 
8796         Throws:
8797             $(REF DateTimeException,std,datetime,date) if the given string is
8798             not in the ISO format or if the resulting $(LREF SysTime) would not
8799             be valid.
8800       +/
8801     static SysTime fromISOString(S)(scope const S isoString, immutable TimeZone tz = null) @safe
8802         if (isSomeString!S)
8803     {
8804         import std.algorithm.searching : startsWith, find;
8805         import std.conv : to;
8806         import std.string : strip;
8807         import std.utf : byCodeUnit;
8808 
8809         auto str = strip(isoString);
8810         immutable skipFirst = str.startsWith('+', '-');
8811 
8812         auto found = (skipFirst ? str[1..$] : str).byCodeUnit.find('.', 'Z', '+', '-');
8813         auto dateTimeStr = str[0 .. $ - found[0].length];
8814 
8815         typeof(str.byCodeUnit) foundTZ; // needs to have longer lifetime than zoneStr
8816         typeof(str) fracSecStr;
8817         typeof(str) zoneStr;
8818 
8819         if (found[1] != 0)
8820         {
8821             if (found[1] == 1)
8822             {
8823                 foundTZ = found[0].find('Z', '+', '-')[0];
8824 
8825                 if (foundTZ.length != 0)
8826                 {
8827                     static if (isNarrowString!S)
8828                     {
8829                         fracSecStr = found[0][0 .. $ - foundTZ.length].source;
8830                         zoneStr = foundTZ.source;
8831                     }
8832                     else
8833                     {
8834                         fracSecStr = found[0][0 .. $ - foundTZ.length];
8835                         zoneStr = foundTZ;
8836                     }
8837                 }
8838                 else
8839                 {
8840                     static if (isNarrowString!S)
8841                         fracSecStr = found[0].source;
8842                     else
8843                         fracSecStr = found[0];
8844                 }
8845             }
8846             else
8847             {
8848                 static if (isNarrowString!S)
8849                     zoneStr = found[0].source;
8850                 else
8851                     zoneStr = found[0];
8852             }
8853         }
8854 
8855         try
8856         {
8857             auto dateTime = DateTime.fromISOString(dateTimeStr);
8858             auto fracSec = fracSecsFromISOString(fracSecStr);
8859 
8860             Rebindable!(immutable TimeZone) parsedZone;
8861 
8862             if (zoneStr.empty)
8863                 parsedZone = LocalTime();
8864             else if (zoneStr == "Z")
8865                 parsedZone = UTC();
8866             else
8867             {
8868                 try
8869                     parsedZone = SimpleTimeZone.fromISOString(zoneStr);
8870                 catch (DateTimeException dte)
8871                     parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
8872             }
8873 
8874             auto retval = SysTime(dateTime, fracSec, parsedZone);
8875 
8876             if (tz !is null)
8877                 retval.timezone = tz;
8878 
8879             return retval;
8880         }
8881         catch (DateTimeException dte)
8882             throw new DateTimeException(format("Invalid ISO String: %s", isoString));
8883     }
8884 
8885     ///
8886     @safe unittest
8887     {
8888         import core.time : hours, msecs, usecs, hnsecs;
8889         import std.datetime.date : DateTime;
8890         import std.datetime.timezone : SimpleTimeZone, UTC;
8891 
8892         assert(SysTime.fromISOString("20100704T070612") ==
8893                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8894 
8895         assert(SysTime.fromISOString("19981225T021500.007") ==
8896                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
8897 
8898         assert(SysTime.fromISOString("00000105T230959.00002") ==
8899                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
8900 
8901         assert(SysTime.fromISOString("20130207T043937.000050392") ==
8902                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
8903 
8904         assert(SysTime.fromISOString("-00040105T000002") ==
8905                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
8906 
8907         assert(SysTime.fromISOString(" 20100704T070612 ") ==
8908                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8909 
8910         assert(SysTime.fromISOString("20100704T070612Z") ==
8911                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
8912 
8913         assert(SysTime.fromISOString("20100704T070612-0800") ==
8914                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8915                        new immutable SimpleTimeZone(hours(-8))));
8916 
8917         assert(SysTime.fromISOString("20100704T070612+0800") ==
8918                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8919                        new immutable SimpleTimeZone(hours(8))));
8920     }
8921 
8922     @safe unittest
8923     {
8924         import core.time;
8925         foreach (str; ["", "20100704000000", "20100704 000000", "20100704t000000",
8926                        "20100704T000000.", "20100704T000000.A", "20100704T000000.Z",
8927                        "20100704T000000.0000000A", "20100704T000000.00000000A",
8928                        "20100704T000000+", "20100704T000000-", "20100704T000000:",
8929                        "20100704T000000-:", "20100704T000000+:", "20100704T000000-1:",
8930                        "20100704T000000+1:", "20100704T000000+1:0",
8931                        "20100704T000000-12.00", "20100704T000000+12.00",
8932                        "20100704T000000-8", "20100704T000000+8",
8933                        "20100704T000000-800", "20100704T000000+800",
8934                        "20100704T000000-080", "20100704T000000+080",
8935                        "20100704T000000-2400", "20100704T000000+2400",
8936                        "20100704T000000-1260", "20100704T000000+1260",
8937                        "20100704T000000.0-8", "20100704T000000.0+8",
8938                        "20100704T000000.0-800", "20100704T000000.0+800",
8939                        "20100704T000000.0-080", "20100704T000000.0+080",
8940                        "20100704T000000.0-2400", "20100704T000000.0+2400",
8941                        "20100704T000000.0-1260", "20100704T000000.0+1260",
8942                        "20100704T000000-8:00", "20100704T000000+8:00",
8943                        "20100704T000000-08:0", "20100704T000000+08:0",
8944                        "20100704T000000-24:00", "20100704T000000+24:00",
8945                        "20100704T000000-12:60", "20100704T000000+12:60",
8946                        "20100704T000000.0-8:00", "20100704T000000.0+8:00",
8947                        "20100704T000000.0-08:0", "20100704T000000.0+08:0",
8948                        "20100704T000000.0-24:00", "20100704T000000.0+24:00",
8949                        "20100704T000000.0-12:60", "20100704T000000.0+12:60",
8950                        "2010-07-0400:00:00", "2010-07-04 00:00:00",
8951                        "2010-07-04t00:00:00", "2010-07-04T00:00:00.",
8952                        "2010-Jul-0400:00:00", "2010-Jul-04 00:00:00", "2010-Jul-04t00:00:00",
8953                        "2010-Jul-04T00:00:00", "2010-Jul-04 00:00:00.",
8954                        "2010-12-22T172201", "2010-Dec-22 17:22:01"])
8955         {
8956             assertThrown!DateTimeException(SysTime.fromISOString(str), format("[%s]", str));
8957         }
8958 
8959         static void test(string str, SysTime st, size_t line = __LINE__)
8960         {
8961             if (SysTime.fromISOString(str) != st)
8962                 throw new AssertError("unittest failure", __FILE__, line);
8963         }
8964 
8965         test("20101222T172201", SysTime(DateTime(2010, 12, 22, 17, 22, 1)));
8966         test("19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8967         test("-19990706T123033", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
8968         test("+019990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8969         test("19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8970         test(" 19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8971         test(" 19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8972 
8973         test("19070707T121212.0", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
8974         test("19070707T121212.0000000", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
8975         test("19070707T121212.0000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), hnsecs(1)));
8976         test("20100704T000000.00000000", SysTime(Date(2010, 7, 4)));
8977         test("20100704T000000.00000009", SysTime(Date(2010, 7, 4)));
8978         test("20100704T000000.00000019", SysTime(DateTime(2010, 7, 4), hnsecs(1)));
8979         test("19070707T121212.000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
8980         test("19070707T121212.0000010", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
8981         test("19070707T121212.001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
8982         test("19070707T121212.0010000", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
8983 
8984         auto west60 = new immutable SimpleTimeZone(hours(-1));
8985         auto west90 = new immutable SimpleTimeZone(minutes(-90));
8986         auto west480 = new immutable SimpleTimeZone(hours(-8));
8987         auto east60 = new immutable SimpleTimeZone(hours(1));
8988         auto east90 = new immutable SimpleTimeZone(minutes(90));
8989         auto east480 = new immutable SimpleTimeZone(hours(8));
8990 
8991         test("20101222T172201Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), UTC()));
8992         test("20101222T172201-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
8993         test("20101222T172201-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
8994         test("20101222T172201-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
8995         test("20101222T172201-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
8996         test("20101222T172201+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
8997         test("20101222T172201+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
8998         test("20101222T172201+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
8999         test("20101222T172201+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
9000 
9001         test("20101103T065106.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
9002         test("20101222T172201.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_341_200), UTC()));
9003         test("20101222T172201.23112-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9004         test("20101222T172201.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), west60));
9005         test("20101222T172201.1-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
9006         test("20101222T172201.55-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
9007         test("20101222T172201.1234567+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
9008         test("20101222T172201.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9009         test("20101222T172201.0000000+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9010         test("20101222T172201.45+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
9011 
9012         // for dstring coverage
9013         assert(SysTime.fromISOString("20101222T172201.23112-0100"d) == SysTime(
9014             DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9015         assert(SysTime.fromISOString("19070707T121212.0010000"d) == SysTime(
9016             DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9017 
9018         // @@@DEPRECATED_2019-07@@@
9019         // This isn't deprecated per se, but that text will make it so that it
9020         // pops up when deprecations are moved along around July 2019. At that
9021         // time, we will update fromISOString so that it is conformant with ISO
9022         // 8601, and it will no longer accept ISO extended time zones (it does
9023         // currently because of https://issues.dlang.org/show_bug.cgi?id=15654
9024         // toISOString used to incorrectly use the ISO extended time zone format).
9025         // These tests will then start failing will need to be updated accordingly.
9026         // Also, the notes about this issue in toISOString and fromISOString's
9027         // documentation will need to be removed.
9028         test("20101222T172201-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9029         test("20101222T172201-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
9030         test("20101222T172201-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
9031         test("20101222T172201+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9032         test("20101222T172201+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9033         test("20101222T172201+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
9034 
9035         test("20101222T172201.23112-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9036         test("20101222T172201.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
9037         test("20101222T172201.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
9038         test("20101222T172201.1234567+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
9039         test("20101222T172201.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9040         test("20101222T172201.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
9041 
9042         static void testScope(scope ref string str) @safe
9043         {
9044             auto result = SysTime.fromISOString(str);
9045         }
9046     }
9047 
9048     // https://issues.dlang.org/show_bug.cgi?id=17801
9049     @safe unittest
9050     {
9051         import std.conv : to;
9052         import std.meta : AliasSeq;
9053         static foreach (C; AliasSeq!(char, wchar, dchar))
9054         {
9055             static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
9056             {
9057                 assert(SysTime.fromISOString(to!S("20121221T141516Z")) ==
9058                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
9059             }
9060         }
9061     }
9062 
9063 
9064     /++
9065         Creates a $(LREF SysTime) from a string with the format
9066         YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
9067         is the time zone). Whitespace is stripped from the given string.
9068 
9069         The exact format is exactly as described in $(LREF toISOExtString)
9070         except that trailing zeroes are permitted - including having fractional
9071         seconds with all zeroes. The time zone and fractional seconds are
9072         optional, however, a decimal point with nothing following it is invalid.
9073         Also, while $(LREF toISOExtString) will never generate a
9074         string with more than 7 digits in the fractional seconds (because that's
9075         the limit with hecto-nanosecond precision), it will allow more than 7
9076         digits in order to read strings from other sources that have higher
9077         precision (however, any digits beyond 7 will be truncated).
9078 
9079         If there is no time zone in the string, then
9080         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
9081         then `UTC` is used. Otherwise, a
9082         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
9083         given offset from UTC is used. To get the returned $(LREF SysTime) to be
9084         a particular time zone, pass in that time zone and the $(LREF SysTime)
9085         to be returned will be converted to that time zone (though it will still
9086         be read in as whatever time zone is in its string).
9087 
9088         The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and
9089         -HH:MM.
9090 
9091         Params:
9092             isoExtString = A string formatted in the ISO Extended format for
9093                            dates and times.
9094             tz           = The time zone to convert the given time to (no
9095                            conversion occurs if null).
9096 
9097         Throws:
9098             $(REF DateTimeException,std,datetime,date) if the given string is
9099             not in the ISO format or if the resulting $(LREF SysTime) would not
9100             be valid.
9101       +/
9102     static SysTime fromISOExtString(S)(scope const S isoExtString, immutable TimeZone tz = null) @safe
9103         if (isSomeString!(S))
9104     {
9105         import std.algorithm.searching : countUntil, find;
9106         import std.conv : to;
9107         import std.string : strip, indexOf;
9108 
9109         auto str = strip(isoExtString);
9110 
9111         auto tIndex = str.indexOf('T');
9112         enforce(tIndex != -1, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
9113 
9114         auto found = str[tIndex + 1 .. $].find('.', 'Z', '+', '-');
9115         auto dateTimeStr = str[0 .. $ - found[0].length];
9116 
9117         typeof(str) foundTZ;  // needs to have longer lifetime than zoneStr
9118         typeof(str) fracSecStr;
9119         typeof(str) zoneStr;
9120 
9121         if (found[1] != 0)
9122         {
9123             if (found[1] == 1)
9124             {
9125                 foundTZ = found[0].find('Z', '+', '-')[0];
9126 
9127                 if (foundTZ.length != 0)
9128                 {
9129                     fracSecStr = found[0][0 .. $ - foundTZ.length];
9130                     zoneStr = foundTZ;
9131                 }
9132                 else
9133                     fracSecStr = found[0];
9134             }
9135             else
9136                 zoneStr = found[0];
9137         }
9138 
9139         try
9140         {
9141             auto dateTime = DateTime.fromISOExtString(dateTimeStr);
9142             auto fracSec = fracSecsFromISOString(fracSecStr);
9143             Rebindable!(immutable TimeZone) parsedZone;
9144 
9145             if (zoneStr.empty)
9146                 parsedZone = LocalTime();
9147             else if (zoneStr == "Z")
9148                 parsedZone = UTC();
9149             else
9150                 parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
9151 
9152             auto retval = SysTime(dateTime, fracSec, parsedZone);
9153 
9154             if (tz !is null)
9155                 retval.timezone = tz;
9156 
9157             return retval;
9158         }
9159         catch (DateTimeException dte)
9160             throw new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString));
9161     }
9162 
9163     ///
9164     @safe unittest
9165     {
9166         import core.time : hours, msecs, usecs, hnsecs;
9167         import std.datetime.date : DateTime;
9168         import std.datetime.timezone : SimpleTimeZone, UTC;
9169 
9170         assert(SysTime.fromISOExtString("2010-07-04T07:06:12") ==
9171                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9172 
9173         assert(SysTime.fromISOExtString("1998-12-25T02:15:00.007") ==
9174                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
9175 
9176         assert(SysTime.fromISOExtString("0000-01-05T23:09:59.00002") ==
9177                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
9178 
9179         assert(SysTime.fromISOExtString("2013-02-07T04:39:37.000050392") ==
9180                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
9181 
9182         assert(SysTime.fromISOExtString("-0004-01-05T00:00:02") ==
9183                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
9184 
9185         assert(SysTime.fromISOExtString(" 2010-07-04T07:06:12 ") ==
9186                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9187 
9188         assert(SysTime.fromISOExtString("2010-07-04T07:06:12Z") ==
9189                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
9190 
9191         assert(SysTime.fromISOExtString("2010-07-04T07:06:12-08:00") ==
9192                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9193                        new immutable SimpleTimeZone(hours(-8))));
9194         assert(SysTime.fromISOExtString("2010-07-04T07:06:12+08:00") ==
9195                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9196                        new immutable SimpleTimeZone(hours(8))));
9197     }
9198 
9199     @safe unittest
9200     {
9201         import core.time;
9202         foreach (str; ["", "20100704000000", "20100704 000000",
9203                        "20100704t000000", "20100704T000000.", "20100704T000000.0",
9204                        "2010-07:0400:00:00", "2010-07-04 00:00:00",
9205                        "2010-07-04 00:00:00", "2010-07-04t00:00:00",
9206                        "2010-07-04T00:00:00.", "2010-07-04T00:00:00.A", "2010-07-04T00:00:00.Z",
9207                        "2010-07-04T00:00:00.0000000A", "2010-07-04T00:00:00.00000000A",
9208                        "2010-07-04T00:00:00+", "2010-07-04T00:00:00-",
9209                        "2010-07-04T00:00:00:", "2010-07-04T00:00:00-:", "2010-07-04T00:00:00+:",
9210                        "2010-07-04T00:00:00-1:", "2010-07-04T00:00:00+1:", "2010-07-04T00:00:00+1:0",
9211                        "2010-07-04T00:00:00-12.00", "2010-07-04T00:00:00+12.00",
9212                        "2010-07-04T00:00:00-8", "2010-07-04T00:00:00+8",
9213                        "20100704T000000-800", "20100704T000000+800",
9214                        "20100704T000000-080", "20100704T000000+080",
9215                        "20100704T000000-2400", "20100704T000000+2400",
9216                        "20100704T000000-1260", "20100704T000000+1260",
9217                        "20100704T000000.0-800", "20100704T000000.0+800",
9218                        "20100704T000000.0-8", "20100704T000000.0+8",
9219                        "20100704T000000.0-080", "20100704T000000.0+080",
9220                        "20100704T000000.0-2400", "20100704T000000.0+2400",
9221                        "20100704T000000.0-1260", "20100704T000000.0+1260",
9222                        "2010-07-04T00:00:00-8:00", "2010-07-04T00:00:00+8:00",
9223                        "2010-07-04T00:00:00-24:00", "2010-07-04T00:00:00+24:00",
9224                        "2010-07-04T00:00:00-12:60", "2010-07-04T00:00:00+12:60",
9225                        "2010-07-04T00:00:00.0-8:00", "2010-07-04T00:00:00.0+8:00",
9226                        "2010-07-04T00:00:00.0-8", "2010-07-04T00:00:00.0+8",
9227                        "2010-07-04T00:00:00.0-24:00", "2010-07-04T00:00:00.0+24:00",
9228                        "2010-07-04T00:00:00.0-12:60", "2010-07-04T00:00:00.0+12:60",
9229                        "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00",
9230                        "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.0",
9231                        "20101222T172201", "2010-Dec-22 17:22:01"])
9232         {
9233             assertThrown!DateTimeException(SysTime.fromISOExtString(str), format("[%s]", str));
9234         }
9235 
9236         static void test(string str, SysTime st, size_t line = __LINE__)
9237         {
9238             if (SysTime.fromISOExtString(str) != st)
9239                 throw new AssertError("unittest failure", __FILE__, line);
9240         }
9241 
9242         test("2010-12-22T17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 1)));
9243         test("1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9244         test("-1999-07-06T12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
9245         test("+01999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9246         test("1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9247         test(" 1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9248         test(" 1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9249 
9250         test("1907-07-07T12:12:12.0", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9251         test("1907-07-07T12:12:12.0000000", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9252         test("1907-07-07T12:12:12.0000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), hnsecs(1)));
9253         test("2010-07-04T00:00:00.00000000", SysTime(Date(2010, 7, 4)));
9254         test("2010-07-04T00:00:00.00000009", SysTime(Date(2010, 7, 4)));
9255         test("2010-07-04T00:00:00.00000019", SysTime(DateTime(2010, 7, 4), hnsecs(1)));
9256         test("1907-07-07T12:12:12.000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9257         test("1907-07-07T12:12:12.0000010", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9258         test("1907-07-07T12:12:12.001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9259         test("1907-07-07T12:12:12.0010000", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9260 
9261         auto west60 = new immutable SimpleTimeZone(hours(-1));
9262         auto west90 = new immutable SimpleTimeZone(minutes(-90));
9263         auto west480 = new immutable SimpleTimeZone(hours(-8));
9264         auto east60 = new immutable SimpleTimeZone(hours(1));
9265         auto east90 = new immutable SimpleTimeZone(minutes(90));
9266         auto east480 = new immutable SimpleTimeZone(hours(8));
9267 
9268         test("2010-12-22T17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), UTC()));
9269         test("2010-12-22T17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9270         test("2010-12-22T17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9271         test("2010-12-22T17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
9272         test("2010-12-22T17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
9273         test("2010-12-22T17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9274         test("2010-12-22T17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9275         test("2010-12-22T17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9276         test("2010-12-22T17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
9277 
9278         test("2010-11-03T06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
9279         test("2010-12-22T17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_341_200), UTC()));
9280         test("2010-12-22T17:22:01.23112-01:00",
9281              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9282         test("2010-12-22T17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), west60));
9283         test("2010-12-22T17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
9284         test("2010-12-22T17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
9285         test("2010-12-22T17:22:01.1234567+01:00",
9286              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
9287         test("2010-12-22T17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9288         test("2010-12-22T17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9289         test("2010-12-22T17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
9290 
9291         static void testScope(scope ref string str) @safe
9292         {
9293             auto result = SysTime.fromISOExtString(str);
9294         }
9295     }
9296 
9297     // https://issues.dlang.org/show_bug.cgi?id=17801
9298     @safe unittest
9299     {
9300         import core.time;
9301         import std.conv : to;
9302         import std.meta : AliasSeq;
9303         static foreach (C; AliasSeq!(char, wchar, dchar))
9304         {
9305             static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
9306             {
9307                 assert(SysTime.fromISOExtString(to!S("2012-12-21T14:15:16Z")) ==
9308                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
9309             }
9310         }
9311     }
9312 
9313 
9314     /++
9315         Creates a $(LREF SysTime) from a string with the format
9316         YYYY-Mon-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
9317         is the time zone). Whitespace is stripped from the given string.
9318 
9319         The exact format is exactly as described in $(LREF toSimpleString) except
9320         that trailing zeroes are permitted - including having fractional seconds
9321         with all zeroes. The time zone and fractional seconds are optional,
9322         however, a decimal point with nothing following it is invalid.
9323         Also, while $(LREF toSimpleString) will never generate a
9324         string with more than 7 digits in the fractional seconds (because that's
9325         the limit with hecto-nanosecond precision), it will allow more than 7
9326         digits in order to read strings from other sources that have higher
9327         precision (however, any digits beyond 7 will be truncated).
9328 
9329         If there is no time zone in the string, then
9330         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
9331         then `UTC` is used. Otherwise, a
9332         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
9333         given offset from UTC is used. To get the returned $(LREF SysTime) to be
9334         a particular time zone, pass in that time zone and the $(LREF SysTime)
9335         to be returned will be converted to that time zone (though it will still
9336         be read in as whatever time zone is in its string).
9337 
9338         The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and
9339         -HH:MM.
9340 
9341         Params:
9342             simpleString = A string formatted in the way that
9343                            `toSimpleString` formats dates and times.
9344             tz           = The time zone to convert the given time to (no
9345                            conversion occurs if null).
9346 
9347         Throws:
9348             $(REF DateTimeException,std,datetime,date) if the given string is
9349             not in the ISO format or if the resulting $(LREF SysTime) would not
9350             be valid.
9351       +/
9352     static SysTime fromSimpleString(S)(scope const S simpleString, immutable TimeZone tz = null) @safe
9353         if (isSomeString!(S))
9354     {
9355         import std.algorithm.searching : find;
9356         import std.conv : to;
9357         import std.string : strip, indexOf;
9358 
9359         auto str = strip(simpleString);
9360 
9361         auto spaceIndex = str.indexOf(' ');
9362         enforce(spaceIndex != -1, new DateTimeException(format("Invalid Simple String: %s", simpleString)));
9363 
9364         auto found = str[spaceIndex + 1 .. $].find('.', 'Z', '+', '-');
9365         auto dateTimeStr = str[0 .. $ - found[0].length];
9366 
9367         typeof(str) foundTZ;  // needs to have longer lifetime than zoneStr
9368         typeof(str) fracSecStr;
9369         typeof(str) zoneStr;
9370 
9371         if (found[1] != 0)
9372         {
9373             if (found[1] == 1)
9374             {
9375                 foundTZ = found[0].find('Z', '+', '-')[0];
9376 
9377                 if (foundTZ.length != 0)
9378                 {
9379                     fracSecStr = found[0][0 .. $ - foundTZ.length];
9380                     zoneStr = foundTZ;
9381                 }
9382                 else
9383                     fracSecStr = found[0];
9384             }
9385             else
9386                 zoneStr = found[0];
9387         }
9388 
9389         try
9390         {
9391             auto dateTime = DateTime.fromSimpleString(dateTimeStr);
9392             auto fracSec = fracSecsFromISOString(fracSecStr);
9393             Rebindable!(immutable TimeZone) parsedZone;
9394 
9395             if (zoneStr.empty)
9396                 parsedZone = LocalTime();
9397             else if (zoneStr == "Z")
9398                 parsedZone = UTC();
9399             else
9400                 parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
9401 
9402             auto retval = SysTime(dateTime, fracSec, parsedZone);
9403 
9404             if (tz !is null)
9405                 retval.timezone = tz;
9406 
9407             return retval;
9408         }
9409         catch (DateTimeException dte)
9410             throw new DateTimeException(format("Invalid Simple String: %s", simpleString));
9411     }
9412 
9413     ///
9414     @safe unittest
9415     {
9416         import core.time : hours, msecs, usecs, hnsecs;
9417         import std.datetime.date : DateTime;
9418         import std.datetime.timezone : SimpleTimeZone, UTC;
9419 
9420         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12") ==
9421                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9422 
9423         assert(SysTime.fromSimpleString("1998-Dec-25 02:15:00.007") ==
9424                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
9425 
9426         assert(SysTime.fromSimpleString("0000-Jan-05 23:09:59.00002") ==
9427                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
9428 
9429         assert(SysTime.fromSimpleString("2013-Feb-07 04:39:37.000050392") ==
9430                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
9431 
9432         assert(SysTime.fromSimpleString("-0004-Jan-05 00:00:02") ==
9433                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
9434 
9435         assert(SysTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") ==
9436                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9437 
9438         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12Z") ==
9439                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
9440 
9441         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12-08:00") ==
9442                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9443                        new immutable SimpleTimeZone(hours(-8))));
9444 
9445         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12+08:00") ==
9446                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9447                        new immutable SimpleTimeZone(hours(8))));
9448     }
9449 
9450     @safe unittest
9451     {
9452         import core.time;
9453         foreach (str; ["", "20100704000000", "20100704 000000",
9454                        "20100704t000000", "20100704T000000.", "20100704T000000.0",
9455                        "2010-07-0400:00:00", "2010-07-04 00:00:00", "2010-07-04t00:00:00",
9456                        "2010-07-04T00:00:00.", "2010-07-04T00:00:00.0",
9457                        "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00", "2010-Jul-04T00:00:00",
9458                        "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.A", "2010-Jul-04 00:00:00.Z",
9459                        "2010-Jul-04 00:00:00.0000000A", "2010-Jul-04 00:00:00.00000000A",
9460                        "2010-Jul-04 00:00:00+", "2010-Jul-04 00:00:00-",
9461                        "2010-Jul-04 00:00:00:", "2010-Jul-04 00:00:00-:",
9462                        "2010-Jul-04 00:00:00+:", "2010-Jul-04 00:00:00-1:",
9463                        "2010-Jul-04 00:00:00+1:", "2010-Jul-04 00:00:00+1:0",
9464                        "2010-Jul-04 00:00:00-12.00", "2010-Jul-04 00:00:00+12.00",
9465                        "2010-Jul-04 00:00:00-8", "2010-Jul-04 00:00:00+8",
9466                        "20100704T000000-800", "20100704T000000+800",
9467                        "20100704T000000-080", "20100704T000000+080",
9468                        "20100704T000000-2400", "20100704T000000+2400",
9469                        "20100704T000000-1260", "20100704T000000+1260",
9470                        "20100704T000000.0-800", "20100704T000000.0+800",
9471                        "20100704T000000.0-8", "20100704T000000.0+8",
9472                        "20100704T000000.0-080", "20100704T000000.0+080",
9473                        "20100704T000000.0-2400", "20100704T000000.0+2400",
9474                        "20100704T000000.0-1260", "20100704T000000.0+1260",
9475                        "2010-Jul-04 00:00:00-8:00", "2010-Jul-04 00:00:00+8:00",
9476                        "2010-Jul-04 00:00:00-08:0", "2010-Jul-04 00:00:00+08:0",
9477                        "2010-Jul-04 00:00:00-24:00", "2010-Jul-04 00:00:00+24:00",
9478                        "2010-Jul-04 00:00:00-12:60", "2010-Jul-04 00:00:00+24:60",
9479                        "2010-Jul-04 00:00:00.0-8:00", "2010-Jul-04 00:00:00+8:00",
9480                        "2010-Jul-04 00:00:00.0-8", "2010-Jul-04 00:00:00.0+8",
9481                        "2010-Jul-04 00:00:00.0-08:0", "2010-Jul-04 00:00:00.0+08:0",
9482                        "2010-Jul-04 00:00:00.0-24:00", "2010-Jul-04 00:00:00.0+24:00",
9483                        "2010-Jul-04 00:00:00.0-12:60", "2010-Jul-04 00:00:00.0+24:60",
9484                        "20101222T172201", "2010-12-22T172201"])
9485         {
9486             assertThrown!DateTimeException(SysTime.fromSimpleString(str), format("[%s]", str));
9487         }
9488 
9489         static void test(string str, SysTime st, size_t line = __LINE__)
9490         {
9491             if (SysTime.fromSimpleString(str) != st)
9492                 throw new AssertError("unittest failure", __FILE__, line);
9493         }
9494 
9495         test("2010-Dec-22 17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 1)));
9496         test("1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9497         test("-1999-Jul-06 12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
9498         test("+01999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9499         test("1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9500         test(" 1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9501         test(" 1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9502 
9503         test("1907-Jul-07 12:12:12.0", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9504         test("1907-Jul-07 12:12:12.0000000", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9505         test("2010-Jul-04 00:00:00.00000000", SysTime(Date(2010, 7, 4)));
9506         test("2010-Jul-04 00:00:00.00000009", SysTime(Date(2010, 7, 4)));
9507         test("2010-Jul-04 00:00:00.00000019", SysTime(DateTime(2010, 7, 4), hnsecs(1)));
9508         test("1907-Jul-07 12:12:12.0000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), hnsecs(1)));
9509         test("1907-Jul-07 12:12:12.000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9510         test("1907-Jul-07 12:12:12.0000010", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9511         test("1907-Jul-07 12:12:12.001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9512         test("1907-Jul-07 12:12:12.0010000", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9513 
9514         auto west60 = new immutable SimpleTimeZone(hours(-1));
9515         auto west90 = new immutable SimpleTimeZone(minutes(-90));
9516         auto west480 = new immutable SimpleTimeZone(hours(-8));
9517         auto east60 = new immutable SimpleTimeZone(hours(1));
9518         auto east90 = new immutable SimpleTimeZone(minutes(90));
9519         auto east480 = new immutable SimpleTimeZone(hours(8));
9520 
9521         test("2010-Dec-22 17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), UTC()));
9522         test("2010-Dec-22 17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9523         test("2010-Dec-22 17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9524         test("2010-Dec-22 17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
9525         test("2010-Dec-22 17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
9526         test("2010-Dec-22 17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9527         test("2010-Dec-22 17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9528         test("2010-Dec-22 17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9529         test("2010-Dec-22 17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
9530 
9531         test("2010-Nov-03 06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
9532         test("2010-Dec-22 17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_341_200), UTC()));
9533         test("2010-Dec-22 17:22:01.23112-01:00",
9534              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9535         test("2010-Dec-22 17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), west60));
9536         test("2010-Dec-22 17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
9537         test("2010-Dec-22 17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
9538         test("2010-Dec-22 17:22:01.1234567+01:00",
9539              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
9540         test("2010-Dec-22 17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9541         test("2010-Dec-22 17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9542         test("2010-Dec-22 17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
9543 
9544         static void testScope(scope ref string str) @safe
9545         {
9546             auto result = SysTime.fromSimpleString(str);
9547         }
9548     }
9549 
9550     // https://issues.dlang.org/show_bug.cgi?id=17801
9551     @safe unittest
9552     {
9553         import core.time;
9554         import std.conv : to;
9555         import std.meta : AliasSeq;
9556         static foreach (C; AliasSeq!(char, wchar, dchar))
9557         {
9558             static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
9559             {
9560                 assert(SysTime.fromSimpleString(to!S("2012-Dec-21 14:15:16Z")) ==
9561                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
9562             }
9563         }
9564     }
9565 
9566 
9567     /++
9568         Returns the $(LREF SysTime) farthest in the past which is representable
9569         by $(LREF SysTime).
9570 
9571         The $(LREF SysTime) which is returned is in UTC.
9572       +/
9573     @property static SysTime min() @safe pure nothrow
9574     {
9575         return SysTime(long.min, UTC());
9576     }
9577 
9578     @safe unittest
9579     {
9580         assert(SysTime.min.year < 0);
9581         assert(SysTime.min < SysTime.max);
9582     }
9583 
9584 
9585     /++
9586         Returns the $(LREF SysTime) farthest in the future which is representable
9587         by $(LREF SysTime).
9588 
9589         The $(LREF SysTime) which is returned is in UTC.
9590       +/
9591     @property static SysTime max() @safe pure nothrow
9592     {
9593         return SysTime(long.max, UTC());
9594     }
9595 
9596     @safe unittest
9597     {
9598         assert(SysTime.max.year > 0);
9599         assert(SysTime.max > SysTime.min);
9600     }
9601 
9602 
9603 private:
9604 
9605     /+
9606         Returns `stdTime` converted to $(LREF SysTime)'s time zone.
9607       +/
9608     @property long adjTime() @safe const nothrow scope
9609     {
9610         return _timezone.utcToTZ(_stdTime);
9611     }
9612 
9613 
9614     /+
9615         Converts the given hnsecs from $(LREF SysTime)'s time zone to std time.
9616       +/
9617     @property void adjTime(long adjTime) @safe nothrow scope
9618     {
9619         _stdTime = _timezone.tzToUTC(adjTime);
9620     }
9621 
9622 
9623     final class InitTimeZone : TimeZone
9624     {
9625     public:
9626 
9627         static immutable(InitTimeZone) opCall() @safe pure nothrow @nogc { return _initTimeZone; }
9628 
9629         @property override bool hasDST() @safe const nothrow @nogc { return false; }
9630 
9631         override bool dstInEffect(long stdTime) @safe const scope nothrow @nogc { return false; }
9632 
9633         override long utcToTZ(long stdTime) @safe const scope nothrow @nogc { return 0; }
9634 
9635         override long tzToUTC(long adjTime) @safe const scope nothrow @nogc { return 0; }
9636 
9637         override Duration utcOffsetAt(long stdTime) @safe const scope nothrow @nogc { return Duration.zero; }
9638 
9639     private:
9640 
9641         this() @safe immutable pure
9642         {
9643             super("SysTime.init's timezone", "SysTime.init's timezone", "SysTime.init's timezone");
9644         }
9645 
9646         static immutable InitTimeZone _initTimeZone = new immutable(InitTimeZone);
9647     }
9648 
9649     // https://issues.dlang.org/show_bug.cgi?id=17732
9650     @safe unittest
9651     {
9652         assert(SysTime.init.timezone is InitTimeZone());
9653         assert(SysTime.init.toISOString() == "00010101T000000+00:00");
9654         assert(SysTime.init.toISOExtString() == "0001-01-01T00:00:00+00:00");
9655         assert(SysTime.init.toSimpleString() == "0001-Jan-01 00:00:00+00:00");
9656         assert(SysTime.init.toString() == "0001-Jan-01 00:00:00+00:00");
9657     }
9658 
9659     // Assigning a value to _timezone in SysTime.init currently doesn't work due
9660     // to https://issues.dlang.org/show_bug.cgi?id=17740. So, to hack around
9661     // that problem, these accessors have been added so that we can insert a
9662     // runtime check for null and then use InitTimeZone for SysTime.init (which
9663     // which is the only case where _timezone would be null). This thus fixes
9664     // the problem with segfaulting when using SysTime.init but at the cost of
9665     // what should be an unnecessary null check. Once 17740 has finally been
9666     // fixed, _timezoneStorage should be removed, these accessors should be
9667     // removed, and the _timezone variable declaration should be restored.
9668     pragma(inline, true) @property _timezone() @safe const pure nothrow @nogc
9669     {
9670         return _timezoneStorage is null ? InitTimeZone() : _timezoneStorage;
9671     }
9672 
9673     pragma(inline, true) @property void _timezone(return scope immutable TimeZone tz) @safe pure nothrow @nogc scope
9674     {
9675         _timezoneStorage = tz;
9676     }
9677 
9678 
9679     long  _stdTime;
9680     Rebindable!(immutable TimeZone) _timezoneStorage;
9681     //Rebindable!(immutable TimeZone) _timezone = InitTimeZone();
9682 }
9683 
9684 ///
9685 @safe unittest
9686 {
9687     import core.time : days, hours, seconds;
9688     import std.datetime.date : Date, DateTime;
9689     import std.datetime.timezone : SimpleTimeZone, UTC;
9690 
9691     const dt = DateTime(2018, 1, 1, 10, 30, 0);
9692     // make a specific point in time in the UTC timezone
9693     auto st = SysTime(dt, UTC());
9694     assert(st.year == 2018);
9695     assert(st.hour == 10);
9696 
9697     // cast to convert
9698     assert(cast(DateTime) st == dt);
9699     assert(cast(Date) st == Date(2018, 1, 1));
9700 
9701     // make a specific point in time in the New York timezone
9702     const ny = SysTime(dt,
9703         new immutable SimpleTimeZone(-5.hours, "America/New_York")
9704     );
9705     assert(ny != st);
9706     assert(ny.hour == 10);
9707 
9708     // ISO standard time strings
9709     assert(st.toISOString() == "20180101T103000Z");
9710     assert(st.toISOExtString() == "2018-01-01T10:30:00Z");
9711 
9712     // add two days and 30 seconds
9713     st += 2.days + 30.seconds;
9714     assert(st.toISOExtString() == "2018-01-03T10:30:30Z");
9715 }
9716 
9717 
9718 /++
9719     Converts from unix time (which uses midnight, January 1st, 1970 UTC as its
9720     epoch and seconds as its units) to "std time" (which uses midnight,
9721     January 1st, 1 A.D. UTC and hnsecs as its units).
9722 
9723     The C standard does not specify the representation of time_t, so it is
9724     implementation defined. On POSIX systems, unix time is equivalent to
9725     time_t, but that's not necessarily true on other systems (e.g. it is
9726     not true for the Digital Mars C runtime). So, be careful when using unix
9727     time with C functions on non-POSIX systems.
9728 
9729     "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO
9730     8601 and is what $(LREF SysTime) uses internally. However, holding the time
9731     as an integer in hnsecs since that epoch technically isn't actually part of
9732     the standard, much as it's based on it, so the name "std time" isn't
9733     particularly good, but there isn't an official name for it. C# uses "ticks"
9734     for the same thing, but they aren't actually clock ticks, and the term
9735     "ticks" $(I is) used for actual clock ticks for $(REF MonoTime, core,time),
9736     so it didn't make sense to use the term ticks here. So, for better or worse,
9737     std.datetime uses the term "std time" for this.
9738 
9739     Params:
9740         unixTime = The unix time to convert.
9741 
9742     See_Also:
9743         SysTime.fromUnixTime
9744   +/
9745 long unixTimeToStdTime(long unixTime) @safe pure nothrow @nogc
9746 {
9747     return 621_355_968_000_000_000L + convert!("seconds", "hnsecs")(unixTime);
9748 }
9749 
9750 ///
9751 @safe unittest
9752 {
9753     import std.datetime.date : DateTime;
9754     import std.datetime.timezone : UTC;
9755 
9756     // Midnight, January 1st, 1970
9757     assert(unixTimeToStdTime(0) == 621_355_968_000_000_000L);
9758     assert(SysTime(unixTimeToStdTime(0)) ==
9759            SysTime(DateTime(1970, 1, 1), UTC()));
9760 
9761     assert(unixTimeToStdTime(int.max) == 642_830_804_470_000_000L);
9762     assert(SysTime(unixTimeToStdTime(int.max)) ==
9763            SysTime(DateTime(2038, 1, 19, 3, 14, 7), UTC()));
9764 
9765     assert(unixTimeToStdTime(-127_127) == 621_354_696_730_000_000L);
9766     assert(SysTime(unixTimeToStdTime(-127_127)) ==
9767            SysTime(DateTime(1969, 12, 30, 12, 41, 13), UTC()));
9768 }
9769 
9770 @safe unittest
9771 {
9772     // Midnight, January 2nd, 1970
9773     assert(unixTimeToStdTime(86_400) == 621_355_968_000_000_000L + 864_000_000_000L);
9774     // Midnight, December 31st, 1969
9775     assert(unixTimeToStdTime(-86_400) == 621_355_968_000_000_000L - 864_000_000_000L);
9776 
9777     assert(unixTimeToStdTime(0) == (Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs");
9778     assert(unixTimeToStdTime(0) == (DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs");
9779 
9780     foreach (dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)])
9781         assert(unixTimeToStdTime((dt - DateTime(1970, 1, 1)).total!"seconds") == (dt - DateTime.init).total!"hnsecs");
9782 }
9783 
9784 
9785 /++
9786     Converts std time (which uses midnight, January 1st, 1 A.D. UTC as its epoch
9787     and hnsecs as its units) to unix time (which uses midnight, January 1st,
9788     1970 UTC as its epoch and seconds as its units).
9789 
9790     The C standard does not specify the representation of time_t, so it is
9791     implementation defined. On POSIX systems, unix time is equivalent to
9792     time_t, but that's not necessarily true on other systems (e.g. it is
9793     not true for the Digital Mars C runtime). So, be careful when using unix
9794     time with C functions on non-POSIX systems.
9795 
9796     "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO
9797     8601 and is what $(LREF SysTime) uses internally. However, holding the time
9798     as an integer in hnsecs since that epoch technically isn't actually part of
9799     the standard, much as it's based on it, so the name "std time" isn't
9800     particularly good, but there isn't an official name for it. C# uses "ticks"
9801     for the same thing, but they aren't actually clock ticks, and the term
9802     "ticks" $(I is) used for actual clock ticks for $(REF MonoTime, core,time),
9803     so it didn't make sense to use the term ticks here. So, for better or worse,
9804     std.datetime uses the term "std time" for this.
9805 
9806     By default, the return type is time_t (which is normally an alias for
9807     int on 32-bit systems and long on 64-bit systems), but if a different
9808     size is required than either int or long can be passed as a template
9809     argument to get the desired size.
9810 
9811     If the return type is int, and the result can't fit in an int, then the
9812     closest value that can be held in 32 bits will be used (so `int.max`
9813     if it goes over and `int.min` if it goes under). However, no attempt
9814     is made to deal with integer overflow if the return type is long.
9815 
9816     Params:
9817         T = The return type (int or long). It defaults to time_t, which is
9818             normally 32 bits on a 32-bit system and 64 bits on a 64-bit
9819             system.
9820         stdTime = The std time to convert.
9821 
9822     Returns:
9823         A signed integer representing the unix time which is equivalent to
9824         the given std time.
9825 
9826     See_Also:
9827         SysTime.toUnixTime
9828   +/
9829 T stdTimeToUnixTime(T = time_t)(long stdTime) @safe pure nothrow
9830 if (is(T == int) || is(T == long))
9831 {
9832     immutable unixTime = convert!("hnsecs", "seconds")(stdTime - 621_355_968_000_000_000L);
9833 
9834     static assert(is(time_t == int) || is(time_t == long),
9835                   "Currently, std.datetime only supports systems where time_t is int or long");
9836 
9837     static if (is(T == long))
9838         return unixTime;
9839     else static if (is(T == int))
9840     {
9841         if (unixTime > int.max)
9842             return int.max;
9843         return unixTime < int.min ? int.min : cast(int) unixTime;
9844     }
9845     else
9846         static assert(0, "Bug in template constraint. Only int and long allowed.");
9847 }
9848 
9849 ///
9850 @safe unittest
9851 {
9852     // Midnight, January 1st, 1970 UTC
9853     assert(stdTimeToUnixTime(621_355_968_000_000_000L) == 0);
9854 
9855     // 2038-01-19 03:14:07 UTC
9856     assert(stdTimeToUnixTime(642_830_804_470_000_000L) == int.max);
9857 }
9858 
9859 @safe unittest
9860 {
9861     enum unixEpochAsStdTime = (Date(1970, 1, 1) - Date.init).total!"hnsecs";
9862 
9863     assert(stdTimeToUnixTime(unixEpochAsStdTime) == 0);  // Midnight, January 1st, 1970
9864     assert(stdTimeToUnixTime(unixEpochAsStdTime + 864_000_000_000L) == 86_400);  // Midnight, January 2nd, 1970
9865     assert(stdTimeToUnixTime(unixEpochAsStdTime - 864_000_000_000L) == -86_400);  // Midnight, December 31st, 1969
9866 
9867     assert(stdTimeToUnixTime((Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs") == 0);
9868     assert(stdTimeToUnixTime((DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs") == 0);
9869 
9870     foreach (dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)])
9871         assert(stdTimeToUnixTime((dt - DateTime.init).total!"hnsecs") == (dt - DateTime(1970, 1, 1)).total!"seconds");
9872 
9873     enum max = convert!("seconds", "hnsecs")(int.max);
9874     enum min = convert!("seconds", "hnsecs")(int.min);
9875     enum one = convert!("seconds", "hnsecs")(1);
9876 
9877     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max) == int.max);
9878     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max) == int.max);
9879 
9880     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + one) == int.max + 1L);
9881     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + one) == int.max);
9882     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + 9_999_999) == int.max);
9883     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + 9_999_999) == int.max);
9884 
9885     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min) == int.min);
9886     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min) == int.min);
9887 
9888     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - one) == int.min - 1L);
9889     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - one) == int.min);
9890     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - 9_999_999) == int.min);
9891     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - 9_999_999) == int.min);
9892 }
9893 
9894 
9895 version (StdDdoc)
9896 {
9897     version (Windows)
9898     {}
9899     else
9900     {
9901         alias SYSTEMTIME = void*;
9902         alias FILETIME = void*;
9903     }
9904 
9905     /++
9906         $(BLUE This function is Windows-Only.)
9907 
9908         Converts a `SYSTEMTIME` struct to a $(LREF SysTime).
9909 
9910         Params:
9911             st = The `SYSTEMTIME` struct to convert.
9912             tz = The time zone that the time in the `SYSTEMTIME` struct is
9913                  assumed to be (if the `SYSTEMTIME` was supplied by a Windows
9914                  system call, the `SYSTEMTIME` will either be in local time
9915                  or UTC, depending on the call).
9916 
9917         Throws:
9918             $(REF DateTimeException,std,datetime,date) if the given
9919             `SYSTEMTIME` will not fit in a $(LREF SysTime), which is highly
9920             unlikely to happen given that `SysTime.max` is in 29,228 A.D. and
9921             the maximum `SYSTEMTIME` is in 30,827 A.D.
9922       +/
9923     SysTime SYSTEMTIMEToSysTime(const scope SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe;
9924 
9925 
9926     /++
9927         $(BLUE This function is Windows-Only.)
9928 
9929         Converts a $(LREF SysTime) to a `SYSTEMTIME` struct.
9930 
9931         The `SYSTEMTIME` which is returned will be set using the given
9932         $(LREF SysTime)'s time zone, so to get the `SYSTEMTIME` in
9933         UTC, set the $(LREF SysTime)'s time zone to UTC.
9934 
9935         Params:
9936             sysTime = The $(LREF SysTime) to convert.
9937 
9938         Throws:
9939             $(REF DateTimeException,std,datetime,date) if the given
9940             $(LREF SysTime) will not fit in a `SYSTEMTIME`. This will only
9941             happen if the $(LREF SysTime)'s date is prior to 1601 A.D.
9942       +/
9943     SYSTEMTIME SysTimeToSYSTEMTIME(scope SysTime sysTime) @safe;
9944 
9945 
9946     /++
9947         $(BLUE This function is Windows-Only.)
9948 
9949         Converts a `FILETIME` struct to the number of hnsecs since midnight,
9950         January 1st, 1 A.D.
9951 
9952         Params:
9953             ft = The `FILETIME` struct to convert.
9954 
9955         Throws:
9956             $(REF DateTimeException,std,datetime,date) if the given
9957             `FILETIME` cannot be represented as the return value.
9958       +/
9959     long FILETIMEToStdTime(scope const FILETIME* ft) @safe;
9960 
9961 
9962     /++
9963         $(BLUE This function is Windows-Only.)
9964 
9965         Converts a `FILETIME` struct to a $(LREF SysTime).
9966 
9967         Params:
9968             ft = The `FILETIME` struct to convert.
9969             tz = The time zone that the $(LREF SysTime) will be in
9970                  (`FILETIME`s are in UTC).
9971 
9972         Throws:
9973             $(REF DateTimeException,std,datetime,date) if the given
9974             `FILETIME` will not fit in a $(LREF SysTime).
9975       +/
9976     SysTime FILETIMEToSysTime(scope const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe;
9977 
9978 
9979     /++
9980         $(BLUE This function is Windows-Only.)
9981 
9982         Converts a number of hnsecs since midnight, January 1st, 1 A.D. to a
9983         `FILETIME` struct.
9984 
9985         Params:
9986             stdTime = The number of hnsecs since midnight, January 1st, 1 A.D.
9987                       UTC.
9988 
9989         Throws:
9990             $(REF DateTimeException,std,datetime,date) if the given value will
9991             not fit in a `FILETIME`.
9992       +/
9993     FILETIME stdTimeToFILETIME(long stdTime) @safe;
9994 
9995 
9996     /++
9997         $(BLUE This function is Windows-Only.)
9998 
9999         Converts a $(LREF SysTime) to a `FILETIME` struct.
10000 
10001         `FILETIME`s are always in UTC.
10002 
10003         Params:
10004             sysTime = The $(LREF SysTime) to convert.
10005 
10006         Throws:
10007             $(REF DateTimeException,std,datetime,date) if the given
10008             $(LREF SysTime) will not fit in a `FILETIME`.
10009       +/
10010     FILETIME SysTimeToFILETIME(scope SysTime sysTime) @safe;
10011 }
10012 else version (Windows)
10013 {
10014     SysTime SYSTEMTIMEToSysTime(const scope SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe
10015     {
10016         const max = SysTime.max;
10017 
10018         static void throwLaterThanMax()
10019         {
10020             throw new DateTimeException("The given SYSTEMTIME is for a date greater than SysTime.max.");
10021         }
10022 
10023         if (st.wYear > max.year)
10024             throwLaterThanMax();
10025         else if (st.wYear == max.year)
10026         {
10027             if (st.wMonth > max.month)
10028                 throwLaterThanMax();
10029             else if (st.wMonth == max.month)
10030             {
10031                 if (st.wDay > max.day)
10032                     throwLaterThanMax();
10033                 else if (st.wDay == max.day)
10034                 {
10035                     if (st.wHour > max.hour)
10036                         throwLaterThanMax();
10037                     else if (st.wHour == max.hour)
10038                     {
10039                         if (st.wMinute > max.minute)
10040                             throwLaterThanMax();
10041                         else if (st.wMinute == max.minute)
10042                         {
10043                             if (st.wSecond > max.second)
10044                                 throwLaterThanMax();
10045                             else if (st.wSecond == max.second)
10046                             {
10047                                 if (st.wMilliseconds > max.fracSecs.total!"msecs")
10048                                     throwLaterThanMax();
10049                             }
10050                         }
10051                     }
10052                 }
10053             }
10054         }
10055 
10056         auto dt = DateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
10057 
10058         import core.time : msecs;
10059         return SysTime(dt, msecs(st.wMilliseconds), tz);
10060     }
10061 
10062     @system unittest
10063     {
10064         auto sysTime = Clock.currTime(UTC());
10065         SYSTEMTIME st = void;
10066         GetSystemTime(&st);
10067         auto converted = SYSTEMTIMEToSysTime(&st, UTC());
10068         import core.time : abs;
10069         assert(abs((converted - sysTime)) <= dur!"seconds"(2));
10070 
10071         static void testScope(scope SYSTEMTIME* st) @safe
10072         {
10073             auto result = SYSTEMTIMEToSysTime(st);
10074         }
10075     }
10076 
10077 
10078     SYSTEMTIME SysTimeToSYSTEMTIME(scope SysTime sysTime) @safe
10079     {
10080         immutable dt = cast(DateTime) sysTime;
10081 
10082         if (dt.year < 1601)
10083             throw new DateTimeException("SYSTEMTIME cannot hold dates prior to the year 1601.");
10084 
10085         SYSTEMTIME st;
10086 
10087         st.wYear = dt.year;
10088         st.wMonth = dt.month;
10089         st.wDayOfWeek = dt.dayOfWeek;
10090         st.wDay = dt.day;
10091         st.wHour = dt.hour;
10092         st.wMinute = dt.minute;
10093         st.wSecond = dt.second;
10094         st.wMilliseconds = cast(ushort) sysTime.fracSecs.total!"msecs";
10095 
10096         return st;
10097     }
10098 
10099     @system unittest
10100     {
10101         SYSTEMTIME st = void;
10102         GetSystemTime(&st);
10103         auto sysTime = SYSTEMTIMEToSysTime(&st, UTC());
10104 
10105         SYSTEMTIME result = SysTimeToSYSTEMTIME(sysTime);
10106 
10107         assert(st.wYear == result.wYear);
10108         assert(st.wMonth == result.wMonth);
10109         assert(st.wDayOfWeek == result.wDayOfWeek);
10110         assert(st.wDay == result.wDay);
10111         assert(st.wHour == result.wHour);
10112         assert(st.wMinute == result.wMinute);
10113         assert(st.wSecond == result.wSecond);
10114         assert(st.wMilliseconds == result.wMilliseconds);
10115 
10116         static void testScope(scope ref SysTime st) @safe
10117         {
10118             auto localResult = SysTimeToSYSTEMTIME(st);
10119         }
10120     }
10121 
10122     private enum hnsecsFrom1601 = 504_911_232_000_000_000L;
10123 
10124     long FILETIMEToStdTime(scope const FILETIME* ft) @safe
10125     {
10126         ULARGE_INTEGER ul;
10127         ul.HighPart = ft.dwHighDateTime;
10128         ul.LowPart = ft.dwLowDateTime;
10129         ulong tempHNSecs = ul.QuadPart;
10130 
10131         if (tempHNSecs > long.max - hnsecsFrom1601)
10132             throw new DateTimeException("The given FILETIME cannot be represented as a stdTime value.");
10133 
10134         return cast(long) tempHNSecs + hnsecsFrom1601;
10135     }
10136 
10137     SysTime FILETIMEToSysTime(scope const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe
10138     {
10139         auto sysTime = SysTime(FILETIMEToStdTime(ft), UTC());
10140         sysTime.timezone = tz;
10141         return sysTime;
10142     }
10143 
10144     @system unittest
10145     {
10146         auto sysTime = Clock.currTime(UTC());
10147         SYSTEMTIME st = void;
10148         GetSystemTime(&st);
10149 
10150         FILETIME ft = void;
10151         SystemTimeToFileTime(&st, &ft);
10152 
10153         auto converted = FILETIMEToSysTime(&ft);
10154 
10155         import core.time : abs;
10156         assert(abs((converted - sysTime)) <= dur!"seconds"(2));
10157 
10158         static void testScope(scope FILETIME* ft) @safe
10159         {
10160             auto result = FILETIMEToSysTime(ft);
10161         }
10162     }
10163 
10164 
10165     FILETIME stdTimeToFILETIME(long stdTime) @safe
10166     {
10167         if (stdTime < hnsecsFrom1601)
10168             throw new DateTimeException("The given stdTime value cannot be represented as a FILETIME.");
10169 
10170         ULARGE_INTEGER ul;
10171         ul.QuadPart = cast(ulong) stdTime - hnsecsFrom1601;
10172 
10173         FILETIME ft;
10174         ft.dwHighDateTime = ul.HighPart;
10175         ft.dwLowDateTime = ul.LowPart;
10176 
10177         return ft;
10178     }
10179 
10180     FILETIME SysTimeToFILETIME(scope SysTime sysTime) @safe
10181     {
10182         return stdTimeToFILETIME(sysTime.stdTime);
10183     }
10184 
10185     @system unittest
10186     {
10187         SYSTEMTIME st = void;
10188         GetSystemTime(&st);
10189 
10190         FILETIME ft = void;
10191         SystemTimeToFileTime(&st, &ft);
10192         auto sysTime = FILETIMEToSysTime(&ft, UTC());
10193 
10194         FILETIME result = SysTimeToFILETIME(sysTime);
10195 
10196         assert(ft.dwLowDateTime == result.dwLowDateTime);
10197         assert(ft.dwHighDateTime == result.dwHighDateTime);
10198 
10199         static void testScope(scope ref SysTime st) @safe
10200         {
10201             auto local_result = SysTimeToFILETIME(st);
10202         }
10203     }
10204 }
10205 
10206 
10207 /++
10208     Type representing the DOS file date/time format.
10209   +/
10210 alias DosFileTime = uint;
10211 
10212 /++
10213     Converts from DOS file date/time to $(LREF SysTime).
10214 
10215     Params:
10216         dft = The DOS file time to convert.
10217         tz  = The time zone which the DOS file time is assumed to be in.
10218 
10219     Throws:
10220         $(REF DateTimeException,std,datetime,date) if the `DosFileTime` is
10221         invalid.
10222   +/
10223 SysTime DosFileTimeToSysTime(DosFileTime dft, immutable TimeZone tz = LocalTime()) @safe
10224 {
10225     uint dt = cast(uint) dft;
10226 
10227     if (dt == 0)
10228         throw new DateTimeException("Invalid DosFileTime.");
10229 
10230     int year = ((dt >> 25) & 0x7F) + 1980;
10231     int month = ((dt >> 21) & 0x0F);       // 1 .. 12
10232     int dayOfMonth = ((dt >> 16) & 0x1F);  // 1 .. 31
10233     int hour = (dt >> 11) & 0x1F;          // 0 .. 23
10234     int minute = (dt >> 5) & 0x3F;         // 0 .. 59
10235     int second = (dt << 1) & 0x3E;         // 0 .. 58 (in 2 second increments)
10236 
10237     try
10238         return SysTime(DateTime(year, month, dayOfMonth, hour, minute, second), tz);
10239     catch (DateTimeException dte)
10240         throw new DateTimeException("Invalid DosFileTime", __FILE__, __LINE__, dte);
10241 }
10242 
10243 ///
10244 @safe unittest
10245 {
10246     import std.datetime.date : DateTime;
10247 
10248     assert(DosFileTimeToSysTime(0b00000000001000010000000000000000) == SysTime(DateTime(1980, 1, 1, 0, 0, 0)));
10249     assert(DosFileTimeToSysTime(0b11111111100111111011111101111101) == SysTime(DateTime(2107, 12, 31, 23, 59, 58)));
10250     assert(DosFileTimeToSysTime(0x3E3F8456) == SysTime(DateTime(2011, 1, 31, 16, 34, 44)));
10251 }
10252 
10253 @safe unittest
10254 {
10255     static void testScope(scope ref DosFileTime dft) @safe
10256     {
10257         auto result = DosFileTimeToSysTime(dft);
10258     }
10259 }
10260 
10261 
10262 /++
10263     Converts from $(LREF SysTime) to DOS file date/time.
10264 
10265     Params:
10266         sysTime = The $(LREF SysTime) to convert.
10267 
10268     Throws:
10269         $(REF DateTimeException,std,datetime,date) if the given
10270         $(LREF SysTime) cannot be converted to a `DosFileTime`.
10271   +/
10272 DosFileTime SysTimeToDosFileTime(scope SysTime sysTime) @safe
10273 {
10274     auto dateTime = cast(DateTime) sysTime;
10275 
10276     if (dateTime.year < 1980)
10277         throw new DateTimeException("DOS File Times cannot hold dates prior to 1980.");
10278 
10279     if (dateTime.year > 2107)
10280         throw new DateTimeException("DOS File Times cannot hold dates past 2107.");
10281 
10282     uint retval = 0;
10283     retval = (dateTime.year - 1980) << 25;
10284     retval |= (dateTime.month & 0x0F) << 21;
10285     retval |= (dateTime.day & 0x1F) << 16;
10286     retval |= (dateTime.hour & 0x1F) << 11;
10287     retval |= (dateTime.minute & 0x3F) << 5;
10288     retval |= (dateTime.second >> 1) & 0x1F;
10289 
10290     return cast(DosFileTime) retval;
10291 }
10292 
10293 ///
10294 @safe unittest
10295 {
10296     import std.datetime.date : DateTime;
10297 
10298     assert(SysTimeToDosFileTime(SysTime(DateTime(1980, 1, 1, 0, 0, 0))) == 0b00000000001000010000000000000000);
10299     assert(SysTimeToDosFileTime(SysTime(DateTime(2107, 12, 31, 23, 59, 58))) == 0b11111111100111111011111101111101);
10300     assert(SysTimeToDosFileTime(SysTime(DateTime(2011, 1, 31, 16, 34, 44))) == 0x3E3F8456);
10301 }
10302 
10303 @safe unittest
10304 {
10305     static void testScope(scope ref SysTime st) @safe
10306     {
10307         auto result = SysTimeToDosFileTime(st);
10308     }
10309 }
10310 
10311 
10312 /++
10313     The given array of `char` or random-access range of `char` or
10314     `ubyte` is expected to be in the format specified in
10315     $(HTTP tools.ietf.org/html/rfc5322, RFC 5322) section 3.3 with the
10316     grammar rule $(I date-time). It is the date-time format commonly used in
10317     internet messages such as e-mail and HTTP. The corresponding
10318     $(LREF SysTime) will be returned.
10319 
10320     RFC 822 was the original spec (hence the function's name), whereas RFC 5322
10321     is the current spec.
10322 
10323     The day of the week is ignored beyond verifying that it's a valid day of the
10324     week, as the day of the week can be inferred from the date. It is not
10325     checked whether the given day of the week matches the actual day of the week
10326     of the given date (though it is technically invalid per the spec if the
10327     day of the week doesn't match the actual day of the week of the given date).
10328 
10329     If the time zone is `"-0000"` (or considered to be equivalent to
10330     `"-0000"` by section 4.3 of the spec), a
10331     $(REF SimpleTimeZone,std,datetime,timezone) with a utc offset of `0` is
10332     used rather than $(REF UTC,std,datetime,timezone), whereas `"+0000"` uses
10333     $(REF UTC,std,datetime,timezone).
10334 
10335     Note that because $(LREF SysTime) does not currently support having a second
10336     value of 60 (as is sometimes done for leap seconds), if the date-time value
10337     does have a value of 60 for the seconds, it is treated as 59.
10338 
10339     The one area in which this function violates RFC 5322 is that it accepts
10340     `"\n"` in folding whitespace in the place of `"\r\n"`, because the
10341     HTTP spec requires it.
10342 
10343     Throws:
10344         $(REF DateTimeException,std,datetime,date) if the given string doesn't
10345         follow the grammar for a date-time field or if the resulting
10346         $(LREF SysTime) is invalid.
10347   +/
10348 SysTime parseRFC822DateTime()(scope const char[] value) @safe
10349 {
10350     import std.string : representation;
10351     return parseRFC822DateTime(value.representation);
10352 }
10353 
10354 /++ Ditto +/
10355 SysTime parseRFC822DateTime(R)(scope R value)
10356 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
10357     (is(immutable ElementType!R == immutable char) || is(immutable ElementType!R == immutable ubyte)))
10358 {
10359     import std.algorithm.searching : find, all;
10360     import std.ascii : isDigit, isAlpha, isPrintable;
10361     import std.conv : to;
10362     import std.functional : not;
10363     import std.string : capitalize, format;
10364     import std.traits : EnumMembers, isArray;
10365     import std.typecons : Rebindable;
10366 
10367     void stripAndCheckLen(R valueBefore, size_t minLen, size_t line = __LINE__)
10368     {
10369         value = _stripCFWS(valueBefore);
10370         if (value.length < minLen)
10371             throw new DateTimeException("date-time value too short", __FILE__, line);
10372     }
10373     stripAndCheckLen(value, "7Dec1200:00A".length);
10374 
10375     static if (isArray!R && (is(ElementEncodingType!R == char) || is(ElementEncodingType!R == ubyte)))
10376     {
10377         static string sliceAsString(R str) @trusted
10378         {
10379             return cast(string) str;
10380         }
10381     }
10382     else
10383     {
10384         char[4] temp;
10385         char[] sliceAsString(R str) @trusted
10386         {
10387             size_t i = 0;
10388             foreach (c; str)
10389                 temp[i++] = cast(char) c;
10390             return temp[0 .. str.length];
10391         }
10392     }
10393 
10394     // day-of-week
10395     if (isAlpha(value[0]))
10396     {
10397         auto dowStr = sliceAsString(value[0 .. 3]);
10398         switch (dowStr)
10399         {
10400             foreach (dow; EnumMembers!DayOfWeek)
10401             {
10402                 enum dowC = capitalize(to!string(dow));
10403                 case dowC:
10404                     goto afterDoW;
10405             }
10406             default: throw new DateTimeException(format("Invalid day-of-week: %s", dowStr));
10407         }
10408 afterDoW: stripAndCheckLen(value[3 .. value.length], ",7Dec1200:00A".length);
10409         if (value[0] != ',')
10410             throw new DateTimeException("day-of-week missing comma");
10411         stripAndCheckLen(value[1 .. value.length], "7Dec1200:00A".length);
10412     }
10413 
10414     // day
10415     immutable digits = isDigit(value[1]) ? 2 : 1;
10416     immutable day = _convDigits!short(value[0 .. digits]);
10417     if (day == -1)
10418         throw new DateTimeException("Invalid day");
10419     stripAndCheckLen(value[digits .. value.length], "Dec1200:00A".length);
10420 
10421     // month
10422     Month month;
10423     {
10424         auto monStr = sliceAsString(value[0 .. 3]);
10425         switch (monStr)
10426         {
10427             foreach (mon; EnumMembers!Month)
10428             {
10429                 enum monC = capitalize(to!string(mon));
10430                 case monC:
10431                 {
10432                     month = mon;
10433                     goto afterMon;
10434                 }
10435             }
10436             default: throw new DateTimeException(format("Invalid month: %s", monStr));
10437         }
10438 afterMon: stripAndCheckLen(value[3 .. value.length], "1200:00A".length);
10439     }
10440 
10441     // year
10442     auto found = value[2 .. value.length].find!(not!(isDigit))();
10443     size_t yearLen = value.length - found.length;
10444     if (found.length == 0)
10445         throw new DateTimeException("Invalid year");
10446     if (found[0] == ':')
10447         yearLen -= 2;
10448     auto year = _convDigits!short(value[0 .. yearLen]);
10449     if (year < 1900)
10450     {
10451         if (year == -1)
10452             throw new DateTimeException("Invalid year");
10453         if (yearLen < 4)
10454         {
10455             if (yearLen == 3)
10456                 year += 1900;
10457             else if (yearLen == 2)
10458                 year += year < 50 ? 2000 : 1900;
10459             else
10460                 throw new DateTimeException("Invalid year. Too few digits.");
10461         }
10462         else
10463             throw new DateTimeException("Invalid year. Cannot be earlier than 1900.");
10464     }
10465     stripAndCheckLen(value[yearLen .. value.length], "00:00A".length);
10466 
10467     // hour
10468     immutable hour = _convDigits!short(value[0 .. 2]);
10469     stripAndCheckLen(value[2 .. value.length], ":00A".length);
10470     if (value[0] != ':')
10471         throw new DateTimeException("Invalid hour");
10472     stripAndCheckLen(value[1 .. value.length], "00A".length);
10473 
10474     // minute
10475     immutable minute = _convDigits!short(value[0 .. 2]);
10476     stripAndCheckLen(value[2 .. value.length], "A".length);
10477 
10478     // second
10479     short second;
10480     if (value[0] == ':')
10481     {
10482         stripAndCheckLen(value[1 .. value.length], "00A".length);
10483         second = _convDigits!short(value[0 .. 2]);
10484         // this is just if/until SysTime is sorted out to fully support leap seconds
10485         if (second == 60)
10486             second = 59;
10487         stripAndCheckLen(value[2 .. value.length], "A".length);
10488     }
10489 
10490     immutable(TimeZone) parseTZ(int sign)
10491     {
10492         if (value.length < 5)
10493             throw new DateTimeException("Invalid timezone");
10494         immutable zoneHours = _convDigits!short(value[1 .. 3]);
10495         immutable zoneMinutes = _convDigits!short(value[3 .. 5]);
10496         if (zoneHours == -1 || zoneMinutes == -1 || zoneMinutes > 59)
10497             throw new DateTimeException("Invalid timezone");
10498         value = value[5 .. value.length];
10499         immutable utcOffset = (dur!"hours"(zoneHours) + dur!"minutes"(zoneMinutes)) * sign;
10500         if (utcOffset == Duration.zero)
10501         {
10502             return sign == 1 ? cast(immutable(TimeZone))UTC()
10503                              : cast(immutable(TimeZone))new immutable SimpleTimeZone(Duration.zero);
10504         }
10505         return new immutable(SimpleTimeZone)(utcOffset);
10506     }
10507 
10508     // zone
10509     Rebindable!(immutable TimeZone) tz;
10510     if (value[0] == '-')
10511         tz = parseTZ(-1);
10512     else if (value[0] == '+')
10513         tz = parseTZ(1);
10514     else
10515     {
10516         // obs-zone
10517         immutable tzLen = value.length - find(value, ' ', '\t', '(')[0].length;
10518         switch (sliceAsString(value[0 .. tzLen <= 4 ? tzLen : 4]))
10519         {
10520             case "UT": case "GMT": tz = UTC(); break;
10521             case "EST": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
10522             case "EDT": tz = new immutable SimpleTimeZone(dur!"hours"(-4)); break;
10523             case "CST": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
10524             case "CDT": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
10525             case "MST": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
10526             case "MDT": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
10527             case "PST": tz = new immutable SimpleTimeZone(dur!"hours"(-8)); break;
10528             case "PDT": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
10529             case "J": case "j": throw new DateTimeException("Invalid timezone");
10530             default:
10531             {
10532                 if (all!(isAlpha)(value[0 .. tzLen]))
10533                 {
10534                     tz = new immutable SimpleTimeZone(Duration.zero);
10535                     break;
10536                 }
10537                 throw new DateTimeException("Invalid timezone");
10538             }
10539         }
10540         value = value[tzLen .. value.length];
10541     }
10542 
10543     // This is kind of arbitrary. Technically, nothing but CFWS is legal past
10544     // the end of the timezone, but we don't want to be picky about that in a
10545     // function that's just parsing rather than validating. So, the idea here is
10546     // that if the next character is printable (and not part of CFWS), then it
10547     // might be part of the timezone and thus affect what the timezone was
10548     // supposed to be, so we'll throw, but otherwise, we'll just ignore it.
10549     if (!value.empty && isPrintable(value[0]) && value[0] != ' ' && value[0] != '(')
10550         throw new DateTimeException("Invalid timezone");
10551 
10552     try
10553         return SysTime(DateTime(year, month, day, hour, minute, second), tz);
10554     catch (DateTimeException dte)
10555         throw new DateTimeException("date-time format is correct, but the resulting SysTime is invalid.", dte);
10556 }
10557 
10558 ///
10559 @safe unittest
10560 {
10561     import core.time : hours;
10562     import std.datetime.date : DateTime, DateTimeException;
10563     import std.datetime.timezone : SimpleTimeZone, UTC;
10564     import std.exception : assertThrown;
10565 
10566     auto tz = new immutable SimpleTimeZone(hours(-8));
10567     assert(parseRFC822DateTime("Sat, 6 Jan 1990 12:14:19 -0800") ==
10568            SysTime(DateTime(1990, 1, 6, 12, 14, 19), tz));
10569 
10570     assert(parseRFC822DateTime("9 Jul 2002 13:11 +0000") ==
10571            SysTime(DateTime(2002, 7, 9, 13, 11, 0), UTC()));
10572 
10573     auto badStr = "29 Feb 2001 12:17:16 +0200";
10574     assertThrown!DateTimeException(parseRFC822DateTime(badStr));
10575 }
10576 
10577 version (StdUnittest) private void testParse822(alias cr)(string str, SysTime expected, size_t line = __LINE__)
10578 {
10579     import std.format : format;
10580     auto value = cr(str);
10581     auto result = parseRFC822DateTime(value);
10582     if (result != expected)
10583         throw new AssertError(format("wrong result. expected [%s], actual[%s]", expected, result), __FILE__, line);
10584 }
10585 
10586 version (StdUnittest) private void testBadParse822(alias cr)(string str, size_t line = __LINE__)
10587 {
10588     try
10589         parseRFC822DateTime(cr(str));
10590     catch (DateTimeException)
10591         return;
10592     throw new AssertError("No DateTimeException was thrown", __FILE__, line);
10593 }
10594 
10595 @system unittest
10596 {
10597     import core.time;
10598     import std.algorithm.iteration : filter, map;
10599     import std.algorithm.searching : canFind;
10600     import std.array : array;
10601     import std.ascii : letters;
10602     import std.format : format;
10603     import std.meta : AliasSeq;
10604     import std.range : chain, iota, take;
10605     import std.stdio : writefln, writeln;
10606     import std.string : representation;
10607 
10608     static struct Rand3Letters
10609     {
10610         enum empty = false;
10611         @property auto front() { return _mon; }
10612         void popFront()
10613         {
10614             import std.exception : assumeUnique;
10615             import std.random : rndGen;
10616             _mon = rndGen.map!(a => letters[a % letters.length])().take(3).array().assumeUnique();
10617         }
10618         string _mon;
10619         static auto start() { Rand3Letters retval; retval.popFront(); return retval; }
10620     }
10621 
10622     static foreach (cr; AliasSeq!(function(string a){return cast(char[]) a;},
10623                            function(string a){return cast(ubyte[]) a;},
10624                            function(string a){return a;},
10625                            function(string a){return map!(b => cast(char) b)(a.representation);}))
10626     {(){ // workaround slow optimizations for large functions
10627          // https://issues.dlang.org/show_bug.cgi?id=2396
10628         scope(failure) writeln(typeof(cr).stringof);
10629         alias test = testParse822!cr;
10630         alias testBad = testBadParse822!cr;
10631 
10632         immutable std1 = DateTime(2012, 12, 21, 13, 14, 15);
10633         immutable std2 = DateTime(2012, 12, 21, 13, 14, 0);
10634         immutable dst1 = DateTime(1976, 7, 4, 5, 4, 22);
10635         immutable dst2 = DateTime(1976, 7, 4, 5, 4, 0);
10636 
10637         test("21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
10638         test("21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
10639         test("Fri, 21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
10640         test("Fri, 21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
10641 
10642         test("04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10643         test("04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10644         test("Sun, 04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10645         test("Sun, 04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10646 
10647         test("4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10648         test("4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10649         test("Sun, 4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10650         test("Sun, 4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10651 
10652         auto badTZ = new immutable SimpleTimeZone(Duration.zero);
10653         test("21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
10654         test("21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
10655         test("Fri, 21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
10656         test("Fri, 21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
10657 
10658         test("04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10659         test("04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10660         test("Sun, 04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10661         test("Sun, 04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10662 
10663         test("4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10664         test("4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10665         test("Sun, 4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10666         test("Sun, 4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10667 
10668         auto pst = new immutable SimpleTimeZone(dur!"hours"(-8));
10669         auto pdt = new immutable SimpleTimeZone(dur!"hours"(-7));
10670         test("21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
10671         test("21 Dec 2012 13:14 -0800", SysTime(std2, pst));
10672         test("Fri, 21 Dec 2012 13:14 -0800", SysTime(std2, pst));
10673         test("Fri, 21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
10674 
10675         test("04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10676         test("04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10677         test("Sun, 04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10678         test("Sun, 04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10679 
10680         test("4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10681         test("4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10682         test("Sun, 4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10683         test("Sun, 4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10684 
10685         auto cet = new immutable SimpleTimeZone(dur!"hours"(1));
10686         auto cest = new immutable SimpleTimeZone(dur!"hours"(2));
10687         test("21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
10688         test("21 Dec 2012 13:14 +0100", SysTime(std2, cet));
10689         test("Fri, 21 Dec 2012 13:14 +0100", SysTime(std2, cet));
10690         test("Fri, 21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
10691 
10692         test("04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10693         test("04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10694         test("Sun, 04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10695         test("Sun, 04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10696 
10697         test("4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10698         test("4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10699         test("Sun, 4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10700         test("Sun, 4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10701 
10702         // dst and std times are switched in the Southern Hemisphere which is why the
10703         // time zone names and DateTime variables don't match.
10704         auto cstStd = new immutable SimpleTimeZone(dur!"hours"(9) + dur!"minutes"(30));
10705         auto cstDST = new immutable SimpleTimeZone(dur!"hours"(10) + dur!"minutes"(30));
10706         test("21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
10707         test("21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
10708         test("Fri, 21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
10709         test("Fri, 21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
10710 
10711         test("04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10712         test("04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10713         test("Sun, 04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10714         test("Sun, 04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10715 
10716         test("4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10717         test("4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10718         test("Sun, 4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10719         test("Sun, 4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10720 
10721         foreach (int i, mon; _monthNames)
10722         {
10723             test(format("17 %s 2012 00:05:02 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 2), UTC()));
10724             test(format("17 %s 2012 00:05 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 0), UTC()));
10725         }
10726 
10727         import std.uni : toLower, toUpper;
10728         foreach (mon; chain(_monthNames[].map!(a => toLower(a))(),
10729                             _monthNames[].map!(a => toUpper(a))(),
10730                             ["Jam", "Jen", "Fec", "Fdb", "Mas", "Mbr", "Aps", "Aqr", "Mai", "Miy",
10731                              "Jum", "Jbn", "Jup", "Jal", "Aur", "Apg", "Sem", "Sap", "Ocm", "Odt",
10732                              "Nom", "Nav", "Dem", "Dac"],
10733                             Rand3Letters.start().filter!(a => !_monthNames[].canFind(a)).take(20)))
10734         {
10735             scope(failure) writefln("Month: %s", mon);
10736             testBad(format("17 %s 2012 00:05:02 +0000", mon));
10737             testBad(format("17 %s 2012 00:05 +0000", mon));
10738         }
10739 
10740         immutable string[7] daysOfWeekNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
10741 
10742         {
10743             auto start = SysTime(DateTime(2012, 11, 11, 9, 42, 0), UTC());
10744             int day = 11;
10745 
10746             foreach (int i, dow; daysOfWeekNames)
10747             {
10748                 auto curr = start + dur!"days"(i);
10749                 test(format("%s, %s Nov 2012 09:42:00 +0000", dow, day), curr);
10750                 test(format("%s, %s Nov 2012 09:42 +0000", dow, day++), curr);
10751 
10752                 // Whether the day of the week matches the date is ignored.
10753                 test(format("%s, 11 Nov 2012 09:42:00 +0000", dow), start);
10754                 test(format("%s, 11 Nov 2012 09:42 +0000", dow), start);
10755             }
10756         }
10757 
10758         foreach (dow; chain(daysOfWeekNames[].map!(a => toLower(a))(),
10759                             daysOfWeekNames[].map!(a => toUpper(a))(),
10760                             ["Sum", "Spn", "Mom", "Man", "Tuf", "Tae", "Wem", "Wdd", "The", "Tur",
10761                              "Fro", "Fai", "San", "Sut"],
10762                             Rand3Letters.start().filter!(a => !daysOfWeekNames[].canFind(a)).take(20)))
10763         {
10764             scope(failure) writefln("Day of Week: %s", dow);
10765             testBad(format("%s, 11 Nov 2012 09:42:00 +0000", dow));
10766             testBad(format("%s, 11 Nov 2012 09:42 +0000", dow));
10767         }
10768 
10769         testBad("31 Dec 1899 23:59:59 +0000");
10770         test("01 Jan 1900 00:00:00 +0000", SysTime(Date(1900, 1, 1), UTC()));
10771         test("01 Jan 1900 00:00:00 -0000", SysTime(Date(1900, 1, 1),
10772                                                    new immutable SimpleTimeZone(Duration.zero)));
10773         test("01 Jan 1900 00:00:00 -0700", SysTime(Date(1900, 1, 1),
10774                                                    new immutable SimpleTimeZone(dur!"hours"(-7))));
10775 
10776         {
10777             auto st1 = SysTime(Date(1900, 1, 1), UTC());
10778             auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
10779             foreach (i; 1900 .. 2102)
10780             {
10781                 test(format("1 Jan %05d 00:00 +0000", i), st1);
10782                 test(format("1 Jan %05d 00:00 -1100", i), st2);
10783                 st1.add!"years"(1);
10784                 st2.add!"years"(1);
10785             }
10786             st1.year = 9998;
10787             st2.year = 9998;
10788             foreach (i; 9998 .. 11_002)
10789             {
10790                 test(format("1 Jan %05d 00:00 +0000", i), st1);
10791                 test(format("1 Jan %05d 00:00 -1100", i), st2);
10792                 st1.add!"years"(1);
10793                 st2.add!"years"(1);
10794             }
10795         }
10796 
10797         testBad("12 Feb 1907 23:17:09 0000");
10798         testBad("12 Feb 1907 23:17:09 +000");
10799         testBad("12 Feb 1907 23:17:09 -000");
10800         testBad("12 Feb 1907 23:17:09 +00000");
10801         testBad("12 Feb 1907 23:17:09 -00000");
10802         testBad("12 Feb 1907 23:17:09 +A");
10803         testBad("12 Feb 1907 23:17:09 +PST");
10804         testBad("12 Feb 1907 23:17:09 -A");
10805         testBad("12 Feb 1907 23:17:09 -PST");
10806 
10807         // test trailing stuff that gets ignored
10808         {
10809             foreach (c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
10810             {
10811                 scope(failure) writefln("c: %d", c);
10812                 test(format("21 Dec 2012 13:14:15 +0000%c", cast(char) c), SysTime(std1, UTC()));
10813                 test(format("21 Dec 2012 13:14:15 +0000%c  ", cast(char) c), SysTime(std1, UTC()));
10814                 test(format("21 Dec 2012 13:14:15 +0000%chello", cast(char) c), SysTime(std1, UTC()));
10815             }
10816         }
10817 
10818         // test trailing stuff that doesn't get ignored
10819         {
10820             foreach (c; chain(iota(33, '('), iota('(' + 1, 127)))
10821             {
10822                 scope(failure) writefln("c: %d", c);
10823                 testBad(format("21 Dec 2012 13:14:15 +0000%c", cast(char) c));
10824                 testBad(format("21 Dec 2012 13:14:15 +0000%c   ", cast(char) c));
10825                 testBad(format("21 Dec 2012 13:14:15 +0000%chello", cast(char) c));
10826             }
10827         }
10828 
10829         testBad("32 Jan 2012 12:13:14 -0800");
10830         testBad("31 Jan 2012 24:13:14 -0800");
10831         testBad("31 Jan 2012 12:60:14 -0800");
10832         testBad("31 Jan 2012 12:13:61 -0800");
10833         testBad("31 Jan 2012 12:13:14 -0860");
10834         test("31 Jan 2012 12:13:14 -0859",
10835              SysTime(DateTime(2012, 1, 31, 12, 13, 14),
10836                      new immutable SimpleTimeZone(dur!"hours"(-8) + dur!"minutes"(-59))));
10837 
10838         // leap-seconds
10839         test("21 Dec 2012 15:59:60 -0800", SysTime(DateTime(2012, 12, 21, 15, 59, 59), pst));
10840 
10841         // FWS
10842         test("Sun,4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10843         test("Sun,4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10844         test("Sun,4 Jul 1976 05:04 +0930 (foo)", SysTime(dst2, cstStd));
10845         test("Sun,4 Jul 1976 05:04:22 +0930 (foo)", SysTime(dst1, cstStd));
10846         test("Sun,4  \r\n  Jul  \r\n  1976  \r\n  05:04  \r\n  +0930  \r\n  (foo)", SysTime(dst2, cstStd));
10847         test("Sun,4  \r\n  Jul  \r\n  1976  \r\n  05:04:22  \r\n  +0930  \r\n  (foo)", SysTime(dst1, cstStd));
10848 
10849         auto str = "01 Jan 2012 12:13:14 -0800 ";
10850         test(str, SysTime(DateTime(2012, 1, 1, 12, 13, 14), new immutable SimpleTimeZone(hours(-8))));
10851         foreach (i; 0 .. str.length)
10852         {
10853             auto currStr = str.dup;
10854             currStr[i] = 'x';
10855             scope(failure) writefln("failed: %s", currStr);
10856             testBad(cast(string) currStr);
10857         }
10858         foreach (i; 2 .. str.length)
10859         {
10860             auto currStr = str[0 .. $ - i];
10861             scope(failure) writefln("failed: %s", currStr);
10862             testBad(cast(string) currStr);
10863             testBad((cast(string) currStr) ~ "                                    ");
10864         }
10865     }();}
10866 
10867     static void testScope(scope ref string str) @safe
10868     {
10869         auto result = parseRFC822DateTime(str);
10870     }
10871 }
10872 
10873 // Obsolete Format per section 4.3 of RFC 5322.
10874 @system unittest
10875 {
10876     import std.algorithm.iteration : filter, map;
10877     import std.ascii : letters;
10878     import std.exception : collectExceptionMsg;
10879     import std.format : format;
10880     import std.meta : AliasSeq;
10881     import std.range : chain, iota;
10882     import std.stdio : writefln, writeln;
10883     import std.string : representation;
10884 
10885     auto std1 = SysTime(DateTime(2012, 12, 21, 13, 14, 15), UTC());
10886     auto std2 = SysTime(DateTime(2012, 12, 21, 13, 14, 0), UTC());
10887     auto std3 = SysTime(DateTime(1912, 12, 21, 13, 14, 15), UTC());
10888     auto std4 = SysTime(DateTime(1912, 12, 21, 13, 14, 0), UTC());
10889     auto dst1 = SysTime(DateTime(1976, 7, 4, 5, 4, 22), UTC());
10890     auto dst2 = SysTime(DateTime(1976, 7, 4, 5, 4, 0), UTC());
10891     auto tooLate1 = SysTime(Date(10_000, 1, 1), UTC());
10892     auto tooLate2 = SysTime(DateTime(12_007, 12, 31, 12, 22, 19), UTC());
10893 
10894     static foreach (cr; AliasSeq!(function(string a){return cast(char[]) a;},
10895                            function(string a){return cast(ubyte[]) a;},
10896                            function(string a){return a;},
10897                            function(string a){return map!(b => cast(char) b)(a.representation);}))
10898     {(){ // workaround slow optimizations for large functions
10899          // https://issues.dlang.org/show_bug.cgi?id=2396
10900         scope(failure) writeln(typeof(cr).stringof);
10901         alias test = testParse822!cr;
10902         {
10903             auto list = ["", " ", " \r\n\t", "\t\r\n (hello world( frien(dog)) silly \r\n )  \t\t \r\n ()",
10904                          " \n ", "\t\n\t", " \n\t (foo) \n (bar) \r\n (baz) \n "];
10905 
10906             foreach (i, cfws; list)
10907             {
10908                 scope(failure) writefln("i: %s", i);
10909 
10910                 test(format("%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10911                 test(format("%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
10912                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
10913                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10914 
10915                 test(format("%1$s04%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10916                 test(format("%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10917                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10918                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04:22 +0000%1$s", cfws), dst1);
10919 
10920                 test(format("%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10921                 test(format("%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10922                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10923                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10924 
10925                 test(format("%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10926                 test(format("%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
10927                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
10928                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10929 
10930                 test(format("%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10931                 test(format("%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10932                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10933                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10934 
10935                 test(format("%1$s4%1$sJul%1$s76 05:04:22%1$s+0000%1$s", cfws), dst1);
10936                 test(format("%1$s4%1$sJul%1$s76 05:04%1$s+0000%1$s", cfws), dst2);
10937                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10938                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10939 
10940                 test(format("%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
10941                 test(format("%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
10942                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
10943                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
10944 
10945                 test(format("%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10946                 test(format("%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10947                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10948                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10949 
10950                 test(format("%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10951                 test(format("%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10952                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10953                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10954 
10955                 test(format("%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
10956                 test(format("%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
10957                 test(format("%1$sSat%1$s,%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
10958                 test(format("%1$sSun%1$s,%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
10959             }
10960         }
10961 
10962         // test years of 1, 2, and 3 digits.
10963         {
10964             auto st1 = SysTime(Date(2000, 1, 1), UTC());
10965             auto st2 = SysTime(Date(2000, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
10966             foreach (i; 0 .. 50)
10967             {
10968                 test(format("1 Jan %02d 00:00 GMT", i), st1);
10969                 test(format("1 Jan %02d 00:00 -1200", i), st2);
10970                 st1.add!"years"(1);
10971                 st2.add!"years"(1);
10972             }
10973         }
10974 
10975         {
10976             auto st1 = SysTime(Date(1950, 1, 1), UTC());
10977             auto st2 = SysTime(Date(1950, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
10978             foreach (i; 50 .. 100)
10979             {
10980                 test(format("1 Jan %02d 00:00 GMT", i), st1);
10981                 test(format("1 Jan %02d 00:00 -1200", i), st2);
10982                 st1.add!"years"(1);
10983                 st2.add!"years"(1);
10984             }
10985         }
10986 
10987         {
10988             auto st1 = SysTime(Date(1900, 1, 1), UTC());
10989             auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
10990             foreach (i; 0 .. 1000)
10991             {
10992                 test(format("1 Jan %03d 00:00 GMT", i), st1);
10993                 test(format("1 Jan %03d 00:00 -1100", i), st2);
10994                 st1.add!"years"(1);
10995                 st2.add!"years"(1);
10996             }
10997         }
10998 
10999         foreach (i; 0 .. 10)
11000         {
11001             auto str1 = cr(format("1 Jan %d 00:00 GMT", i));
11002             auto str2 = cr(format("1 Jan %d 00:00 -1200", i));
11003             assertThrown!DateTimeException(parseRFC822DateTime(str1));
11004             assertThrown!DateTimeException(parseRFC822DateTime(str1));
11005         }
11006 
11007         // test time zones
11008         {
11009             auto dt = DateTime(1982, 5, 3, 12, 22, 4);
11010             test("Wed, 03 May 1982 12:22:04 UT", SysTime(dt, UTC()));
11011             test("Wed, 03 May 1982 12:22:04 GMT", SysTime(dt, UTC()));
11012             test("Wed, 03 May 1982 12:22:04 EST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
11013             test("Wed, 03 May 1982 12:22:04 EDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-4))));
11014             test("Wed, 03 May 1982 12:22:04 CST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
11015             test("Wed, 03 May 1982 12:22:04 CDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
11016             test("Wed, 03 May 1982 12:22:04 MST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
11017             test("Wed, 03 May 1982 12:22:04 MDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
11018             test("Wed, 03 May 1982 12:22:04 PST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-8))));
11019             test("Wed, 03 May 1982 12:22:04 PDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
11020 
11021             auto badTZ = new immutable SimpleTimeZone(Duration.zero);
11022             foreach (dchar c; filter!(a => a != 'j' && a != 'J')(letters))
11023             {
11024                 scope(failure) writefln("c: %s", c);
11025                 test(format("Wed, 03 May 1982 12:22:04 %s", c), SysTime(dt, badTZ));
11026                 test(format("Wed, 03 May 1982 12:22:04%s", c), SysTime(dt, badTZ));
11027             }
11028 
11029             foreach (dchar c; ['j', 'J'])
11030             {
11031                 scope(failure) writefln("c: %s", c);
11032                 assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04 %s", c))));
11033                 assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04%s", c))));
11034             }
11035 
11036             foreach (string s; ["AAA", "GQW", "DDT", "PDA", "GT", "GM"])
11037             {
11038                 scope(failure) writefln("s: %s", s);
11039                 test(format("Wed, 03 May 1982 12:22:04 %s", s), SysTime(dt, badTZ));
11040             }
11041 
11042             // test trailing stuff that gets ignored
11043             {
11044                 foreach (c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
11045                 {
11046                     scope(failure) writefln("c: %d", c);
11047                     test(format("21Dec1213:14:15+0000%c", cast(char) c), std1);
11048                     test(format("21Dec1213:14:15+0000%c  ", cast(char) c), std1);
11049                     test(format("21Dec1213:14:15+0000%chello", cast(char) c), std1);
11050                 }
11051             }
11052 
11053             // test trailing stuff that doesn't get ignored
11054             {
11055                 foreach (c; chain(iota(33, '('), iota('(' + 1, 127)))
11056                 {
11057                     scope(failure) writefln("c: %d", c);
11058                     assertThrown!DateTimeException(
11059                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c", cast(char) c))));
11060                     assertThrown!DateTimeException(
11061                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c  ", cast(char) c))));
11062                     assertThrown!DateTimeException(
11063                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%chello", cast(char) c))));
11064                 }
11065             }
11066         }
11067 
11068         // test that the checks for minimum length work correctly and avoid
11069         // any RangeErrors.
11070         test("7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11071                                      new immutable SimpleTimeZone(Duration.zero)));
11072         test("Fri,7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11073                                          new immutable SimpleTimeZone(Duration.zero)));
11074         test("7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11075                                         new immutable SimpleTimeZone(Duration.zero)));
11076         test("Fri,7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11077                                             new immutable SimpleTimeZone(Duration.zero)));
11078 
11079         auto tooShortMsg = collectExceptionMsg!DateTimeException(parseRFC822DateTime(""));
11080         foreach (str; ["Fri,7Dec1200:00:00", "7Dec1200:00:00"])
11081         {
11082             foreach (i; 0 .. str.length)
11083             {
11084                 auto value = str[0 .. $ - i];
11085                 scope(failure) writeln(value);
11086                 assert(collectExceptionMsg!DateTimeException(parseRFC822DateTime(value)) == tooShortMsg);
11087             }
11088         }
11089     }();}
11090 }
11091 
11092 
11093 private:
11094 
11095 /+
11096     Returns the given hnsecs as an ISO string of fractional seconds.
11097   +/
11098 string fracSecsToISOString(int hnsecs, int prec = -1) @safe pure nothrow
11099 {
11100     import std.array : appender;
11101     auto w = appender!string();
11102     try
11103         fracSecsToISOString(w, hnsecs, prec);
11104     catch (Exception e)
11105         assert(0, "fracSecsToISOString() threw.");
11106     return w.data;
11107 }
11108 
11109 void fracSecsToISOString(W)(ref W writer, int hnsecs, int prec = -1)
11110 {
11111     import std.conv : toChars;
11112     import std.range : padLeft;
11113 
11114     assert(hnsecs >= 0);
11115 
11116     if (prec == 0)
11117         return;
11118 
11119     if (hnsecs == 0)
11120         return;
11121 
11122     put(writer, '.');
11123     auto chars = hnsecs.toChars.padLeft('0', 7);
11124 
11125     if (prec == -1)
11126     {
11127         while (chars.back == '0')
11128             chars.popBack();
11129         put(writer, chars);
11130     }
11131     else
11132         put(writer, chars[0 .. prec]);
11133 }
11134 
11135 @safe unittest
11136 {
11137     assert(fracSecsToISOString(0) == "");
11138     assert(fracSecsToISOString(1) == ".0000001");
11139     assert(fracSecsToISOString(10) == ".000001");
11140     assert(fracSecsToISOString(100) == ".00001");
11141     assert(fracSecsToISOString(1000) == ".0001");
11142     assert(fracSecsToISOString(10_000) == ".001");
11143     assert(fracSecsToISOString(100_000) == ".01");
11144     assert(fracSecsToISOString(1_000_000) == ".1");
11145     assert(fracSecsToISOString(1_000_001) == ".1000001");
11146     assert(fracSecsToISOString(1_001_001) == ".1001001");
11147     assert(fracSecsToISOString(1_071_601) == ".1071601");
11148     assert(fracSecsToISOString(1_271_641) == ".1271641");
11149     assert(fracSecsToISOString(9_999_999) == ".9999999");
11150     assert(fracSecsToISOString(9_999_990) == ".999999");
11151     assert(fracSecsToISOString(9_999_900) == ".99999");
11152     assert(fracSecsToISOString(9_999_000) == ".9999");
11153     assert(fracSecsToISOString(9_990_000) == ".999");
11154     assert(fracSecsToISOString(9_900_000) == ".99");
11155     assert(fracSecsToISOString(9_000_000) == ".9");
11156     assert(fracSecsToISOString(999) == ".0000999");
11157     assert(fracSecsToISOString(9990) == ".000999");
11158     assert(fracSecsToISOString(99_900) == ".00999");
11159     assert(fracSecsToISOString(999_000) == ".0999");
11160 }
11161 
11162 
11163 /+
11164     Returns a Duration corresponding to to the given ISO string of
11165     fractional seconds.
11166   +/
11167 static Duration fracSecsFromISOString(S)(scope const S isoString) @safe pure
11168 if (isSomeString!S)
11169 {
11170     import std.algorithm.searching : all;
11171     import std.ascii : isDigit;
11172     import std.conv : to;
11173     import std.string : representation;
11174 
11175     if (isoString.empty)
11176         return Duration.zero;
11177 
11178     auto str = isoString.representation;
11179 
11180     enforce(str[0] == '.', new DateTimeException("Invalid ISO String"));
11181     str.popFront();
11182 
11183     enforce(!str.empty && all!isDigit(str), new DateTimeException("Invalid ISO String"));
11184 
11185     dchar[7] fullISOString = void;
11186     foreach (i, ref dchar c; fullISOString)
11187     {
11188         if (i < str.length)
11189             c = str[i];
11190         else
11191             c = '0';
11192     }
11193 
11194     return hnsecs(to!int(fullISOString[]));
11195 }
11196 
11197 @safe unittest
11198 {
11199     import core.time;
11200     static void testFSInvalid(string isoString)
11201     {
11202         fracSecsFromISOString(isoString);
11203     }
11204 
11205     assertThrown!DateTimeException(testFSInvalid("."));
11206     assertThrown!DateTimeException(testFSInvalid("0."));
11207     assertThrown!DateTimeException(testFSInvalid("0"));
11208     assertThrown!DateTimeException(testFSInvalid("0000000"));
11209     assertThrown!DateTimeException(testFSInvalid("T"));
11210     assertThrown!DateTimeException(testFSInvalid("T."));
11211     assertThrown!DateTimeException(testFSInvalid(".T"));
11212     assertThrown!DateTimeException(testFSInvalid(".00000Q0"));
11213     assertThrown!DateTimeException(testFSInvalid(".000000Q"));
11214     assertThrown!DateTimeException(testFSInvalid(".0000000Q"));
11215     assertThrown!DateTimeException(testFSInvalid(".0000000000Q"));
11216 
11217     assert(fracSecsFromISOString("") == Duration.zero);
11218     assert(fracSecsFromISOString(".0000001") == hnsecs(1));
11219     assert(fracSecsFromISOString(".000001") == hnsecs(10));
11220     assert(fracSecsFromISOString(".00001") == hnsecs(100));
11221     assert(fracSecsFromISOString(".0001") == hnsecs(1000));
11222     assert(fracSecsFromISOString(".001") == hnsecs(10_000));
11223     assert(fracSecsFromISOString(".01") == hnsecs(100_000));
11224     assert(fracSecsFromISOString(".1") == hnsecs(1_000_000));
11225     assert(fracSecsFromISOString(".1000001") == hnsecs(1_000_001));
11226     assert(fracSecsFromISOString(".1001001") == hnsecs(1_001_001));
11227     assert(fracSecsFromISOString(".1071601") == hnsecs(1_071_601));
11228     assert(fracSecsFromISOString(".1271641") == hnsecs(1_271_641));
11229     assert(fracSecsFromISOString(".9999999") == hnsecs(9_999_999));
11230     assert(fracSecsFromISOString(".9999990") == hnsecs(9_999_990));
11231     assert(fracSecsFromISOString(".999999") == hnsecs(9_999_990));
11232     assert(fracSecsFromISOString(".9999900") == hnsecs(9_999_900));
11233     assert(fracSecsFromISOString(".99999") == hnsecs(9_999_900));
11234     assert(fracSecsFromISOString(".9999000") == hnsecs(9_999_000));
11235     assert(fracSecsFromISOString(".9999") == hnsecs(9_999_000));
11236     assert(fracSecsFromISOString(".9990000") == hnsecs(9_990_000));
11237     assert(fracSecsFromISOString(".999") == hnsecs(9_990_000));
11238     assert(fracSecsFromISOString(".9900000") == hnsecs(9_900_000));
11239     assert(fracSecsFromISOString(".9900") == hnsecs(9_900_000));
11240     assert(fracSecsFromISOString(".99") == hnsecs(9_900_000));
11241     assert(fracSecsFromISOString(".9000000") == hnsecs(9_000_000));
11242     assert(fracSecsFromISOString(".9") == hnsecs(9_000_000));
11243     assert(fracSecsFromISOString(".0000999") == hnsecs(999));
11244     assert(fracSecsFromISOString(".0009990") == hnsecs(9990));
11245     assert(fracSecsFromISOString(".000999") == hnsecs(9990));
11246     assert(fracSecsFromISOString(".0099900") == hnsecs(99_900));
11247     assert(fracSecsFromISOString(".00999") == hnsecs(99_900));
11248     assert(fracSecsFromISOString(".0999000") == hnsecs(999_000));
11249     assert(fracSecsFromISOString(".0999") == hnsecs(999_000));
11250     assert(fracSecsFromISOString(".00000000") == Duration.zero);
11251     assert(fracSecsFromISOString(".00000001") == Duration.zero);
11252     assert(fracSecsFromISOString(".00000009") == Duration.zero);
11253     assert(fracSecsFromISOString(".1234567890") == hnsecs(1_234_567));
11254     assert(fracSecsFromISOString(".12345678901234567890") == hnsecs(1_234_567));
11255 }
11256 
11257 
11258 /+
11259     This function is used to split out the units without getting the remaining
11260     hnsecs.
11261 
11262     Params:
11263         units  = The units to split out.
11264         hnsecs = The current total hnsecs.
11265 
11266     Returns:
11267         The split out value.
11268   +/
11269 long getUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
11270 if (validTimeUnits(units) &&
11271     CmpTimeUnits!(units, "months") < 0)
11272 {
11273     return convert!("hnsecs", units)(hnsecs);
11274 }
11275 
11276 @safe unittest
11277 {
11278     auto hnsecs = 2595000000007L;
11279     immutable days = getUnitsFromHNSecs!"days"(hnsecs);
11280     assert(days == 3);
11281     assert(hnsecs == 2595000000007L);
11282 }
11283 
11284 
11285 /+
11286     This function is used to split out the units without getting the units but
11287     just the remaining hnsecs.
11288 
11289     Params:
11290         units  = The units to split out.
11291         hnsecs = The current total hnsecs.
11292 
11293     Returns:
11294         The remaining hnsecs.
11295   +/
11296 long removeUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
11297 if (validTimeUnits(units) &&
11298     CmpTimeUnits!(units, "months") < 0)
11299 {
11300     immutable value = convert!("hnsecs", units)(hnsecs);
11301     return hnsecs - convert!(units, "hnsecs")(value);
11302 }
11303 
11304 @safe unittest
11305 {
11306     auto hnsecs = 2595000000007L;
11307     auto returned = removeUnitsFromHNSecs!"days"(hnsecs);
11308     assert(returned == 3000000007);
11309     assert(hnsecs == 2595000000007L);
11310 }
11311 
11312 
11313 /+
11314     Strips what RFC 5322, section 3.2.2 refers to as CFWS from the left-hand
11315     side of the given range (it strips comments delimited by $(D '(') and
11316     `'`') as well as folding whitespace).
11317 
11318     It is assumed that the given range contains the value of a header field and
11319     no terminating CRLF for the line (though the CRLF for folding whitespace is
11320     of course expected and stripped) and thus that the only case of CR or LF is
11321     in folding whitespace.
11322 
11323     If a comment does not terminate correctly (e.g. mismatched parens) or if the
11324     the FWS is malformed, then the range will be empty when stripCWFS is done.
11325     However, only minimal validation of the content is done (e.g. quoted pairs
11326     within a comment aren't validated beyond \$LPAREN or \$RPAREN, because
11327     they're inside a comment, and thus their value doesn't matter anyway). It's
11328     only when the content does not conform to the grammar rules for FWS and thus
11329     literally cannot be parsed that content is considered invalid, and an empty
11330     range is returned.
11331 
11332     Note that _stripCFWS is eager, not lazy. It does not create a new range.
11333     Rather, it pops off the CFWS from the range and returns it.
11334   +/
11335 R _stripCFWS(R)(R range)
11336 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
11337     (is(immutable ElementType!R == immutable char) || is(immutable ElementType!R == immutable ubyte)))
11338 {
11339     immutable e = range.length;
11340     outer: for (size_t i = 0; i < e; )
11341     {
11342         switch (range[i])
11343         {
11344             case ' ': case '\t':
11345             {
11346                 ++i;
11347                 break;
11348             }
11349             case '\r':
11350             {
11351                 if (i + 2 < e && range[i + 1] == '\n' && (range[i + 2] == ' ' || range[i + 2] == '\t'))
11352                 {
11353                     i += 3;
11354                     break;
11355                 }
11356                 break outer;
11357             }
11358             case '\n':
11359             {
11360                 if (i + 1 < e && (range[i + 1] == ' ' || range[i + 1] == '\t'))
11361                 {
11362                     i += 2;
11363                     break;
11364                 }
11365                 break outer;
11366             }
11367             case '(':
11368             {
11369                 ++i;
11370                 size_t commentLevel = 1;
11371                 while (i < e)
11372                 {
11373                     if (range[i] == '(')
11374                         ++commentLevel;
11375                     else if (range[i] == ')')
11376                     {
11377                         ++i;
11378                         if (--commentLevel == 0)
11379                             continue outer;
11380                         continue;
11381                     }
11382                     else if (range[i] == '\\')
11383                     {
11384                         if (++i == e)
11385                             break outer;
11386                     }
11387                     ++i;
11388                 }
11389                 break outer;
11390             }
11391             default: return range[i .. e];
11392         }
11393     }
11394     return range[e .. e];
11395 }
11396 
11397 @system unittest
11398 {
11399     import std.algorithm.comparison : equal;
11400     import std.algorithm.iteration : map;
11401     import std.meta : AliasSeq;
11402     import std.stdio : writeln;
11403     import std.string : representation;
11404 
11405     static foreach (cr; AliasSeq!(function(string a){return cast(ubyte[]) a;},
11406                            function(string a){return map!(b => cast(char) b)(a.representation);}))
11407     {
11408         scope(failure) writeln(typeof(cr).stringof);
11409 
11410         assert(_stripCFWS(cr("")).empty);
11411         assert(_stripCFWS(cr("\r")).empty);
11412         assert(_stripCFWS(cr("\r\n")).empty);
11413         assert(_stripCFWS(cr("\r\n ")).empty);
11414         assert(_stripCFWS(cr(" \t\r\n")).empty);
11415         assert(equal(_stripCFWS(cr(" \t\r\n hello")), cr("hello")));
11416         assert(_stripCFWS(cr(" \t\r\nhello")).empty);
11417         assert(_stripCFWS(cr(" \t\r\n\v")).empty);
11418         assert(equal(_stripCFWS(cr("\v \t\r\n\v")), cr("\v \t\r\n\v")));
11419         assert(_stripCFWS(cr("()")).empty);
11420         assert(_stripCFWS(cr("(hello world)")).empty);
11421         assert(_stripCFWS(cr("(hello world)(hello world)")).empty);
11422         assert(_stripCFWS(cr("(hello world\r\n foo\r where's\nwaldo)")).empty);
11423         assert(_stripCFWS(cr(" \t (hello \tworld\r\n foo\r where's\nwaldo)\t\t ")).empty);
11424         assert(_stripCFWS(cr("      ")).empty);
11425         assert(_stripCFWS(cr("\t\t\t")).empty);
11426         assert(_stripCFWS(cr("\t \r\n\r \n")).empty);
11427         assert(_stripCFWS(cr("(hello world) (can't find waldo) (he's lost)")).empty);
11428         assert(_stripCFWS(cr("(hello\\) world) (can't \\(find waldo) (he's \\(\\)lost)")).empty);
11429         assert(_stripCFWS(cr("(((((")).empty);
11430         assert(_stripCFWS(cr("(((()))")).empty);
11431         assert(_stripCFWS(cr("(((())))")).empty);
11432         assert(equal(_stripCFWS(cr("(((()))))")), cr(")")));
11433         assert(equal(_stripCFWS(cr(")))))")), cr(")))))")));
11434         assert(equal(_stripCFWS(cr("()))))")), cr("))))")));
11435         assert(equal(_stripCFWS(cr(" hello hello ")), cr("hello hello ")));
11436         assert(equal(_stripCFWS(cr("\thello (world)")), cr("hello (world)")));
11437         assert(equal(_stripCFWS(cr(" \r\n \\((\\))  foo")), cr("\\((\\))  foo")));
11438         assert(equal(_stripCFWS(cr(" \r\n (\\((\\)))  foo")), cr("foo")));
11439         assert(equal(_stripCFWS(cr(" \r\n (\\(()))  foo")), cr(")  foo")));
11440         assert(_stripCFWS(cr(" \r\n (((\\)))  foo")).empty);
11441 
11442         assert(_stripCFWS(cr("(hello)(hello)")).empty);
11443         assert(_stripCFWS(cr(" \r\n (hello)\r\n (hello)")).empty);
11444         assert(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n ")).empty);
11445         assert(_stripCFWS(cr("\t\t\t\t(hello)\t\t\t\t(hello)\t\t\t\t")).empty);
11446         assert(equal(_stripCFWS(cr(" \r\n (hello)\r\n (hello) \r\n hello")), cr("hello")));
11447         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n hello")), cr("hello")));
11448         assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\r\n\t(hello)\t\r\n hello")), cr("hello")));
11449         assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\t\r\n\t(hello)\t\r\n hello")), cr("hello")));
11450         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n \r\n (hello) \r\n hello")), cr("hello")));
11451         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n \r\n hello")), cr("hello")));
11452         assert(equal(_stripCFWS(cr(" \r\n \r\n (hello)\t\r\n (hello) \r\n hello")), cr("hello")));
11453         assert(equal(_stripCFWS(cr(" \r\n\t\r\n\t(hello)\t\r\n (hello) \r\n hello")), cr("hello")));
11454 
11455         assert(equal(_stripCFWS(cr(" (\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
11456         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) foo")), cr("foo")));
11457         assert(equal(_stripCFWS(cr(" (\t\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
11458         assert(equal(_stripCFWS(cr(" (\r\n\t( \r\n ) \r\n ) foo")), cr("foo")));
11459         assert(equal(_stripCFWS(cr(" ( \r\n (\t\r\n ) \r\n ) foo")), cr("foo")));
11460         assert(equal(_stripCFWS(cr(" ( \r\n (\r\n ) \r\n ) foo")), cr("foo")));
11461         assert(equal(_stripCFWS(cr(" ( \r\n (\r\n\t) \r\n ) foo")), cr("foo")));
11462         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n) \r\n ) foo")), cr("foo")));
11463         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\t\r\n ) foo")), cr("foo")));
11464         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\r\n ) foo")), cr("foo")));
11465         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n) foo")), cr("foo")));
11466         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n\t) foo")), cr("foo")));
11467         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) \r\n foo")), cr("foo")));
11468         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\t\r\n foo")), cr("foo")));
11469         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\r\n foo")), cr("foo")));
11470 
11471         assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11472         assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11473         assert(equal(_stripCFWS(cr(" (\t\r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11474         assert(equal(_stripCFWS(cr(" (\r\n \r\n\t( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11475         assert(equal(_stripCFWS(cr(" (\r\n \r\n( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11476         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n\t) \r\n ) foo")), cr("foo")));
11477         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\t\r\n ) foo")), cr("foo")));
11478         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\r\n ) foo")), cr("foo")));
11479 
11480         assert(equal(_stripCFWS(cr(" ( \r\n bar \r\n ( \r\n bar \r\n ) \r\n ) foo")), cr("foo")));
11481         assert(equal(_stripCFWS(cr(" ( \r\n () \r\n ( \r\n () \r\n ) \r\n ) foo")), cr("foo")));
11482         assert(equal(_stripCFWS(cr(" ( \r\n \\\\ \r\n ( \r\n \\\\ \r\n ) \r\n ) foo")), cr("foo")));
11483 
11484         assert(_stripCFWS(cr("(hello)(hello)")).empty);
11485         assert(_stripCFWS(cr(" \n (hello)\n (hello) \n ")).empty);
11486         assert(_stripCFWS(cr(" \n (hello) \n (hello) \n ")).empty);
11487         assert(equal(_stripCFWS(cr(" \n (hello)\n (hello) \n hello")), cr("hello")));
11488         assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n hello")), cr("hello")));
11489         assert(equal(_stripCFWS(cr("\t\n\t(hello)\n\t(hello)\t\n hello")), cr("hello")));
11490         assert(equal(_stripCFWS(cr("\t\n\t(hello)\t\n\t(hello)\t\n hello")), cr("hello")));
11491         assert(equal(_stripCFWS(cr(" \n (hello) \n \n (hello) \n hello")), cr("hello")));
11492         assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n \n hello")), cr("hello")));
11493         assert(equal(_stripCFWS(cr(" \n \n (hello)\t\n (hello) \n hello")), cr("hello")));
11494         assert(equal(_stripCFWS(cr(" \n\t\n\t(hello)\t\n (hello) \n hello")), cr("hello")));
11495     }
11496 }
11497 
11498 // This is so that we don't have to worry about std.conv.to throwing. It also
11499 // doesn't have to worry about quite as many cases as std.conv.to, since it
11500 // doesn't have to worry about a sign on the value or about whether it fits.
11501 T _convDigits(T, R)(R str)
11502 if (isIntegral!T && isSigned!T) // The constraints on R were already covered by parseRFC822DateTime.
11503 {
11504     import std.ascii : isDigit;
11505 
11506     assert(!str.empty);
11507     T num = 0;
11508     foreach (i; 0 .. str.length)
11509     {
11510         if (i != 0)
11511             num *= 10;
11512         if (!isDigit(str[i]))
11513             return -1;
11514         num += str[i] - '0';
11515     }
11516     return num;
11517 }
11518 
11519 @safe unittest
11520 {
11521     import std.conv : to;
11522     import std.range : chain, iota;
11523     foreach (i; chain(iota(0, 101), [250, 999, 1000, 1001, 2345, 9999]))
11524     {
11525         assert(_convDigits!int(to!string(i)) == i, i.to!string);
11526     }
11527     foreach (str; ["-42", "+42", "1a", "1 ", " ", " 42 "])
11528     {
11529         assert(_convDigits!int(str) == -1, str);
11530     }
11531 }
11532 
11533 
11534 // NOTE: all the non-simple array literals are wrapped in functions, because
11535 // otherwise importing causes re-evaluation of the static initializers using
11536 // CTFE with unittests enabled
11537 version (StdUnittest)
11538 {
11539 private @safe:
11540     // Variables to help in testing.
11541     Duration currLocalDiffFromUTC;
11542     immutable (TimeZone)[] testTZs;
11543 
11544     // All of these helper arrays are sorted in ascending order.
11545     auto testYearsBC = [-1999, -1200, -600, -4, -1, 0];
11546     auto testYearsAD = [1, 4, 1000, 1999, 2000, 2012];
11547 
11548     // I'd use a Tuple, but I get forward reference errors if I try.
11549     struct MonthDay
11550     {
11551         Month month;
11552         short day;
11553 
11554         this(int m, short d)
11555         {
11556             month = cast(Month) m;
11557             day = d;
11558         }
11559     }
11560 
11561     MonthDay[] testMonthDays()
11562     {
11563        static result = [MonthDay(1, 1),
11564                                 MonthDay(1, 2),
11565                                 MonthDay(3, 17),
11566                                 MonthDay(7, 4),
11567                                 MonthDay(10, 27),
11568                                 MonthDay(12, 30),
11569                                 MonthDay(12, 31)];
11570        return result;
11571     }
11572 
11573     auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31];
11574 
11575     TimeOfDay[] testTODs()
11576     {
11577        static result = [TimeOfDay(0, 0, 0),
11578                      TimeOfDay(0, 0, 1),
11579                      TimeOfDay(0, 1, 0),
11580                      TimeOfDay(1, 0, 0),
11581                      TimeOfDay(13, 13, 13),
11582                      TimeOfDay(23, 59, 59)];
11583        return result;
11584     }
11585 
11586     auto testHours = [0, 1, 12, 22, 23];
11587     auto testMinSecs = [0, 1, 30, 58, 59];
11588 
11589     // Throwing exceptions is incredibly expensive, so we want to use a smaller
11590     // set of values for tests using assertThrown.
11591     TimeOfDay[] testTODsThrown()
11592     {
11593        static result = [TimeOfDay(0, 0, 0),
11594                            TimeOfDay(13, 13, 13),
11595                            TimeOfDay(23, 59, 59)];
11596        return result;
11597     }
11598 
11599     Date[] testDatesBC;
11600     Date[] testDatesAD;
11601 
11602     DateTime[] testDateTimesBC;
11603     DateTime[] testDateTimesAD;
11604 
11605     Duration[] testFracSecs;
11606 
11607     SysTime[] testSysTimesBC;
11608     SysTime[] testSysTimesAD;
11609 
11610     // I'd use a Tuple, but I get forward reference errors if I try.
11611     struct GregDay { int day; Date date; }
11612     GregDay[] testGregDaysBC()
11613     {
11614        static result = [GregDay(-1_373_427, Date(-3760, 9, 7)), // Start of the Hebrew Calendar
11615                            GregDay(-735_233, Date(-2012, 1, 1)),
11616                            GregDay(-735_202, Date(-2012, 2, 1)),
11617                            GregDay(-735_175, Date(-2012, 2, 28)),
11618                            GregDay(-735_174, Date(-2012, 2, 29)),
11619                            GregDay(-735_173, Date(-2012, 3, 1)),
11620                            GregDay(-734_502, Date(-2010, 1, 1)),
11621                            GregDay(-734_472, Date(-2010, 1, 31)),
11622                            GregDay(-734_471, Date(-2010, 2, 1)),
11623                            GregDay(-734_444, Date(-2010, 2, 28)),
11624                            GregDay(-734_443, Date(-2010, 3, 1)),
11625                            GregDay(-734_413, Date(-2010, 3, 31)),
11626                            GregDay(-734_412, Date(-2010, 4, 1)),
11627                            GregDay(-734_383, Date(-2010, 4, 30)),
11628                            GregDay(-734_382, Date(-2010, 5, 1)),
11629                            GregDay(-734_352, Date(-2010, 5, 31)),
11630                            GregDay(-734_351, Date(-2010, 6, 1)),
11631                            GregDay(-734_322, Date(-2010, 6, 30)),
11632                            GregDay(-734_321, Date(-2010, 7, 1)),
11633                            GregDay(-734_291, Date(-2010, 7, 31)),
11634                            GregDay(-734_290, Date(-2010, 8, 1)),
11635                            GregDay(-734_260, Date(-2010, 8, 31)),
11636                            GregDay(-734_259, Date(-2010, 9, 1)),
11637                            GregDay(-734_230, Date(-2010, 9, 30)),
11638                            GregDay(-734_229, Date(-2010, 10, 1)),
11639                            GregDay(-734_199, Date(-2010, 10, 31)),
11640                            GregDay(-734_198, Date(-2010, 11, 1)),
11641                            GregDay(-734_169, Date(-2010, 11, 30)),
11642                            GregDay(-734_168, Date(-2010, 12, 1)),
11643                            GregDay(-734_139, Date(-2010, 12, 30)),
11644                            GregDay(-734_138, Date(-2010, 12, 31)),
11645                            GregDay(-731_215, Date(-2001, 1, 1)),
11646                            GregDay(-730_850, Date(-2000, 1, 1)),
11647                            GregDay(-730_849, Date(-2000, 1, 2)),
11648                            GregDay(-730_486, Date(-2000, 12, 30)),
11649                            GregDay(-730_485, Date(-2000, 12, 31)),
11650                            GregDay(-730_484, Date(-1999, 1, 1)),
11651                            GregDay(-694_690, Date(-1901, 1, 1)),
11652                            GregDay(-694_325, Date(-1900, 1, 1)),
11653                            GregDay(-585_118, Date(-1601, 1, 1)),
11654                            GregDay(-584_753, Date(-1600, 1, 1)),
11655                            GregDay(-584_388, Date(-1600, 12, 31)),
11656                            GregDay(-584_387, Date(-1599, 1, 1)),
11657                            GregDay(-365_972, Date(-1001, 1, 1)),
11658                            GregDay(-365_607, Date(-1000, 1, 1)),
11659                            GregDay(-183_351, Date(-501, 1, 1)),
11660                            GregDay(-182_986, Date(-500, 1, 1)),
11661                            GregDay(-182_621, Date(-499, 1, 1)),
11662                            GregDay(-146_827, Date(-401, 1, 1)),
11663                            GregDay(-146_462, Date(-400, 1, 1)),
11664                            GregDay(-146_097, Date(-400, 12, 31)),
11665                            GregDay(-110_302, Date(-301, 1, 1)),
11666                            GregDay(-109_937, Date(-300, 1, 1)),
11667                            GregDay(-73_778, Date(-201, 1, 1)),
11668                            GregDay(-73_413, Date(-200, 1, 1)),
11669                            GregDay(-38_715, Date(-105, 1, 1)),
11670                            GregDay(-37_254, Date(-101, 1, 1)),
11671                            GregDay(-36_889, Date(-100, 1, 1)),
11672                            GregDay(-36_524, Date(-99, 1, 1)),
11673                            GregDay(-36_160, Date(-99, 12, 31)),
11674                            GregDay(-35_794, Date(-97, 1, 1)),
11675                            GregDay(-18_627, Date(-50, 1, 1)),
11676                            GregDay(-18_262, Date(-49, 1, 1)),
11677                            GregDay(-3652, Date(-9, 1, 1)),
11678                            GregDay(-2191, Date(-5, 1, 1)),
11679                            GregDay(-1827, Date(-5, 12, 31)),
11680                            GregDay(-1826, Date(-4, 1, 1)),
11681                            GregDay(-1825, Date(-4, 1, 2)),
11682                            GregDay(-1462, Date(-4, 12, 30)),
11683                            GregDay(-1461, Date(-4, 12, 31)),
11684                            GregDay(-1460, Date(-3, 1, 1)),
11685                            GregDay(-1096, Date(-3, 12, 31)),
11686                            GregDay(-1095, Date(-2, 1, 1)),
11687                            GregDay(-731, Date(-2, 12, 31)),
11688                            GregDay(-730, Date(-1, 1, 1)),
11689                            GregDay(-367, Date(-1, 12, 30)),
11690                            GregDay(-366, Date(-1, 12, 31)),
11691                            GregDay(-365, Date(0, 1, 1)),
11692                            GregDay(-31, Date(0, 11, 30)),
11693                            GregDay(-30, Date(0, 12, 1)),
11694                            GregDay(-1, Date(0, 12, 30)),
11695                            GregDay(0, Date(0, 12, 31))];
11696        return result;
11697     }
11698 
11699     GregDay[] testGregDaysAD()
11700     {
11701        static result = [GregDay(1, Date(1, 1, 1)),
11702                            GregDay(2, Date(1, 1, 2)),
11703                            GregDay(32, Date(1, 2, 1)),
11704                            GregDay(365, Date(1, 12, 31)),
11705                            GregDay(366, Date(2, 1, 1)),
11706                            GregDay(731, Date(3, 1, 1)),
11707                            GregDay(1096, Date(4, 1, 1)),
11708                            GregDay(1097, Date(4, 1, 2)),
11709                            GregDay(1460, Date(4, 12, 30)),
11710                            GregDay(1461, Date(4, 12, 31)),
11711                            GregDay(1462, Date(5, 1, 1)),
11712                            GregDay(17_898, Date(50, 1, 1)),
11713                            GregDay(35_065, Date(97, 1, 1)),
11714                            GregDay(36_160, Date(100, 1, 1)),
11715                            GregDay(36_525, Date(101, 1, 1)),
11716                            GregDay(37_986, Date(105, 1, 1)),
11717                            GregDay(72_684, Date(200, 1, 1)),
11718                            GregDay(73_049, Date(201, 1, 1)),
11719                            GregDay(109_208, Date(300, 1, 1)),
11720                            GregDay(109_573, Date(301, 1, 1)),
11721                            GregDay(145_732, Date(400, 1, 1)),
11722                            GregDay(146_098, Date(401, 1, 1)),
11723                            GregDay(182_257, Date(500, 1, 1)),
11724                            GregDay(182_622, Date(501, 1, 1)),
11725                            GregDay(364_878, Date(1000, 1, 1)),
11726                            GregDay(365_243, Date(1001, 1, 1)),
11727                            GregDay(584_023, Date(1600, 1, 1)),
11728                            GregDay(584_389, Date(1601, 1, 1)),
11729                            GregDay(693_596, Date(1900, 1, 1)),
11730                            GregDay(693_961, Date(1901, 1, 1)),
11731                            GregDay(729_755, Date(1999, 1, 1)),
11732                            GregDay(730_120, Date(2000, 1, 1)),
11733                            GregDay(730_121, Date(2000, 1, 2)),
11734                            GregDay(730_484, Date(2000, 12, 30)),
11735                            GregDay(730_485, Date(2000, 12, 31)),
11736                            GregDay(730_486, Date(2001, 1, 1)),
11737                            GregDay(733_773, Date(2010, 1, 1)),
11738                            GregDay(733_774, Date(2010, 1, 2)),
11739                            GregDay(733_803, Date(2010, 1, 31)),
11740                            GregDay(733_804, Date(2010, 2, 1)),
11741                            GregDay(733_831, Date(2010, 2, 28)),
11742                            GregDay(733_832, Date(2010, 3, 1)),
11743                            GregDay(733_862, Date(2010, 3, 31)),
11744                            GregDay(733_863, Date(2010, 4, 1)),
11745                            GregDay(733_892, Date(2010, 4, 30)),
11746                            GregDay(733_893, Date(2010, 5, 1)),
11747                            GregDay(733_923, Date(2010, 5, 31)),
11748                            GregDay(733_924, Date(2010, 6, 1)),
11749                            GregDay(733_953, Date(2010, 6, 30)),
11750                            GregDay(733_954, Date(2010, 7, 1)),
11751                            GregDay(733_984, Date(2010, 7, 31)),
11752                            GregDay(733_985, Date(2010, 8, 1)),
11753                            GregDay(734_015, Date(2010, 8, 31)),
11754                            GregDay(734_016, Date(2010, 9, 1)),
11755                            GregDay(734_045, Date(2010, 9, 30)),
11756                            GregDay(734_046, Date(2010, 10, 1)),
11757                            GregDay(734_076, Date(2010, 10, 31)),
11758                            GregDay(734_077, Date(2010, 11, 1)),
11759                            GregDay(734_106, Date(2010, 11, 30)),
11760                            GregDay(734_107, Date(2010, 12, 1)),
11761                            GregDay(734_136, Date(2010, 12, 30)),
11762                            GregDay(734_137, Date(2010, 12, 31)),
11763                            GregDay(734_503, Date(2012, 1, 1)),
11764                            GregDay(734_534, Date(2012, 2, 1)),
11765                            GregDay(734_561, Date(2012, 2, 28)),
11766                            GregDay(734_562, Date(2012, 2, 29)),
11767                            GregDay(734_563, Date(2012, 3, 1)),
11768                            GregDay(734_858, Date(2012, 12, 21))];
11769        return result;
11770     }
11771 
11772     // I'd use a Tuple, but I get forward reference errors if I try.
11773     struct DayOfYear { int day; MonthDay md; }
11774     DayOfYear[] testDaysOfYear()
11775     {
11776        static result = [DayOfYear(1, MonthDay(1, 1)),
11777                            DayOfYear(2, MonthDay(1, 2)),
11778                            DayOfYear(3, MonthDay(1, 3)),
11779                            DayOfYear(31, MonthDay(1, 31)),
11780                            DayOfYear(32, MonthDay(2, 1)),
11781                            DayOfYear(59, MonthDay(2, 28)),
11782                            DayOfYear(60, MonthDay(3, 1)),
11783                            DayOfYear(90, MonthDay(3, 31)),
11784                            DayOfYear(91, MonthDay(4, 1)),
11785                            DayOfYear(120, MonthDay(4, 30)),
11786                            DayOfYear(121, MonthDay(5, 1)),
11787                            DayOfYear(151, MonthDay(5, 31)),
11788                            DayOfYear(152, MonthDay(6, 1)),
11789                            DayOfYear(181, MonthDay(6, 30)),
11790                            DayOfYear(182, MonthDay(7, 1)),
11791                            DayOfYear(212, MonthDay(7, 31)),
11792                            DayOfYear(213, MonthDay(8, 1)),
11793                            DayOfYear(243, MonthDay(8, 31)),
11794                            DayOfYear(244, MonthDay(9, 1)),
11795                            DayOfYear(273, MonthDay(9, 30)),
11796                            DayOfYear(274, MonthDay(10, 1)),
11797                            DayOfYear(304, MonthDay(10, 31)),
11798                            DayOfYear(305, MonthDay(11, 1)),
11799                            DayOfYear(334, MonthDay(11, 30)),
11800                            DayOfYear(335, MonthDay(12, 1)),
11801                            DayOfYear(363, MonthDay(12, 29)),
11802                            DayOfYear(364, MonthDay(12, 30)),
11803                            DayOfYear(365, MonthDay(12, 31))];
11804        return result;
11805     }
11806 
11807     DayOfYear[] testDaysOfLeapYear()
11808     {
11809        static result = [DayOfYear(1, MonthDay(1, 1)),
11810                                DayOfYear(2, MonthDay(1, 2)),
11811                                DayOfYear(3, MonthDay(1, 3)),
11812                                DayOfYear(31, MonthDay(1, 31)),
11813                                DayOfYear(32, MonthDay(2, 1)),
11814                                DayOfYear(59, MonthDay(2, 28)),
11815                                DayOfYear(60, MonthDay(2, 29)),
11816                                DayOfYear(61, MonthDay(3, 1)),
11817                                DayOfYear(91, MonthDay(3, 31)),
11818                                DayOfYear(92, MonthDay(4, 1)),
11819                                DayOfYear(121, MonthDay(4, 30)),
11820                                DayOfYear(122, MonthDay(5, 1)),
11821                                DayOfYear(152, MonthDay(5, 31)),
11822                                DayOfYear(153, MonthDay(6, 1)),
11823                                DayOfYear(182, MonthDay(6, 30)),
11824                                DayOfYear(183, MonthDay(7, 1)),
11825                                DayOfYear(213, MonthDay(7, 31)),
11826                                DayOfYear(214, MonthDay(8, 1)),
11827                                DayOfYear(244, MonthDay(8, 31)),
11828                                DayOfYear(245, MonthDay(9, 1)),
11829                                DayOfYear(274, MonthDay(9, 30)),
11830                                DayOfYear(275, MonthDay(10, 1)),
11831                                DayOfYear(305, MonthDay(10, 31)),
11832                                DayOfYear(306, MonthDay(11, 1)),
11833                                DayOfYear(335, MonthDay(11, 30)),
11834                                DayOfYear(336, MonthDay(12, 1)),
11835                                DayOfYear(364, MonthDay(12, 29)),
11836                                DayOfYear(365, MonthDay(12, 30)),
11837                                DayOfYear(366, MonthDay(12, 31))];
11838        return result;
11839     }
11840 
11841     void initializeTests()
11842     {
11843         import std.algorithm.sorting : sort;
11844         import std.typecons : Rebindable;
11845         immutable lt = LocalTime().utcToTZ(0);
11846         currLocalDiffFromUTC = dur!"hnsecs"(lt);
11847 
11848         version (Posix)
11849         {
11850             import std.datetime.timezone : PosixTimeZone;
11851             immutable otherTZ = lt < 0 ? PosixTimeZone.getTimeZone("Australia/Sydney")
11852                                        : PosixTimeZone.getTimeZone("America/Denver");
11853         }
11854         else version (Windows)
11855         {
11856             import std.datetime.timezone : WindowsTimeZone;
11857             immutable otherTZ = lt < 0 ? WindowsTimeZone.getTimeZone("AUS Eastern Standard Time")
11858                                        : WindowsTimeZone.getTimeZone("Mountain Standard Time");
11859         }
11860 
11861         immutable ot = otherTZ.utcToTZ(0);
11862 
11863         auto diffs = [0L, lt, ot];
11864         auto diffAA = [0L : Rebindable!(immutable TimeZone)(UTC())];
11865         diffAA[lt] = Rebindable!(immutable TimeZone)(LocalTime());
11866         diffAA[ot] = Rebindable!(immutable TimeZone)(otherTZ);
11867 
11868         sort(diffs);
11869         testTZs = [diffAA[diffs[0]], diffAA[diffs[1]], diffAA[diffs[2]]];
11870 
11871         testFracSecs = [Duration.zero, hnsecs(1), hnsecs(5007), hnsecs(9_999_999)];
11872 
11873         foreach (year; testYearsBC)
11874         {
11875             foreach (md; testMonthDays)
11876                 testDatesBC ~= Date(year, md.month, md.day);
11877         }
11878 
11879         foreach (year; testYearsAD)
11880         {
11881             foreach (md; testMonthDays)
11882                 testDatesAD ~= Date(year, md.month, md.day);
11883         }
11884 
11885         foreach (dt; testDatesBC)
11886         {
11887             foreach (tod; testTODs)
11888                 testDateTimesBC ~= DateTime(dt, tod);
11889         }
11890 
11891         foreach (dt; testDatesAD)
11892         {
11893             foreach (tod; testTODs)
11894                 testDateTimesAD ~= DateTime(dt, tod);
11895         }
11896 
11897         foreach (dt; testDateTimesBC)
11898         {
11899             foreach (tz; testTZs)
11900             {
11901                 foreach (fs; testFracSecs)
11902                     testSysTimesBC ~= SysTime(dt, fs, tz);
11903             }
11904         }
11905 
11906         foreach (dt; testDateTimesAD)
11907         {
11908             foreach (tz; testTZs)
11909             {
11910                 foreach (fs; testFracSecs)
11911                     testSysTimesAD ~= SysTime(dt, fs, tz);
11912             }
11913         }
11914     }
11915 }