1 // Written in the D programming language
2 
3 /++
4 
5 $(SCRIPT inhibitQuickIndex = 1;)
6 $(DIVC quickindex,
7 $(BOOKTABLE,
8 $(TR $(TH Category) $(TH Functions))
9 $(TR $(TD Types) $(TD
10     $(LREF Clock)
11     $(LREF SysTime)
12     $(LREF DosFileTime)
13 ))
14 $(TR $(TD Conversion) $(TD
15     $(LREF parseRFC822DateTime)
16     $(LREF DosFileTimeToSysTime)
17     $(LREF FILETIMEToStdTime)
18     $(LREF FILETIMEToSysTime)
19     $(LREF stdTimeToFILETIME)
20     $(LREF stdTimeToUnixTime)
21     $(LREF SYSTEMTIMEToSysTime)
22     $(LREF SysTimeToDosFileTime)
23     $(LREF SysTimeToFILETIME)
24     $(LREF SysTimeToSYSTEMTIME)
25     $(LREF unixTimeToStdTime)
26 ))
27 ))
28 
29     License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
30     Authors:   $(HTTP jmdavisprog.com, Jonathan M Davis)
31     Source:    $(PHOBOSSRC std/datetime/systime.d)
32 +/
33 module std.datetime.systime;
34 
35 version (OSX)
36     version = Darwin;
37 else version (iOS)
38     version = Darwin;
39 else version (TVOS)
40     version = Darwin;
41 else version (WatchOS)
42     version = Darwin;
43 
44 /// Get the current time as a $(LREF SysTime)
45 @safe unittest
46 {
47     import std.datetime.timezone : LocalTime;
48     SysTime today = Clock.currTime();
49     assert(today.timezone is LocalTime());
50 }
51 
52 /// Construct a $(LREF SysTime) from a ISO time string
53 @safe unittest
54 {
55     import std.datetime.date : DateTime;
56     import std.datetime.timezone : UTC;
57 
58     auto st = SysTime.fromISOExtString("2018-01-01T10:30:00Z");
59     assert(st == SysTime(DateTime(2018, 1, 1, 10, 30, 0), UTC()));
60 }
61 
62 /// Make a specific point in time in the New York timezone
63 @safe unittest
64 {
65     import core.time : hours;
66     import std.datetime.date : DateTime;
67     import std.datetime.timezone : SimpleTimeZone;
68 
69     auto ny = SysTime(
70         DateTime(2018, 1, 1, 10, 30, 0),
71         new immutable SimpleTimeZone(-5.hours, "America/New_York")
72     );
73 
74     // ISO standard time strings
75     assert(ny.toISOString() == "20180101T103000-05:00");
76     assert(ny.toISOExtString() == "2018-01-01T10:30:00-05:00");
77 }
78 
79 // Note: reconsider using specific imports below after
80 // https://issues.dlang.org/show_bug.cgi?id=17630 has been fixed
81 import core.time;// : ClockType, convert, dur, Duration, seconds, TimeException;
82 import std.datetime.date;// : _monthNames, AllowDayOverflow, CmpTimeUnits, Date,
83     //DateTime, DateTimeException, DayOfWeek, enforceValid, getDayOfWeek, maxDay,
84     //Month, splitUnitsFromHNSecs, TimeOfDay, validTimeUnits, yearIsLeapYear;
85 import std.datetime.timezone;// : LocalTime, SimpleTimeZone, TimeZone, UTC;
86 import std.exception : enforce;
87 import std.format : format;
88 import std.range.primitives;
89 import std.traits : isIntegral, isSigned, isSomeString, isNarrowString;
90 
91 version (Windows)
92 {
93     import core.stdc.time : time_t;
94     import core.sys.windows.winbase;
95     import core.sys.windows.winnt;
96     import core.sys.windows.winsock2;
97 }
98 else version (Posix)
99 {
100     import core.sys.posix.signal : timespec;
101     import core.sys.posix.sys.types : time_t;
102 }
103 
104 version (StdUnittest)
105 {
106     import core.exception : AssertError;
107     import std.exception : assertThrown;
108 }
109 
110 
111 @safe unittest
112 {
113     initializeTests();
114 }
115 
116 version (unittest) private bool clockSupported(ClockType c)
117 {
118     // Skip unsupported clocks on older linux kernels, assume that only
119     // CLOCK_MONOTONIC and CLOCK_REALTIME exist, as that is the lowest
120     // common denominator supported by all versions of Linux pre-2.6.12.
121     version (Linux_Pre_2639)
122         return c == ClockType.normal || c == ClockType.precise;
123     else
124         return true;
125 }
126 
127 /++
128     Effectively a namespace to make it clear that the methods it contains are
129     getting the time from the system clock. It cannot be instantiated.
130  +/
131 final class Clock
132 {
133 public:
134 
135     /++
136         Returns the current time in the given time zone.
137 
138         Params:
139             clockType = The $(REF ClockType, core,time) indicates which system
140                         clock to use to get the current time. Very few programs
141                         need to use anything other than the default.
142             tz = The time zone for the SysTime that's returned.
143 
144         Throws:
145             $(REF DateTimeException,std,datetime,date) if it fails to get the
146             time.
147       +/
148     static SysTime currTime(ClockType clockType = ClockType.normal)(immutable TimeZone tz = LocalTime()) @safe
149     {
150         return SysTime(currStdTime!clockType, tz);
151     }
152 
153     @safe unittest
154     {
155         import std.format : format;
156         import core.time;
157         assert(currTime().timezone is LocalTime());
158         assert(currTime(UTC()).timezone is UTC());
159 
160         // core.stdc.time.time does not always use unix time on Windows systems.
161         // In particular, dmc does not use unix time. If we can guarantee that
162         // the MS runtime uses unix time, then we may be able run this test
163         // then, but for now, we're just not going to run this test on Windows.
164         version (Posix)
165         {
166             static import core.stdc.time;
167             static import std.math;
168             immutable unixTimeD = currTime().toUnixTime();
169             immutable unixTimeC = core.stdc.time.time(null);
170             assert(std.math.abs(unixTimeC - unixTimeD) <= 2);
171         }
172 
173         auto norm1 = Clock.currTime;
174         auto norm2 = Clock.currTime(UTC());
175         assert(norm1 <= norm2, format("%s %s", norm1, norm2));
176         assert(abs(norm1 - norm2) <= seconds(2));
177 
178         import std.meta : AliasSeq;
179         static foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
180         {{
181             static if (clockSupported(ct))
182             {
183                 auto value1 = Clock.currTime!ct;
184                 auto value2 = Clock.currTime!ct(UTC());
185                 assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
186                 assert(abs(value1 - value2) <= seconds(2), format("ClockType.%s", ct));
187             }
188         }}
189     }
190 
191 
192     /++
193         Returns the number of hnsecs since midnight, January 1st, 1 A.D. for the
194         current time.
195 
196         Params:
197             clockType = The $(REF ClockType, core,time) indicates which system
198                         clock to use to get the current time. Very few programs
199                         need to use anything other than the default.
200 
201         Throws:
202             $(REF DateTimeException,std,datetime,date) if it fails to get the
203             time.
204       +/
205     static @property long currStdTime(ClockType clockType = ClockType.normal)() @trusted
206     {
207         static if (clockType != ClockType.coarse &&
208                    clockType != ClockType.normal &&
209                    clockType != ClockType.precise &&
210                    clockType != ClockType.second)
211         {
212             static assert(0, format("ClockType.%s is not supported by Clock.currTime or Clock.currStdTime", clockType));
213         }
214 
215         version (Windows)
216         {
217             FILETIME fileTime;
218             GetSystemTimeAsFileTime(&fileTime);
219             immutable result = FILETIMEToStdTime(&fileTime);
220             static if (clockType == ClockType.second)
221             {
222                 // Ideally, this would use core.std.time.time, but the C runtime
223                 // has to be using unix time for that to work, and that's not
224                 // guaranteed on Windows. Digital Mars does not use unix time.
225                 // MS may or may not. If it does, then this can be made to use
226                 // core.stdc.time for MS, but for now, we'll leave it like this.
227                 return convert!("seconds", "hnsecs")(convert!("hnsecs", "seconds")(result));
228             }
229             else
230                 return result;
231         }
232         else version (Posix)
233         {
234             static import core.stdc.time;
235             enum hnsecsToUnixEpoch = unixTimeToStdTime(0);
236 
237             version (Darwin)
238             {
239                 static if (clockType == ClockType.second)
240                     return unixTimeToStdTime(core.stdc.time.time(null));
241                 else
242                 {
243                     import core.sys.posix.sys.time : gettimeofday, timeval;
244                     timeval tv = void;
245                     // Posix gettimeofday called with a valid timeval address
246                     // and a null second parameter doesn't fail.
247                     gettimeofday(&tv, null);
248                     return convert!("seconds", "hnsecs")(tv.tv_sec) +
249                            tv.tv_usec * 10 +
250                            hnsecsToUnixEpoch;
251                 }
252             }
253             else version (linux)
254             {
255                 static if (clockType == ClockType.second)
256                     return unixTimeToStdTime(core.stdc.time.time(null));
257                 else
258                 {
259                     import core.sys.linux.time : CLOCK_REALTIME_COARSE;
260                     import core.sys.posix.time : clock_gettime, CLOCK_REALTIME;
261                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_COARSE;
262                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
263                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
264                     else static assert(0, "Previous static if is wrong.");
265                     timespec ts = void;
266                     immutable error = clock_gettime(clockArg, &ts);
267                     // Posix clock_gettime called with a valid address and valid clock_id is only
268                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
269                     // is long or larger overflow won't happen before 292 billion years A.D.
270                     static if (ts.tv_sec.max < long.max)
271                     {
272                         if (error)
273                             throw new TimeException("Call to clock_gettime() failed");
274                     }
275                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
276                            ts.tv_nsec / 100 +
277                            hnsecsToUnixEpoch;
278                 }
279             }
280             else version (FreeBSD)
281             {
282                 import core.sys.freebsd.time : clock_gettime, CLOCK_REALTIME,
283                     CLOCK_REALTIME_FAST, CLOCK_REALTIME_PRECISE, CLOCK_SECOND;
284                 static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_FAST;
285                 else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
286                 else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE;
287                 else static if (clockType == ClockType.second)  alias clockArg = CLOCK_SECOND;
288                 else static assert(0, "Previous static if is wrong.");
289                 timespec ts = void;
290                 immutable error = clock_gettime(clockArg, &ts);
291                 // Posix clock_gettime called with a valid address and valid clock_id is only
292                 // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
293                 // is long or larger overflow won't happen before 292 billion years A.D.
294                 static if (ts.tv_sec.max < long.max)
295                 {
296                     if (error)
297                         throw new TimeException("Call to clock_gettime() failed");
298                 }
299                 return convert!("seconds", "hnsecs")(ts.tv_sec) +
300                        ts.tv_nsec / 100 +
301                        hnsecsToUnixEpoch;
302             }
303             else version (NetBSD)
304             {
305                 static if (clockType == ClockType.second)
306                     return unixTimeToStdTime(core.stdc.time.time(null));
307                 else
308                 {
309                     import core.sys.netbsd.time : clock_gettime, CLOCK_REALTIME;
310                     timespec ts = void;
311                     immutable error = clock_gettime(CLOCK_REALTIME, &ts);
312                     // Posix clock_gettime called with a valid address and valid clock_id is only
313                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
314                     // is long or larger overflow won't happen before 292 billion years A.D.
315                     static if (ts.tv_sec.max < long.max)
316                     {
317                         if (error)
318                             throw new TimeException("Call to clock_gettime() failed");
319                     }
320                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
321                            ts.tv_nsec / 100 +
322                            hnsecsToUnixEpoch;
323                 }
324             }
325             else version (OpenBSD)
326             {
327                 static if (clockType == ClockType.second)
328                     return unixTimeToStdTime(core.stdc.time.time(null));
329                 else
330                 {
331                     import core.sys.openbsd.time : clock_gettime, CLOCK_REALTIME;
332                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME;
333                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
334                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
335                     else static assert(0, "Previous static if is wrong.");
336                     timespec ts;
337                     if (clock_gettime(clockArg, &ts) != 0)
338                         throw new TimeException("Call to clock_gettime() failed");
339                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
340                            ts.tv_nsec / 100 +
341                            hnsecsToUnixEpoch;
342                 }
343             }
344             else version (DragonFlyBSD)
345             {
346                 import core.sys.dragonflybsd.time : clock_gettime, CLOCK_REALTIME,
347                     CLOCK_REALTIME_FAST, CLOCK_REALTIME_PRECISE, CLOCK_SECOND;
348                 static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_FAST;
349                 else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
350                 else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE;
351                 else static if (clockType == ClockType.second)  alias clockArg = CLOCK_SECOND;
352                 else static assert(0, "Previous static if is wrong.");
353                 timespec ts = void;
354                 immutable error = clock_gettime(clockArg, &ts);
355                 // Posix clock_gettime called with a valid address and valid clock_id is only
356                 // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
357                 // is long or larger overflow won't happen before 292 billion years A.D.
358                 static if (ts.tv_sec.max < long.max)
359                 {
360                     if (error)
361                         throw new TimeException("Call to clock_gettime() failed");
362                 }
363                 return convert!("seconds", "hnsecs")(ts.tv_sec) +
364                        ts.tv_nsec / 100 +
365                        hnsecsToUnixEpoch;
366             }
367             else version (Solaris)
368             {
369                 static if (clockType == ClockType.second)
370                     return unixTimeToStdTime(core.stdc.time.time(null));
371                 else
372                 {
373                     import core.sys.solaris.time : clock_gettime, CLOCK_REALTIME;
374                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME;
375                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
376                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
377                     else static assert(0, "Previous static if is wrong.");
378                     timespec ts = void;
379                     immutable error = clock_gettime(clockArg, &ts);
380                     // Posix clock_gettime called with a valid address and valid clock_id is only
381                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
382                     // is long or larger overflow won't happen before 292 billion years A.D.
383                     static if (ts.tv_sec.max < long.max)
384                     {
385                         if (error)
386                             throw new TimeException("Call to clock_gettime() failed");
387                     }
388                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
389                            ts.tv_nsec / 100 +
390                            hnsecsToUnixEpoch;
391                 }
392             }
393             else version (Hurd)
394             {
395                 static if (clockType == ClockType.second)
396                     return unixTimeToStdTime(core.stdc.time.time(null));
397                 else
398                 {
399                     import core.sys.hurd.time : CLOCK_REALTIME_COARSE;
400                     import core.sys.posix.time : clock_gettime, CLOCK_REALTIME;
401                     static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_COARSE;
402                     else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
403                     else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
404                     else static assert(0, "Previous static if is wrong.");
405                     timespec ts = void;
406                     immutable error = clock_gettime(clockArg, &ts);
407                     // Posix clock_gettime called with a valid address and valid clock_id is only
408                     // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
409                     // is long or larger overflow won't happen before 292 billion years A.D.
410                     static if (ts.tv_sec.max < long.max)
411                     {
412                         if (error)
413                             throw new TimeException("Call to clock_gettime() failed");
414                     }
415                     return convert!("seconds", "hnsecs")(ts.tv_sec) +
416                            ts.tv_nsec / 100 +
417                            hnsecsToUnixEpoch;
418                 }
419             }
420             else static assert(0, "Unsupported OS");
421         }
422         else static assert(0, "Unsupported OS");
423     }
424 
425     @safe unittest
426     {
427         import std.format : format;
428         import std.math.algebraic : abs;
429         import std.meta : AliasSeq;
430         enum limit = convert!("seconds", "hnsecs")(2);
431 
432         auto norm1 = Clock.currStdTime;
433         auto norm2 = Clock.currStdTime;
434         assert(norm1 <= norm2, format("%s %s", norm1, norm2));
435         assert(abs(norm1 - norm2) <= limit);
436 
437         static foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
438         {{
439             static if (clockSupported(ct))
440             {
441                 auto value1 = Clock.currStdTime!ct;
442                 auto value2 = Clock.currStdTime!ct;
443                 assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
444                 assert(abs(value1 - value2) <= limit);
445             }
446         }}
447     }
448 
449 
450 private:
451 
452     @disable this();
453 }
454 
455 /// Get the current time as a $(LREF SysTime)
456 @safe unittest
457 {
458     import std.datetime.timezone : LocalTime;
459     SysTime today = Clock.currTime();
460     assert(today.timezone is LocalTime());
461 }
462 
463 
464 /++
465     `SysTime` is the type used to get the current time from the
466     system or doing anything that involves time zones. Unlike
467     $(REF DateTime,std,datetime,date), the time zone is an integral part of
468     `SysTime` (though for local time applications, time zones can be ignored
469     and it will work, since it defaults to using the local time zone). It holds
470     its internal time in std time (hnsecs since midnight, January 1st, 1 A.D.
471     UTC), so it interfaces well with the system time. However, that means that,
472     unlike $(REF DateTime,std,datetime,date), it is not optimized for
473     calendar-based operations, and getting individual units from it such as
474     years or days is going to involve conversions and be less efficient.
475 
476     An $(I hnsec) (hecto-nanosecond) is 100 nanoseconds. There are 10,000,000 hnsecs in a second.
477 
478     For calendar-based operations that don't
479     care about time zones, then $(REF DateTime,std,datetime,date) would be
480     the type to use. For system time, use `SysTime`.
481 
482     $(LREF Clock.currTime) will return the current time as a `SysTime`.
483     To convert a `SysTime` to a $(REF Date,std,datetime,date) or
484     $(REF DateTime,std,datetime,date), simply cast it. To convert a
485     $(REF Date,std,datetime,date) or $(REF DateTime,std,datetime,date) to a
486     `SysTime`, use `SysTime`'s constructor, and pass in the intended time
487     zone with it (or don't pass in a $(REF TimeZone,std,datetime,timezone), and
488     the local time zone will be used). Be aware, however, that converting from a
489     $(REF DateTime,std,datetime,date) to a `SysTime` will not necessarily
490     be 100% accurate due to DST (one hour of the year doesn't exist and another
491     occurs twice). To not risk any conversion errors, keep times as
492     `SysTime`s. Aside from DST though, there shouldn't be any conversion
493     problems.
494 
495     For using time zones other than local time or UTC, use
496     $(REF PosixTimeZone,std,datetime,timezone) on Posix systems (or on Windows,
497     if providing the TZ Database files), and use
498     $(REF WindowsTimeZone,std,datetime,timezone) on Windows systems. The time in
499     `SysTime` is kept internally in hnsecs from midnight, January 1st, 1 A.D.
500     UTC. Conversion error cannot happen when changing the time zone of a
501     `SysTime`. $(REF LocalTime,std,datetime,timezone) is the
502     $(REF TimeZone,std,datetime,timezone) class which represents the local time,
503     and `UTC` is the $(REF TimeZone,std,datetime,timezone) class which
504     represents UTC. `SysTime` uses $(REF LocalTime,std,datetime,timezone) if
505     no $(REF TimeZone,std,datetime,timezone) is provided. For more details on
506     time zones, see the documentation for $(REF TimeZone,std,datetime,timezone),
507     $(REF PosixTimeZone,std,datetime,timezone), and
508     $(REF WindowsTimeZone,std,datetime,timezone).
509 
510     `SysTime`'s range is from approximately 29,000 B.C. to approximately
511     29,000 A.D.
512   +/
513 struct SysTime
514 {
515     import core.stdc.time : tm;
516     version (Posix) import core.sys.posix.sys.time : timeval;
517     import std.typecons : Rebindable;
518 
519 public:
520 
521     /++
522         Params:
523             dateTime = The $(REF DateTime,std,datetime,date) to use to set
524                        this $(LREF SysTime)'s internal std time. As
525                        $(REF DateTime,std,datetime,date) has no concept of
526                        time zone, tz is used as its time zone.
527             tz       = The $(REF TimeZone,std,datetime,timezone) to use for this
528                        $(LREF SysTime). If null,
529                        $(REF LocalTime,std,datetime,timezone) will be used. The
530                        given $(REF DateTime,std,datetime,date) is assumed to
531                        be in the given time zone.
532       +/
533     this(DateTime dateTime, return scope immutable TimeZone tz = null) return scope @safe nothrow
534     {
535         try
536             this(dateTime, Duration.zero, tz);
537         catch (Exception e)
538             assert(0, "SysTime's constructor threw when it shouldn't have.");
539     }
540 
541     @safe unittest
542     {
543         static void test(DateTime dt, immutable TimeZone tz, long expected)
544         {
545             auto sysTime = SysTime(dt, tz);
546             assert(sysTime._stdTime == expected);
547             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given DateTime: %s", dt));
548         }
549 
550         test(DateTime.init, UTC(), 0);
551         test(DateTime(1, 1, 1, 12, 30, 33), UTC(), 450_330_000_000L);
552         test(DateTime(0, 12, 31, 12, 30, 33), UTC(), -413_670_000_000L);
553         test(DateTime(1, 1, 1, 0, 0, 0), UTC(), 0);
554         test(DateTime(1, 1, 1, 0, 0, 1), UTC(), 10_000_000L);
555         test(DateTime(0, 12, 31, 23, 59, 59), UTC(), -10_000_000L);
556 
557         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(-60)), 36_000_000_000L);
558         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(Duration.zero), 0);
559         test(DateTime(1, 1, 1, 0, 0, 0), new immutable SimpleTimeZone(dur!"minutes"(60)), -36_000_000_000L);
560 
561         static void testScope(scope ref DateTime dt) @safe
562         {
563             auto st = SysTime(dt);
564         }
565     }
566 
567     /++
568         Params:
569             dateTime = The $(REF DateTime,std,datetime,date) to use to set
570                        this $(LREF SysTime)'s internal std time. As
571                        $(REF DateTime,std,datetime,date) has no concept of
572                        time zone, tz is used as its time zone.
573             fracSecs = The fractional seconds portion of the time.
574             tz       = The $(REF TimeZone,std,datetime,timezone) to use for this
575                        $(LREF SysTime). If null,
576                        $(REF LocalTime,std,datetime,timezone) will be used. The
577                        given $(REF DateTime,std,datetime,date) is assumed to
578                        be in the given time zone.
579 
580         Throws:
581             $(REF DateTimeException,std,datetime,date) if `fracSecs` is negative or if it's
582             greater than or equal to one second.
583       +/
584     this(DateTime dateTime, Duration fracSecs, return scope immutable TimeZone tz = null) return scope @safe
585     {
586         enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
587         enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
588         auto nonNullTZ = tz is null ? LocalTime() : tz;
589 
590         immutable dateDiff = dateTime.date - Date.init;
591         immutable todDiff = dateTime.timeOfDay - TimeOfDay.init;
592 
593         immutable adjustedTime = dateDiff + todDiff + fracSecs;
594         immutable standardTime = nonNullTZ.tzToUTC(adjustedTime.total!"hnsecs");
595 
596         this(standardTime, nonNullTZ);
597     }
598 
599     @safe unittest
600     {
601         import core.time;
602         static void test(DateTime dt, Duration fracSecs, immutable TimeZone tz, long expected)
603         {
604             auto sysTime = SysTime(dt, fracSecs, tz);
605             assert(sysTime._stdTime == expected);
606             assert(sysTime._timezone is (tz is null ? LocalTime() : tz),
607                    format("Given DateTime: %s, Given Duration: %s", dt, fracSecs));
608         }
609 
610         test(DateTime.init, Duration.zero, UTC(), 0);
611         test(DateTime(1, 1, 1, 12, 30, 33), Duration.zero, UTC(), 450_330_000_000L);
612         test(DateTime(0, 12, 31, 12, 30, 33), Duration.zero, UTC(), -413_670_000_000L);
613         test(DateTime(1, 1, 1, 0, 0, 0), msecs(1), UTC(), 10_000L);
614         test(DateTime(0, 12, 31, 23, 59, 59), msecs(999), UTC(), -10_000L);
615 
616         test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC(), -1);
617         test(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC(), -9_999_999);
618         test(DateTime(0, 12, 31, 23, 59, 59), Duration.zero, UTC(), -10_000_000);
619 
620         assertThrown!DateTimeException(SysTime(DateTime.init, hnsecs(-1), UTC()));
621         assertThrown!DateTimeException(SysTime(DateTime.init, seconds(1), UTC()));
622 
623         static void testScope(scope ref DateTime dt, scope ref Duration d) @safe
624         {
625             auto st = SysTime(dt, d);
626         }
627     }
628 
629     /++
630         Params:
631             date = The $(REF Date,std,datetime,date) to use to set this
632                    $(LREF SysTime)'s internal std time. As
633                    $(REF Date,std,datetime,date) has no concept of time zone, tz
634                    is used as its time zone.
635             tz   = The $(REF TimeZone,std,datetime,timezone) to use for this
636                    $(LREF SysTime). If null,
637                    $(REF LocalTime,std,datetime,timezone) will be used. The
638                    given $(REF Date,std,datetime,date) is assumed to be in the
639                    given time zone.
640       +/
641     this(Date date, return scope immutable TimeZone tz = null) return scope @safe nothrow
642     {
643         _timezone = tz is null ? LocalTime() : tz;
644 
645         try
646         {
647             immutable adjustedTime = (date - Date(1, 1, 1)).total!"hnsecs";
648             immutable standardTime = _timezone.tzToUTC(adjustedTime);
649 
650             this(standardTime, _timezone);
651         }
652         catch (Exception e)
653             assert(0, "Date's constructor through when it shouldn't have.");
654     }
655 
656     @safe unittest
657     {
658         static void test(Date d, immutable TimeZone tz, long expected)
659         {
660             auto sysTime = SysTime(d, tz);
661             assert(sysTime._stdTime == expected);
662             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given Date: %s", d));
663         }
664 
665         test(Date.init, UTC(), 0);
666         test(Date(1, 1, 1), UTC(), 0);
667         test(Date(1, 1, 2), UTC(), 864000000000);
668         test(Date(0, 12, 31), UTC(), -864000000000);
669 
670         static void testScope(scope ref Date d) @safe
671         {
672             auto st = SysTime(d);
673         }
674     }
675 
676     /++
677         Note:
678             Whereas the other constructors take in the given date/time, assume
679             that it's in the given time zone, and convert it to hnsecs in UTC
680             since midnight, January 1st, 1 A.D. UTC - i.e. std time - this
681             constructor takes a std time, which is specifically already in UTC,
682             so no conversion takes place. Of course, the various getter
683             properties and functions will use the given time zone's conversion
684             function to convert the results to that time zone, but no conversion
685             of the arguments to this constructor takes place.
686 
687         Params:
688             stdTime = The number of hnsecs since midnight, January 1st, 1 A.D.
689                       UTC.
690             tz      = The $(REF TimeZone,std,datetime,timezone) to use for this
691                       $(LREF SysTime). If null,
692                       $(REF LocalTime,std,datetime,timezone) will be used.
693       +/
694     this(long stdTime, return scope immutable TimeZone tz = null) return scope @safe pure nothrow
695     {
696         _stdTime = stdTime;
697         _timezone = tz is null ? LocalTime() : tz;
698     }
699 
700     @safe unittest
701     {
702         static void test(long stdTime, immutable TimeZone tz)
703         {
704             auto sysTime = SysTime(stdTime, tz);
705             assert(sysTime._stdTime == stdTime);
706             assert(sysTime._timezone is (tz is null ? LocalTime() : tz), format("Given stdTime: %s", stdTime));
707         }
708 
709         foreach (stdTime; [-1234567890L, -250, 0, 250, 1235657390L])
710         {
711             foreach (tz; testTZs)
712                 test(stdTime, tz);
713         }
714     }
715 
716 
717     /++
718         Params:
719             rhs = The $(LREF SysTime) to assign to this one.
720 
721         Returns: The `this` of this `SysTime`.
722       +/
723     ref SysTime opAssign()(auto ref const(SysTime) rhs) scope return @safe pure nothrow
724     {
725         _stdTime = rhs._stdTime;
726         _timezone = rhs._timezone;
727         return this;
728     }
729 
730     @safe unittest
731     {
732         SysTime st;
733         st = SysTime(DateTime(2012, 12, 21, 1, 2, 3), UTC());
734         assert(st == SysTime(DateTime(2012, 12, 21, 1, 2, 3), UTC()));
735 
736         const other = SysTime(DateTime(19, 1, 7, 13, 14, 15), LocalTime());
737         st = other;
738         assert(st == other);
739 
740         version (none) // https://issues.dlang.org/show_bug.cgi?id=21175
741         static void testScope(scope ref SysTime left, const scope SysTime right) @safe
742         {
743             left = right;
744         }
745     }
746 
747 
748     /++
749         Checks for equality between this $(LREF SysTime) and the given
750         $(LREF SysTime).
751 
752         Note that the time zone is ignored. Only the internal
753         std times (which are in UTC) are compared.
754      +/
755     bool opEquals()(auto ref const(SysTime) rhs) @safe const pure nothrow scope
756     {
757         return _stdTime == rhs._stdTime;
758     }
759 
760     @safe unittest
761     {
762         import std.range : chain;
763 
764         assert(SysTime(DateTime.init, UTC()) == SysTime(0, UTC()));
765         assert(SysTime(DateTime.init, UTC()) == SysTime(0));
766         assert(SysTime(Date.init, UTC()) == SysTime(0));
767         assert(SysTime(0) == SysTime(0));
768 
769         static void test(DateTime dt, immutable TimeZone tz1, immutable TimeZone tz2)
770         {
771             auto st1 = SysTime(dt);
772             st1.timezone = tz1;
773 
774             auto st2 = SysTime(dt);
775             st2.timezone = tz2;
776 
777             assert(st1 == st2);
778         }
779 
780         foreach (tz1; testTZs)
781         {
782             foreach (tz2; testTZs)
783             {
784                 foreach (dt; chain(testDateTimesBC, testDateTimesAD))
785                     test(dt, tz1, tz2);
786             }
787         }
788 
789         auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
790         const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
791         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
792         assert(st == st);
793         assert(st == cst);
794         assert(st == ist);
795         assert(cst == st);
796         assert(cst == cst);
797         assert(cst == ist);
798         assert(ist == st);
799         assert(ist == cst);
800         assert(ist == ist);
801 
802         static void testScope(scope ref SysTime left, const scope SysTime right) @safe
803         {
804             assert(left == right);
805             assert(right == left);
806         }
807     }
808 
809 
810     /++
811         Compares this $(LREF SysTime) with the given $(LREF SysTime).
812 
813         Time zone is irrelevant when comparing $(LREF SysTime)s.
814 
815         Returns:
816             $(BOOKTABLE,
817             $(TR $(TD this &lt; rhs) $(TD &lt; 0))
818             $(TR $(TD this == rhs) $(TD 0))
819             $(TR $(TD this &gt; rhs) $(TD &gt; 0))
820             )
821      +/
822     int opCmp()(auto ref const(SysTime) rhs) @safe const pure nothrow scope
823     {
824         if (_stdTime < rhs._stdTime)
825             return -1;
826         if (_stdTime > rhs._stdTime)
827             return 1;
828         return 0;
829     }
830 
831     @safe unittest
832     {
833         import std.algorithm.iteration : map;
834         import std.array : array;
835         import std.range : chain;
836 
837         assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0, UTC())) == 0);
838         assert(SysTime(DateTime.init, UTC()).opCmp(SysTime(0)) == 0);
839         assert(SysTime(Date.init, UTC()).opCmp(SysTime(0)) == 0);
840         assert(SysTime(0).opCmp(SysTime(0)) == 0);
841 
842         static void testEqual(SysTime st, immutable TimeZone tz1, immutable TimeZone tz2)
843         {
844             auto st1 = st;
845             st1.timezone = tz1;
846 
847             auto st2 = st;
848             st2.timezone = tz2;
849 
850             assert(st1.opCmp(st2) == 0);
851         }
852 
853         auto sts = array(map!SysTime(chain(testDateTimesBC, testDateTimesAD)));
854 
855         foreach (st; sts)
856         {
857             foreach (tz1; testTZs)
858             {
859                 foreach (tz2; testTZs)
860                     testEqual(st, tz1, tz2);
861             }
862         }
863 
864         static void testCmp(SysTime st1, immutable TimeZone tz1, SysTime st2, immutable TimeZone tz2)
865         {
866             st1.timezone = tz1;
867             st2.timezone = tz2;
868             assert(st1.opCmp(st2) < 0);
869             assert(st2.opCmp(st1) > 0);
870         }
871 
872         foreach (si, st1; sts)
873         {
874             foreach (st2; sts[si + 1 .. $])
875             {
876                 foreach (tz1; testTZs)
877                 {
878                     foreach (tz2; testTZs)
879                         testCmp(st1, tz1, st2, tz2);
880                 }
881             }
882         }
883 
884         auto st = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
885         const cst = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
886         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 33, 30));
887         assert(st.opCmp(st) == 0);
888         assert(st.opCmp(cst) == 0);
889         assert(st.opCmp(ist) == 0);
890         assert(cst.opCmp(st) == 0);
891         assert(cst.opCmp(cst) == 0);
892         assert(cst.opCmp(ist) == 0);
893         assert(ist.opCmp(st) == 0);
894         assert(ist.opCmp(cst) == 0);
895         assert(ist.opCmp(ist) == 0);
896 
897         static void testScope(scope ref SysTime left, const scope SysTime right) @safe
898         {
899             assert(left < right);
900             assert(right > left);
901         }
902     }
903 
904 
905     /++
906         Returns: A hash of the $(LREF SysTime).
907      +/
908     size_t toHash() const @nogc pure nothrow @safe scope
909     {
910         static if (is(size_t == ulong))
911             return _stdTime;
912         else
913         {
914             // MurmurHash2
915             enum ulong m = 0xc6a4a7935bd1e995UL;
916             enum ulong n = m * 16;
917             enum uint r = 47;
918 
919             ulong k = _stdTime;
920             k *= m;
921             k ^= k >> r;
922             k *= m;
923 
924             ulong h = n;
925             h ^= k;
926             h *= m;
927 
928             return cast(size_t) h;
929         }
930     }
931 
932     @safe unittest
933     {
934         assert(SysTime(0).toHash == SysTime(0).toHash);
935         assert(SysTime(DateTime(2000, 1, 1)).toHash == SysTime(DateTime(2000, 1, 1)).toHash);
936         assert(SysTime(DateTime(2000, 1, 1)).toHash != SysTime(DateTime(2000, 1, 2)).toHash);
937 
938         // test that timezones aren't taken into account
939         assert(SysTime(0, LocalTime()).toHash == SysTime(0, LocalTime()).toHash);
940         assert(SysTime(0, LocalTime()).toHash == SysTime(0, UTC()).toHash);
941         assert(SysTime(DateTime(2000, 1, 1), LocalTime()).toHash == SysTime(DateTime(2000, 1, 1), LocalTime()).toHash);
942         immutable zone = new SimpleTimeZone(dur!"minutes"(60));
943         assert(SysTime(DateTime(2000, 1, 1, 1), zone).toHash == SysTime(DateTime(2000, 1, 1), UTC()).toHash);
944         assert(SysTime(DateTime(2000, 1, 1), zone).toHash != SysTime(DateTime(2000, 1, 1), UTC()).toHash);
945 
946         static void testScope(scope ref SysTime st) @safe
947         {
948             auto result = st.toHash();
949         }
950     }
951 
952 
953     /++
954         Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
955         are B.C.
956      +/
957     @property short year() @safe const nothrow scope
958     {
959         return (cast(Date) this).year;
960     }
961 
962     @safe unittest
963     {
964         import std.range : chain;
965         static void test(SysTime sysTime, long expected)
966         {
967             assert(sysTime.year == expected, format("Value given: %s", sysTime));
968         }
969 
970         test(SysTime(0, UTC()), 1);
971         test(SysTime(1, UTC()), 1);
972         test(SysTime(-1, UTC()), 0);
973 
974         foreach (year; chain(testYearsBC, testYearsAD))
975         {
976             foreach (md; testMonthDays)
977             {
978                 foreach (tod; testTODs)
979                 {
980                     auto dt = DateTime(Date(year, md.month, md.day), tod);
981                     foreach (tz; testTZs)
982                     {
983                         foreach (fs; testFracSecs)
984                             test(SysTime(dt, fs, tz), year);
985                     }
986                 }
987             }
988         }
989 
990         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
991         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
992         assert(cst.year == 1999);
993         assert(ist.year == 1999);
994 
995         static void testScope(scope ref SysTime st) @safe
996         {
997             auto result = st.year;
998         }
999     }
1000 
1001     /++
1002         Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
1003         are B.C.
1004 
1005         Params:
1006             year = The year to set this $(LREF SysTime)'s year to.
1007 
1008         Throws:
1009             $(REF DateTimeException,std,datetime,date) if the new year is not
1010             a leap year and the resulting date would be on February 29th.
1011      +/
1012     @property void year(int year) @safe scope
1013     {
1014         auto hnsecs = adjTime;
1015         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1016 
1017         if (hnsecs < 0)
1018         {
1019             hnsecs += convert!("hours", "hnsecs")(24);
1020             --days;
1021         }
1022 
1023         auto date = Date(cast(int) days);
1024         date.year = year;
1025 
1026         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1027         adjTime = newDaysHNSecs + hnsecs;
1028     }
1029 
1030     ///
1031     @safe unittest
1032     {
1033         import std.datetime.date : DateTime;
1034 
1035         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).year == 1999);
1036         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).year == 2010);
1037         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).year == -7);
1038     }
1039 
1040     @safe unittest
1041     {
1042         import std.range : chain;
1043 
1044         static void test(SysTime st, int year, SysTime expected)
1045         {
1046             st.year = year;
1047             assert(st == expected);
1048         }
1049 
1050         foreach (st; chain(testSysTimesBC, testSysTimesAD))
1051         {
1052             auto dt = cast(DateTime) st;
1053 
1054             foreach (year; chain(testYearsBC, testYearsAD))
1055             {
1056                 auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
1057                                  st.fracSecs,
1058                                  st.timezone);
1059                 test(st, year, e);
1060             }
1061         }
1062 
1063         foreach (fs; testFracSecs)
1064         {
1065             foreach (tz; testTZs)
1066             {
1067                 foreach (tod; testTODs)
1068                 {
1069                     test(SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz), 2000,
1070                          SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz));
1071                     test(SysTime(DateTime(Date(2000, 2, 28), tod), fs, tz), 1999,
1072                          SysTime(DateTime(Date(1999, 2, 28), tod), fs, tz));
1073                 }
1074 
1075                 foreach (tod; testTODsThrown)
1076                 {
1077                     auto st = SysTime(DateTime(Date(2000, 2, 29), tod), fs, tz);
1078                     assertThrown!DateTimeException(st.year = 1999);
1079                 }
1080             }
1081         }
1082 
1083         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1084         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1085         static assert(!__traits(compiles, cst.year = 7));
1086         static assert(!__traits(compiles, ist.year = 7));
1087 
1088         static void testScope(scope ref SysTime st) @safe
1089         {
1090             st.year = 42;
1091         }
1092     }
1093 
1094     /++
1095         Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
1096 
1097         Throws:
1098             $(REF DateTimeException,std,datetime,date) if `isAD` is true.
1099      +/
1100     @property ushort yearBC() @safe const scope
1101     {
1102         return (cast(Date) this).yearBC;
1103     }
1104 
1105     ///
1106     @safe unittest
1107     {
1108         import std.datetime.date : DateTime;
1109 
1110         assert(SysTime(DateTime(0, 1, 1, 12, 30, 33)).yearBC == 1);
1111         assert(SysTime(DateTime(-1, 1, 1, 10, 7, 2)).yearBC == 2);
1112         assert(SysTime(DateTime(-100, 1, 1, 4, 59, 0)).yearBC == 101);
1113     }
1114 
1115     @safe unittest
1116     {
1117         import std.exception : assertNotThrown;
1118         foreach (st; testSysTimesBC)
1119         {
1120             auto msg = format("SysTime: %s", st);
1121             assertNotThrown!DateTimeException(st.yearBC, msg);
1122             assert(st.yearBC == (st.year * -1) + 1, msg);
1123         }
1124 
1125         foreach (st; [testSysTimesAD[0], testSysTimesAD[$/2], testSysTimesAD[$-1]])
1126             assertThrown!DateTimeException(st.yearBC, format("SysTime: %s", st));
1127 
1128         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1129         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1130         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1131         st.year = 12;
1132         assert(st.year == 12);
1133         static assert(!__traits(compiles, cst.year = 12));
1134         static assert(!__traits(compiles, ist.year = 12));
1135 
1136         static void testScope(scope ref SysTime st) @safe
1137         {
1138             auto result = st.yearBC;
1139         }
1140     }
1141 
1142 
1143     /++
1144         Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
1145 
1146         Params:
1147             year = The year B.C. to set this $(LREF SysTime)'s year to.
1148 
1149         Throws:
1150             $(REF DateTimeException,std,datetime,date) if a non-positive value
1151             is given.
1152      +/
1153     @property void yearBC(int year) @safe scope
1154     {
1155         auto hnsecs = adjTime;
1156         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1157 
1158         if (hnsecs < 0)
1159         {
1160             hnsecs += convert!("hours", "hnsecs")(24);
1161             --days;
1162         }
1163 
1164         auto date = Date(cast(int) days);
1165         date.yearBC = year;
1166 
1167         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1168         adjTime = newDaysHNSecs + hnsecs;
1169     }
1170 
1171     @safe unittest
1172     {
1173         auto st = SysTime(DateTime(2010, 1, 1, 7, 30, 0));
1174         st.yearBC = 1;
1175         assert(st == SysTime(DateTime(0, 1, 1, 7, 30, 0)));
1176 
1177         st.yearBC = 10;
1178         assert(st == SysTime(DateTime(-9, 1, 1, 7, 30, 0)));
1179     }
1180 
1181     @safe unittest
1182     {
1183         import std.range : chain;
1184         static void test(SysTime st, int year, SysTime expected)
1185         {
1186             st.yearBC = year;
1187             assert(st == expected, format("SysTime: %s", st));
1188         }
1189 
1190         foreach (st; chain(testSysTimesBC, testSysTimesAD))
1191         {
1192             auto dt = cast(DateTime) st;
1193 
1194             foreach (year; testYearsBC)
1195             {
1196                 auto e = SysTime(DateTime(year, dt.month, dt.day, dt.hour, dt.minute, dt.second),
1197                                  st.fracSecs,
1198                                  st.timezone);
1199                 test(st, (year * -1) + 1, e);
1200             }
1201         }
1202 
1203         foreach (st; [testSysTimesBC[0], testSysTimesBC[$ - 1], testSysTimesAD[0], testSysTimesAD[$ - 1]])
1204         {
1205             foreach (year; testYearsBC)
1206                 assertThrown!DateTimeException(st.yearBC = year);
1207         }
1208 
1209         foreach (fs; testFracSecs)
1210         {
1211             foreach (tz; testTZs)
1212             {
1213                 foreach (tod; testTODs)
1214                 {
1215                     test(SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz), 2001,
1216                          SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz));
1217                     test(SysTime(DateTime(Date(-2000, 2, 28), tod), fs, tz), 2000,
1218                          SysTime(DateTime(Date(-1999, 2, 28), tod), fs, tz));
1219                 }
1220 
1221                 foreach (tod; testTODsThrown)
1222                 {
1223                     auto st = SysTime(DateTime(Date(-2000, 2, 29), tod), fs, tz);
1224                     assertThrown!DateTimeException(st.year = -1999);
1225                 }
1226             }
1227         }
1228 
1229         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1230         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1231         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1232         st.yearBC = 12;
1233         assert(st.yearBC == 12);
1234         static assert(!__traits(compiles, cst.yearBC = 12));
1235         static assert(!__traits(compiles, ist.yearBC = 12));
1236 
1237         static void testScope(scope ref SysTime st) @safe
1238         {
1239             st.yearBC = 42;
1240         }
1241     }
1242 
1243 
1244     /++
1245         Month of a Gregorian Year.
1246      +/
1247     @property Month month() @safe const nothrow scope
1248     {
1249         return (cast(Date) this).month;
1250     }
1251 
1252     ///
1253     @safe unittest
1254     {
1255         import std.datetime.date : DateTime;
1256 
1257         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).month == 7);
1258         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).month == 10);
1259         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).month == 4);
1260     }
1261 
1262     @safe unittest
1263     {
1264         import std.range : chain;
1265 
1266         static void test(SysTime sysTime, Month expected)
1267         {
1268             assert(sysTime.month == expected, format("Value given: %s", sysTime));
1269         }
1270 
1271         test(SysTime(0, UTC()), Month.jan);
1272         test(SysTime(1, UTC()), Month.jan);
1273         test(SysTime(-1, UTC()), Month.dec);
1274 
1275         foreach (year; chain(testYearsBC, testYearsAD))
1276         {
1277             foreach (md; testMonthDays)
1278             {
1279                 foreach (tod; testTODs)
1280                 {
1281                     auto dt = DateTime(Date(year, md.month, md.day), tod);
1282                     foreach (fs; testFracSecs)
1283                     {
1284                         foreach (tz; testTZs)
1285                             test(SysTime(dt, fs, tz), md.month);
1286                     }
1287                 }
1288             }
1289         }
1290 
1291         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1292         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1293         assert(cst.month == 7);
1294         assert(ist.month == 7);
1295 
1296         static void testScope(scope ref SysTime st) @safe
1297         {
1298             auto result = st.month;
1299         }
1300     }
1301 
1302 
1303     /++
1304         Month of a Gregorian Year.
1305 
1306         Params:
1307             month = The month to set this $(LREF SysTime)'s month to.
1308 
1309         Throws:
1310             $(REF DateTimeException,std,datetime,date) if the given month is
1311             not a valid month.
1312      +/
1313     @property void month(Month month) @safe scope
1314     {
1315         auto hnsecs = adjTime;
1316         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1317 
1318         if (hnsecs < 0)
1319         {
1320             hnsecs += convert!("hours", "hnsecs")(24);
1321             --days;
1322         }
1323 
1324         auto date = Date(cast(int) days);
1325         date.month = month;
1326 
1327         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1328         adjTime = newDaysHNSecs + hnsecs;
1329     }
1330 
1331     @safe unittest
1332     {
1333         import std.algorithm.iteration : filter;
1334         import std.range : chain;
1335 
1336         static void test(SysTime st, Month month, SysTime expected)
1337         {
1338             st.month = cast(Month) month;
1339             assert(st == expected);
1340         }
1341 
1342         foreach (st; chain(testSysTimesBC, testSysTimesAD))
1343         {
1344             auto dt = cast(DateTime) st;
1345 
1346             foreach (md; testMonthDays)
1347             {
1348                 if (st.day > maxDay(dt.year, md.month))
1349                     continue;
1350                 auto e = SysTime(DateTime(dt.year, md.month, dt.day, dt.hour, dt.minute, dt.second),
1351                                  st.fracSecs,
1352                                  st.timezone);
1353                 test(st, md.month, e);
1354             }
1355         }
1356 
1357         foreach (fs; testFracSecs)
1358         {
1359             foreach (tz; testTZs)
1360             {
1361                 foreach (tod; testTODs)
1362                 {
1363                     foreach (year; filter!((a){return yearIsLeapYear(a);}) (chain(testYearsBC, testYearsAD)))
1364                     {
1365                         test(SysTime(DateTime(Date(year, 1, 29), tod), fs, tz),
1366                              Month.feb,
1367                              SysTime(DateTime(Date(year, 2, 29), tod), fs, tz));
1368                     }
1369 
1370                     foreach (year; chain(testYearsBC, testYearsAD))
1371                     {
1372                         test(SysTime(DateTime(Date(year, 1, 28), tod), fs, tz),
1373                              Month.feb,
1374                              SysTime(DateTime(Date(year, 2, 28), tod), fs, tz));
1375                         test(SysTime(DateTime(Date(year, 7, 30), tod), fs, tz),
1376                              Month.jun,
1377                              SysTime(DateTime(Date(year, 6, 30), tod), fs, tz));
1378                     }
1379                 }
1380             }
1381         }
1382 
1383         foreach (fs; [testFracSecs[0], testFracSecs[$-1]])
1384         {
1385             foreach (tz; testTZs)
1386             {
1387                 foreach (tod; testTODsThrown)
1388                 {
1389                     foreach (year; [testYearsBC[$-3], testYearsBC[$-2],
1390                                     testYearsBC[$-2], testYearsAD[0],
1391                                     testYearsAD[$-2], testYearsAD[$-1]])
1392                     {
1393                         auto day = yearIsLeapYear(year) ? 30 : 29;
1394                         auto st1 = SysTime(DateTime(Date(year, 1, day), tod), fs, tz);
1395                         assertThrown!DateTimeException(st1.month = Month.feb);
1396 
1397                         auto st2 = SysTime(DateTime(Date(year, 7, 31), tod), fs, tz);
1398                         assertThrown!DateTimeException(st2.month = Month.jun);
1399                     }
1400                 }
1401             }
1402         }
1403 
1404         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1405         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1406         static assert(!__traits(compiles, cst.month = Month.dec));
1407         static assert(!__traits(compiles, ist.month = Month.dec));
1408 
1409         static void testScope(scope ref SysTime st) @safe
1410         {
1411             st.month = Month.dec;
1412         }
1413     }
1414 
1415     /++
1416         Day of a Gregorian Month.
1417      +/
1418     @property ubyte day() @safe const nothrow scope
1419     {
1420         return (cast(Date) this).day;
1421     }
1422 
1423     ///
1424     @safe unittest
1425     {
1426         import std.datetime.date : DateTime;
1427 
1428         assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).day == 6);
1429         assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).day == 4);
1430         assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).day == 5);
1431     }
1432 
1433     @safe unittest
1434     {
1435         import std.range : chain;
1436 
1437         static void test(SysTime sysTime, int expected)
1438         {
1439             assert(sysTime.day == expected, format("Value given: %s", sysTime));
1440         }
1441 
1442         test(SysTime(0, UTC()), 1);
1443         test(SysTime(1, UTC()), 1);
1444         test(SysTime(-1, UTC()), 31);
1445 
1446         foreach (year; chain(testYearsBC, testYearsAD))
1447         {
1448             foreach (md; testMonthDays)
1449             {
1450                 foreach (tod; testTODs)
1451                 {
1452                     auto dt = DateTime(Date(year, md.month, md.day), tod);
1453 
1454                     foreach (tz; testTZs)
1455                     {
1456                         foreach (fs; testFracSecs)
1457                             test(SysTime(dt, fs, tz), md.day);
1458                     }
1459                 }
1460             }
1461         }
1462 
1463         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1464         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1465          assert(cst.day == 6);
1466         assert(ist.day == 6);
1467 
1468         static void testScope(scope ref SysTime st) @safe
1469         {
1470             auto result = st.day;
1471         }
1472     }
1473 
1474 
1475     /++
1476         Day of a Gregorian Month.
1477 
1478         Params:
1479             day = The day of the month to set this $(LREF SysTime)'s day to.
1480 
1481         Throws:
1482             $(REF DateTimeException,std,datetime,date) if the given day is not
1483             a valid day of the current month.
1484      +/
1485     @property void day(int day) @safe scope
1486     {
1487         auto hnsecs = adjTime;
1488         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1489 
1490         if (hnsecs < 0)
1491         {
1492             hnsecs += convert!("hours", "hnsecs")(24);
1493             --days;
1494         }
1495 
1496         auto date = Date(cast(int) days);
1497         date.day = day;
1498 
1499         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
1500         adjTime = newDaysHNSecs + hnsecs;
1501     }
1502 
1503     @safe unittest
1504     {
1505         import std.range : chain;
1506         import std.traits : EnumMembers;
1507 
1508         foreach (day; chain(testDays))
1509         {
1510             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1511             {
1512                 auto dt = cast(DateTime) st;
1513 
1514                 if (day > maxDay(dt.year, dt.month))
1515                     continue;
1516                 auto expected = SysTime(DateTime(dt.year, dt.month, day, dt.hour, dt.minute, dt.second),
1517                                         st.fracSecs,
1518                                         st.timezone);
1519                 st.day = day;
1520                 assert(st == expected, format("[%s] [%s]", st, expected));
1521             }
1522         }
1523 
1524         foreach (tz; testTZs)
1525         {
1526             foreach (tod; testTODs)
1527             {
1528                 foreach (fs; testFracSecs)
1529                 {
1530                     foreach (year; chain(testYearsBC, testYearsAD))
1531                     {
1532                         foreach (month; EnumMembers!Month)
1533                         {
1534                             auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz);
1535                             immutable max = maxDay(year, month);
1536                             auto expected = SysTime(DateTime(Date(year, month, max), tod), fs, tz);
1537 
1538                             st.day = max;
1539                             assert(st == expected, format("[%s] [%s]", st, expected));
1540                         }
1541                     }
1542                 }
1543             }
1544         }
1545 
1546         foreach (tz; testTZs)
1547         {
1548             foreach (tod; testTODsThrown)
1549             {
1550                 foreach (fs; [testFracSecs[0], testFracSecs[$-1]])
1551                 {
1552                     foreach (year; [testYearsBC[$-3], testYearsBC[$-2],
1553                                     testYearsBC[$-2], testYearsAD[0],
1554                                     testYearsAD[$-2], testYearsAD[$-1]])
1555                     {
1556                         foreach (month; EnumMembers!Month)
1557                         {
1558                             auto st = SysTime(DateTime(Date(year, month, 1), tod), fs, tz);
1559                             immutable max = maxDay(year, month);
1560 
1561                             assertThrown!DateTimeException(st.day = max + 1);
1562                         }
1563                     }
1564                 }
1565             }
1566         }
1567 
1568         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1569         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1570         static assert(!__traits(compiles, cst.day = 27));
1571         static assert(!__traits(compiles, ist.day = 27));
1572 
1573         static void testScope(scope ref SysTime st) @safe
1574         {
1575             st.day = 12;
1576         }
1577     }
1578 
1579 
1580     /++
1581         Hours past midnight.
1582      +/
1583     @property ubyte hour() @safe const nothrow scope
1584     {
1585         auto hnsecs = adjTime;
1586         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1587 
1588         if (hnsecs < 0)
1589         {
1590             hnsecs += convert!("hours", "hnsecs")(24);
1591             --days;
1592         }
1593 
1594         return cast(ubyte) getUnitsFromHNSecs!"hours"(hnsecs);
1595     }
1596 
1597     @safe unittest
1598     {
1599         import std.range : chain;
1600 
1601         static void test(SysTime sysTime, int expected)
1602         {
1603             assert(sysTime.hour == expected, format("Value given: %s", sysTime));
1604         }
1605 
1606         test(SysTime(0, UTC()), 0);
1607         test(SysTime(1, UTC()), 0);
1608         test(SysTime(-1, UTC()), 23);
1609 
1610         foreach (tz; testTZs)
1611         {
1612             foreach (year; chain(testYearsBC, testYearsAD))
1613             {
1614                 foreach (md; testMonthDays)
1615                 {
1616                     foreach (hour; testHours)
1617                     {
1618                         foreach (minute; testMinSecs)
1619                         {
1620                             foreach (second; testMinSecs)
1621                             {
1622                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1623                                 foreach (fs; testFracSecs)
1624                                     test(SysTime(dt, fs, tz), hour);
1625                             }
1626                         }
1627                     }
1628                 }
1629             }
1630         }
1631 
1632         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1633         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1634         assert(cst.hour == 12);
1635         assert(ist.hour == 12);
1636 
1637         static void testScope(scope ref SysTime st) @safe
1638         {
1639             auto result = st.hour;
1640         }
1641     }
1642 
1643 
1644     /++
1645         Hours past midnight.
1646 
1647         Params:
1648             hour = The hours to set this $(LREF SysTime)'s hour to.
1649 
1650         Throws:
1651             $(REF DateTimeException,std,datetime,date) if the given hour are
1652             not a valid hour of the day.
1653      +/
1654     @property void hour(int hour) @safe scope
1655     {
1656         enforceValid!"hours"(hour);
1657 
1658         auto hnsecs = adjTime;
1659         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1660         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1661         immutable negative = hnsecs < 0;
1662 
1663         if (negative)
1664             hnsecs += convert!("hours", "hnsecs")(24);
1665 
1666         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1667         hnsecs += convert!("hours", "hnsecs")(hour);
1668 
1669         if (negative)
1670             hnsecs -= convert!("hours", "hnsecs")(24);
1671 
1672         adjTime = daysHNSecs + hnsecs;
1673     }
1674 
1675     @safe unittest
1676     {
1677         import std.range : chain;
1678 
1679         foreach (hour; chain(testHours))
1680         {
1681             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1682             {
1683                 auto dt = cast(DateTime) st;
1684                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, hour, dt.minute, dt.second),
1685                                         st.fracSecs,
1686                                         st.timezone);
1687                 st.hour = hour;
1688                 assert(st == expected, format("[%s] [%s]", st, expected));
1689             }
1690         }
1691 
1692         auto st = testSysTimesAD[0];
1693         assertThrown!DateTimeException(st.hour = -1);
1694         assertThrown!DateTimeException(st.hour = 60);
1695 
1696         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1697         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1698         static assert(!__traits(compiles, cst.hour = 27));
1699         static assert(!__traits(compiles, ist.hour = 27));
1700 
1701         static void testScope(scope ref SysTime st) @safe
1702         {
1703             st.hour = 12;
1704         }
1705     }
1706 
1707 
1708     /++
1709         Minutes past the current hour.
1710      +/
1711     @property ubyte minute() @safe const nothrow scope
1712     {
1713         auto hnsecs = adjTime;
1714         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1715 
1716         if (hnsecs < 0)
1717         {
1718             hnsecs += convert!("hours", "hnsecs")(24);
1719             --days;
1720         }
1721 
1722         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1723 
1724         return cast(ubyte) getUnitsFromHNSecs!"minutes"(hnsecs);
1725     }
1726 
1727     @safe unittest
1728     {
1729         import std.range : chain;
1730 
1731         static void test(SysTime sysTime, int expected)
1732         {
1733             assert(sysTime.minute == expected, format("Value given: %s", sysTime));
1734         }
1735 
1736         test(SysTime(0, UTC()), 0);
1737         test(SysTime(1, UTC()), 0);
1738         test(SysTime(-1, UTC()), 59);
1739 
1740         foreach (tz; testTZs)
1741         {
1742             foreach (year; chain(testYearsBC, testYearsAD))
1743             {
1744                 foreach (md; testMonthDays)
1745                 {
1746                     foreach (hour; testHours)
1747                     {
1748                         foreach (minute; testMinSecs)
1749                         {
1750                             foreach (second; testMinSecs)
1751                             {
1752                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1753                                 foreach (fs; testFracSecs)
1754                                     test(SysTime(dt, fs, tz), minute);
1755                             }
1756                         }
1757                     }
1758                 }
1759             }
1760         }
1761 
1762         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1763         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1764         assert(cst.minute == 30);
1765         assert(ist.minute == 30);
1766 
1767         static void testScope(scope ref SysTime st) @safe
1768         {
1769             auto result = st.minute;
1770         }
1771     }
1772 
1773 
1774     /++
1775         Minutes past the current hour.
1776 
1777         Params:
1778             minute = The minute to set this $(LREF SysTime)'s minute to.
1779 
1780         Throws:
1781             $(REF DateTimeException,std,datetime,date) if the given minute are
1782             not a valid minute of an hour.
1783      +/
1784     @property void minute(int minute) @safe scope
1785     {
1786         enforceValid!"minutes"(minute);
1787 
1788         auto hnsecs = adjTime;
1789         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1790         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1791         immutable negative = hnsecs < 0;
1792 
1793         if (negative)
1794             hnsecs += convert!("hours", "hnsecs")(24);
1795 
1796         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
1797         hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs);
1798 
1799         hnsecs += convert!("hours", "hnsecs")(hour);
1800         hnsecs += convert!("minutes", "hnsecs")(minute);
1801 
1802         if (negative)
1803             hnsecs -= convert!("hours", "hnsecs")(24);
1804 
1805         adjTime = daysHNSecs + hnsecs;
1806     }
1807 
1808     @safe unittest
1809     {
1810         import std.range : chain;
1811 
1812         foreach (minute; testMinSecs)
1813         {
1814             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1815             {
1816                 auto dt = cast(DateTime) st;
1817                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, minute, dt.second),
1818                                         st.fracSecs,
1819                                         st.timezone);
1820                 st.minute = minute;
1821                 assert(st == expected, format("[%s] [%s]", st, expected));
1822             }
1823         }
1824 
1825         auto st = testSysTimesAD[0];
1826         assertThrown!DateTimeException(st.minute = -1);
1827         assertThrown!DateTimeException(st.minute = 60);
1828 
1829         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1830         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1831         static assert(!__traits(compiles, cst.minute = 27));
1832         static assert(!__traits(compiles, ist.minute = 27));
1833 
1834         static void testScope(scope ref SysTime st) @safe
1835         {
1836             st.minute = 12;
1837         }
1838     }
1839 
1840 
1841     /++
1842         Seconds past the current minute.
1843      +/
1844     @property ubyte second() @safe const nothrow scope
1845     {
1846         auto hnsecs = adjTime;
1847         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
1848 
1849         if (hnsecs < 0)
1850         {
1851             hnsecs += convert!("hours", "hnsecs")(24);
1852             --days;
1853         }
1854 
1855         hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs);
1856         hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs);
1857 
1858         return cast(ubyte) getUnitsFromHNSecs!"seconds"(hnsecs);
1859     }
1860 
1861     @safe unittest
1862     {
1863         import std.range : chain;
1864 
1865         static void test(SysTime sysTime, int expected)
1866         {
1867             assert(sysTime.second == expected, format("Value given: %s", sysTime));
1868         }
1869 
1870         test(SysTime(0, UTC()), 0);
1871         test(SysTime(1, UTC()), 0);
1872         test(SysTime(-1, UTC()), 59);
1873 
1874         foreach (tz; testTZs)
1875         {
1876             foreach (year; chain(testYearsBC, testYearsAD))
1877             {
1878                 foreach (md; testMonthDays)
1879                 {
1880                     foreach (hour; testHours)
1881                     {
1882                         foreach (minute; testMinSecs)
1883                         {
1884                             foreach (second; testMinSecs)
1885                             {
1886                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
1887                                 foreach (fs; testFracSecs)
1888                                     test(SysTime(dt, fs, tz), second);
1889                             }
1890                         }
1891                     }
1892                 }
1893             }
1894         }
1895 
1896         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1897         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1898         assert(cst.second == 33);
1899         assert(ist.second == 33);
1900 
1901         static void testScope(scope ref SysTime st) @safe
1902         {
1903             auto result = st.second;
1904         }
1905     }
1906 
1907 
1908     /++
1909         Seconds past the current minute.
1910 
1911         Params:
1912             second = The second to set this $(LREF SysTime)'s second to.
1913 
1914         Throws:
1915             $(REF DateTimeException,std,datetime,date) if the given second are
1916             not a valid second of a minute.
1917      +/
1918     @property void second(int second) @safe scope
1919     {
1920         enforceValid!"seconds"(second);
1921 
1922         auto hnsecs = adjTime;
1923         auto days = splitUnitsFromHNSecs!"days"(hnsecs);
1924         immutable daysHNSecs = convert!("days", "hnsecs")(days);
1925         immutable negative = hnsecs < 0;
1926 
1927         if (negative)
1928             hnsecs += convert!("hours", "hnsecs")(24);
1929 
1930         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
1931         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
1932         hnsecs = removeUnitsFromHNSecs!"seconds"(hnsecs);
1933 
1934         hnsecs += convert!("hours", "hnsecs")(hour);
1935         hnsecs += convert!("minutes", "hnsecs")(minute);
1936         hnsecs += convert!("seconds", "hnsecs")(second);
1937 
1938         if (negative)
1939             hnsecs -= convert!("hours", "hnsecs")(24);
1940 
1941         adjTime = daysHNSecs + hnsecs;
1942     }
1943 
1944     @safe unittest
1945     {
1946         import std.range : chain;
1947 
1948         foreach (second; testMinSecs)
1949         {
1950             foreach (st; chain(testSysTimesBC, testSysTimesAD))
1951             {
1952                 auto dt = cast(DateTime) st;
1953                 auto expected = SysTime(DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, second),
1954                                         st.fracSecs,
1955                                         st.timezone);
1956                 st.second = second;
1957                 assert(st == expected, format("[%s] [%s]", st, expected));
1958             }
1959         }
1960 
1961         auto st = testSysTimesAD[0];
1962         assertThrown!DateTimeException(st.second = -1);
1963         assertThrown!DateTimeException(st.second = 60);
1964 
1965         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1966         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
1967         static assert(!__traits(compiles, cst.seconds = 27));
1968         static assert(!__traits(compiles, ist.seconds = 27));
1969 
1970         static void testScope(scope ref SysTime st) @safe
1971         {
1972             st.second = 12;
1973         }
1974     }
1975 
1976 
1977     /++
1978         Fractional seconds past the second (i.e. the portion of a
1979         $(LREF SysTime) which is less than a second).
1980      +/
1981     @property Duration fracSecs() @safe const nothrow scope
1982     {
1983         auto hnsecs = removeUnitsFromHNSecs!"days"(adjTime);
1984 
1985         if (hnsecs < 0)
1986             hnsecs += convert!("hours", "hnsecs")(24);
1987 
1988         return dur!"hnsecs"(removeUnitsFromHNSecs!"seconds"(hnsecs));
1989     }
1990 
1991     ///
1992     @safe unittest
1993     {
1994         import core.time : msecs, usecs, hnsecs, nsecs;
1995         import std.datetime.date : DateTime;
1996 
1997         auto dt = DateTime(1982, 4, 1, 20, 59, 22);
1998         assert(SysTime(dt, msecs(213)).fracSecs == msecs(213));
1999         assert(SysTime(dt, usecs(5202)).fracSecs == usecs(5202));
2000         assert(SysTime(dt, hnsecs(1234567)).fracSecs == hnsecs(1234567));
2001 
2002         // SysTime and Duration both have a precision of hnsecs (100 ns),
2003         // so nsecs are going to be truncated.
2004         assert(SysTime(dt, nsecs(123456789)).fracSecs == nsecs(123456700));
2005     }
2006 
2007     @safe unittest
2008     {
2009         import std.range : chain;
2010         import core.time;
2011 
2012         assert(SysTime(0, UTC()).fracSecs == Duration.zero);
2013         assert(SysTime(1, UTC()).fracSecs == hnsecs(1));
2014         assert(SysTime(-1, UTC()).fracSecs == hnsecs(9_999_999));
2015 
2016         foreach (tz; testTZs)
2017         {
2018             foreach (year; chain(testYearsBC, testYearsAD))
2019             {
2020                 foreach (md; testMonthDays)
2021                 {
2022                     foreach (hour; testHours)
2023                     {
2024                         foreach (minute; testMinSecs)
2025                         {
2026                             foreach (second; testMinSecs)
2027                             {
2028                                 auto dt = DateTime(Date(year, md.month, md.day), TimeOfDay(hour, minute, second));
2029                                 foreach (fs; testFracSecs)
2030                                     assert(SysTime(dt, fs, tz).fracSecs == fs);
2031                             }
2032                         }
2033                     }
2034                 }
2035             }
2036         }
2037 
2038         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2039         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2040         assert(cst.fracSecs == Duration.zero);
2041         assert(ist.fracSecs == Duration.zero);
2042 
2043         static void testScope(scope ref SysTime st) @safe
2044         {
2045             auto result = st.fracSecs;
2046         }
2047     }
2048 
2049 
2050     /++
2051         Fractional seconds past the second (i.e. the portion of a
2052         $(LREF SysTime) which is less than a second).
2053 
2054         Params:
2055             fracSecs = The duration to set this $(LREF SysTime)'s fractional
2056                        seconds to.
2057 
2058         Throws:
2059             $(REF DateTimeException,std,datetime,date) if the given duration
2060             is negative or if it's greater than or equal to one second.
2061      +/
2062     @property void fracSecs(Duration fracSecs) @safe scope
2063     {
2064         enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
2065         enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
2066 
2067         auto oldHNSecs = adjTime;
2068         auto days = splitUnitsFromHNSecs!"days"(oldHNSecs);
2069         immutable daysHNSecs = convert!("days", "hnsecs")(days);
2070         immutable negative = oldHNSecs < 0;
2071 
2072         if (negative)
2073             oldHNSecs += convert!("hours", "hnsecs")(24);
2074 
2075         immutable seconds = splitUnitsFromHNSecs!"seconds"(oldHNSecs);
2076         immutable secondsHNSecs = convert!("seconds", "hnsecs")(seconds);
2077         auto newHNSecs = fracSecs.total!"hnsecs" + secondsHNSecs;
2078 
2079         if (negative)
2080             newHNSecs -= convert!("hours", "hnsecs")(24);
2081 
2082         adjTime = daysHNSecs + newHNSecs;
2083     }
2084 
2085     ///
2086     @safe unittest
2087     {
2088         import core.time : Duration, msecs, hnsecs, nsecs;
2089         import std.datetime.date : DateTime;
2090 
2091         auto st = SysTime(DateTime(1982, 4, 1, 20, 59, 22));
2092         assert(st.fracSecs == Duration.zero);
2093 
2094         st.fracSecs = msecs(213);
2095         assert(st.fracSecs == msecs(213));
2096 
2097         st.fracSecs = hnsecs(1234567);
2098         assert(st.fracSecs == hnsecs(1234567));
2099 
2100         // SysTime has a precision of hnsecs (100 ns), so nsecs are
2101         // going to be truncated.
2102         st.fracSecs = nsecs(123456789);
2103         assert(st.fracSecs == hnsecs(1234567));
2104     }
2105 
2106     @safe unittest
2107     {
2108         import std.range : chain;
2109         import core.time;
2110 
2111         foreach (fracSec; testFracSecs)
2112         {
2113             foreach (st; chain(testSysTimesBC, testSysTimesAD))
2114             {
2115                 auto dt = cast(DateTime) st;
2116                 auto expected = SysTime(dt, fracSec, st.timezone);
2117                 st.fracSecs = fracSec;
2118                 assert(st == expected, format("[%s] [%s]", st, expected));
2119             }
2120         }
2121 
2122         auto st = testSysTimesAD[0];
2123         assertThrown!DateTimeException(st.fracSecs = hnsecs(-1));
2124         assertThrown!DateTimeException(st.fracSecs = seconds(1));
2125 
2126         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2127         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2128         static assert(!__traits(compiles, cst.fracSecs = msecs(7)));
2129         static assert(!__traits(compiles, ist.fracSecs = msecs(7)));
2130 
2131         static void testScope(scope ref SysTime st) @safe
2132         {
2133             st.fracSecs = Duration.zero;
2134         }
2135     }
2136 
2137 
2138     /++
2139         The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the
2140         internal representation of $(LREF SysTime).
2141      +/
2142     @property long stdTime() @safe const pure nothrow scope @nogc
2143     {
2144         return _stdTime;
2145     }
2146 
2147     @safe unittest
2148     {
2149         import core.time;
2150         assert(SysTime(0).stdTime == 0);
2151         assert(SysTime(1).stdTime == 1);
2152         assert(SysTime(-1).stdTime == -1);
2153         assert(SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC()).stdTime == 330_000_502L);
2154         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC()).stdTime == 621_355_968_000_000_000L);
2155 
2156         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2157         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2158         assert(cst.stdTime > 0);
2159         assert(ist.stdTime > 0);
2160 
2161         static void testScope(scope ref SysTime st) @safe
2162         {
2163             auto result = st.stdTime;
2164         }
2165     }
2166 
2167 
2168     /++
2169         The total hnsecs from midnight, January 1st, 1 A.D. UTC. This is the
2170         internal representation of $(LREF SysTime).
2171 
2172         Params:
2173             stdTime = The number of hnsecs since January 1st, 1 A.D. UTC.
2174      +/
2175     @property void stdTime(long stdTime) @safe pure nothrow scope
2176     {
2177         _stdTime = stdTime;
2178     }
2179 
2180     @safe unittest
2181     {
2182         import core.time;
2183         static void test(long stdTime, SysTime expected, size_t line = __LINE__)
2184         {
2185             auto st = SysTime(0, UTC());
2186             st.stdTime = stdTime;
2187             assert(st == expected);
2188         }
2189 
2190         test(0, SysTime(Date(1, 1, 1), UTC()));
2191         test(1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()));
2192         test(-1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()));
2193         test(330_000_502L, SysTime(DateTime(1, 1, 1, 0, 0, 33), hnsecs(502), UTC()));
2194         test(621_355_968_000_000_000L, SysTime(DateTime(1970, 1, 1, 0, 0, 0), UTC()));
2195 
2196         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2197         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
2198         static assert(!__traits(compiles, cst.stdTime = 27));
2199         static assert(!__traits(compiles, ist.stdTime = 27));
2200 
2201         static void testScope(scope ref SysTime st) @safe
2202         {
2203             st.stdTime = 42;
2204         }
2205     }
2206 
2207 
2208     /++
2209         The current time zone of this $(LREF SysTime). Its internal time is
2210         always kept in UTC, so there are no conversion issues between time zones
2211         due to DST. Functions which return all or part of the time - such as
2212         hours - adjust the time to this $(LREF SysTime)'s time zone before
2213         returning.
2214       +/
2215     @property immutable(TimeZone) timezone() @safe const pure nothrow return scope
2216     {
2217         return _timezone;
2218     }
2219 
2220     @safe unittest
2221     {
2222         assert(SysTime.init.timezone is InitTimeZone());
2223         assert(SysTime(DateTime.init, UTC()).timezone is UTC());
2224 
2225         static void testScope(scope ref SysTime st) @safe
2226         {
2227             auto result = st.timezone;
2228         }
2229     }
2230 
2231 
2232     /++
2233         The current time zone of this $(LREF SysTime). It's internal time is
2234         always kept in UTC, so there are no conversion issues between time zones
2235         due to DST. Functions which return all or part of the time - such as
2236         hours - adjust the time to this $(LREF SysTime)'s time zone before
2237         returning.
2238 
2239         Params:
2240             timezone = The $(REF _TimeZone,std,datetime,_timezone) to set this
2241                        $(LREF SysTime)'s time zone to.
2242       +/
2243     @property void timezone(immutable TimeZone timezone) @safe pure nothrow scope
2244     {
2245         if (timezone is null)
2246             _timezone = LocalTime();
2247         else
2248             _timezone = timezone;
2249     }
2250 
2251     @safe unittest
2252     {
2253         SysTime st;
2254         st.timezone = null;
2255         assert(st.timezone is LocalTime());
2256         st.timezone = UTC();
2257         assert(st.timezone is UTC());
2258 
2259         static void testScope(scope ref SysTime st) @safe
2260         {
2261             st.timezone = UTC();
2262         }
2263     }
2264 
2265 
2266     /++
2267         Returns whether DST is in effect for this $(LREF SysTime).
2268       +/
2269     @property bool dstInEffect() @safe const nothrow return scope
2270     {
2271         return _timezone.dstInEffect(_stdTime);
2272     }
2273 
2274     // This function's full unit testing is done in the time zone classes, but
2275     // this verifies that SysTime.init works correctly, since historically, it
2276     // has segfaulted due to a null _timezone.
2277     @safe unittest
2278     {
2279         assert(!SysTime.init.dstInEffect);
2280 
2281         static void testScope(scope ref SysTime st) @safe
2282         {
2283             auto result = st.dstInEffect;
2284         }
2285     }
2286 
2287 
2288     /++
2289         Returns what the offset from UTC is for this $(LREF SysTime).
2290         It includes the DST offset in effect at that time (if any).
2291       +/
2292     @property Duration utcOffset() @safe const nothrow return scope
2293     {
2294         return _timezone.utcOffsetAt(_stdTime);
2295     }
2296 
2297     // This function's full unit testing is done in the time zone classes, but
2298     // this verifies that SysTime.init works correctly, since historically, it
2299     // has segfaulted due to a null _timezone.
2300     @safe unittest
2301     {
2302         assert(SysTime.init.utcOffset == Duration.zero);
2303 
2304         static void testScope(scope ref SysTime st) @safe
2305         {
2306             auto result = st.utcOffset;
2307         }
2308     }
2309 
2310 
2311     /++
2312         Returns a $(LREF SysTime) with the same std time as this one, but with
2313         $(REF LocalTime,std,datetime,timezone) as its time zone.
2314       +/
2315     SysTime toLocalTime() @safe const pure nothrow scope
2316     {
2317         return SysTime(_stdTime, LocalTime());
2318     }
2319 
2320     @safe unittest
2321     {
2322         import core.time;
2323         {
2324             auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2325             assert(sysTime == sysTime.toLocalTime());
2326             assert(sysTime._stdTime == sysTime.toLocalTime()._stdTime);
2327             assert(sysTime.toLocalTime().timezone is LocalTime());
2328             assert(sysTime.toLocalTime().timezone is sysTime.timezone);
2329             assert(sysTime.toLocalTime().timezone !is UTC());
2330         }
2331 
2332         {
2333             auto stz = new immutable SimpleTimeZone(dur!"minutes"(-3 * 60));
2334             auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27), stz);
2335             assert(sysTime == sysTime.toLocalTime());
2336             assert(sysTime._stdTime == sysTime.toLocalTime()._stdTime);
2337             assert(sysTime.toLocalTime().timezone is LocalTime());
2338             assert(sysTime.toLocalTime().timezone !is UTC());
2339             assert(sysTime.toLocalTime().timezone !is stz);
2340         }
2341 
2342         static void testScope(scope ref SysTime st) @safe
2343         {
2344             auto result = st.toLocalTime();
2345         }
2346     }
2347 
2348 
2349     /++
2350         Returns a $(LREF SysTime) with the same std time as this one, but with
2351         `UTC` as its time zone.
2352       +/
2353     SysTime toUTC() @safe const pure nothrow scope
2354     {
2355         return SysTime(_stdTime, UTC());
2356     }
2357 
2358     @safe unittest
2359     {
2360         import core.time;
2361         auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2362         assert(sysTime == sysTime.toUTC());
2363         assert(sysTime._stdTime == sysTime.toUTC()._stdTime);
2364         assert(sysTime.toUTC().timezone is UTC());
2365         assert(sysTime.toUTC().timezone !is LocalTime());
2366         assert(sysTime.toUTC().timezone !is sysTime.timezone);
2367 
2368         static void testScope(scope ref SysTime st) @safe
2369         {
2370             auto result = st.toUTC();
2371         }
2372     }
2373 
2374 
2375     /++
2376         Returns a $(LREF SysTime) with the same std time as this one, but with
2377         given time zone as its time zone.
2378       +/
2379     SysTime toOtherTZ(immutable TimeZone tz) @safe const pure nothrow scope
2380     {
2381         if (tz is null)
2382             return SysTime(_stdTime, LocalTime());
2383         else
2384             return SysTime(_stdTime, tz);
2385     }
2386 
2387     @safe unittest
2388     {
2389         import core.time;
2390         auto stz = new immutable SimpleTimeZone(dur!"minutes"(11 * 60));
2391         auto sysTime = SysTime(DateTime(1982, 1, 4, 8, 59, 7), hnsecs(27));
2392         assert(sysTime == sysTime.toOtherTZ(stz));
2393         assert(sysTime._stdTime == sysTime.toOtherTZ(stz)._stdTime);
2394         assert(sysTime.toOtherTZ(stz).timezone is stz);
2395         assert(sysTime.toOtherTZ(stz).timezone !is LocalTime());
2396         assert(sysTime.toOtherTZ(stz).timezone !is UTC());
2397         assert(sysTime.toOtherTZ(null).timezone is LocalTime());
2398 
2399         static void testScope(scope ref SysTime st) @safe
2400         {
2401             auto result = st.toOtherTZ(null);
2402         }
2403     }
2404 
2405 
2406     /++
2407         Converts this $(LREF SysTime) to unix time (i.e. seconds from midnight,
2408         January 1st, 1970 in UTC).
2409 
2410         The C standard does not specify the representation of time_t, so it is
2411         implementation defined. On POSIX systems, unix time is equivalent to
2412         time_t, but that's not necessarily true on other systems (e.g. it is
2413         not true for the Digital Mars C runtime). So, be careful when using unix
2414         time with C functions on non-POSIX systems.
2415 
2416         By default, the return type is time_t (which is normally an alias for
2417         int on 32-bit systems and long on 64-bit systems), but if a different
2418         size is required than either int or long can be passed as a template
2419         argument to get the desired size.
2420 
2421         If the return type is int, and the result can't fit in an int, then the
2422         closest value that can be held in 32 bits will be used (so `int.max`
2423         if it goes over and `int.min` if it goes under). However, no attempt
2424         is made to deal with integer overflow if the return type is long.
2425 
2426         Params:
2427             T = The return type (int or long). It defaults to time_t, which is
2428                 normally 32 bits on a 32-bit system and 64 bits on a 64-bit
2429                 system.
2430 
2431         Returns:
2432             A signed integer representing the unix time which is equivalent to
2433             this SysTime.
2434       +/
2435     T toUnixTime(T = time_t)() @safe const pure nothrow scope
2436         if (is(T == int) || is(T == long))
2437     {
2438         return stdTimeToUnixTime!T(_stdTime);
2439     }
2440 
2441     ///
2442     @safe unittest
2443     {
2444         import core.time : hours;
2445         import std.datetime.date : DateTime;
2446         import std.datetime.timezone : SimpleTimeZone, UTC;
2447 
2448         assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0);
2449 
2450         auto pst = new immutable SimpleTimeZone(hours(-8));
2451         assert(SysTime(DateTime(1970, 1, 1), pst).toUnixTime() == 28800);
2452 
2453         auto utc = SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC());
2454         assert(utc.toUnixTime() == 1_198_311_285);
2455 
2456         auto ca = SysTime(DateTime(2007, 12, 22, 8, 14, 45), pst);
2457         assert(ca.toUnixTime() == 1_198_340_085);
2458 
2459         static void testScope(scope ref SysTime st) @safe
2460         {
2461             auto result = st.toUnixTime();
2462         }
2463     }
2464 
2465     @safe unittest
2466     {
2467         import std.meta : AliasSeq;
2468         import core.time;
2469         assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0);
2470         static foreach (units; ["hnsecs", "usecs", "msecs"])
2471             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 0), dur!units(1), UTC()).toUnixTime() == 0);
2472         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toUnixTime() == 1);
2473         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toUnixTime() == 0);
2474         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toUnixTime() == 0);
2475         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toUnixTime() == 0);
2476         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toUnixTime() == -1);
2477     }
2478 
2479 
2480     /++
2481         Converts from unix time (i.e. seconds from midnight, January 1st, 1970
2482         in UTC) to a $(LREF SysTime).
2483 
2484         The C standard does not specify the representation of time_t, so it is
2485         implementation defined. On POSIX systems, unix time is equivalent to
2486         time_t, but that's not necessarily true on other systems (e.g. it is
2487         not true for the Digital Mars C runtime). So, be careful when using unix
2488         time with C functions on non-POSIX systems.
2489 
2490         Params:
2491             unixTime = Seconds from midnight, January 1st, 1970 in UTC.
2492             tz = The time zone for the SysTime that's returned.
2493       +/
2494     static SysTime fromUnixTime(long unixTime, immutable TimeZone tz = LocalTime()) @safe pure nothrow
2495     {
2496         return SysTime(unixTimeToStdTime(unixTime), tz);
2497     }
2498 
2499     ///
2500     @safe unittest
2501     {
2502         import core.time : hours;
2503         import std.datetime.date : DateTime;
2504         import std.datetime.timezone : SimpleTimeZone, UTC;
2505 
2506         assert(SysTime.fromUnixTime(0) ==
2507                SysTime(DateTime(1970, 1, 1), UTC()));
2508 
2509         auto pst = new immutable SimpleTimeZone(hours(-8));
2510         assert(SysTime.fromUnixTime(28800) ==
2511                SysTime(DateTime(1970, 1, 1), pst));
2512 
2513         auto st1 = SysTime.fromUnixTime(1_198_311_285, UTC());
2514         assert(st1 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC()));
2515         assert(st1.timezone is UTC());
2516         assert(st1 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst));
2517 
2518         auto st2 = SysTime.fromUnixTime(1_198_311_285, pst);
2519         assert(st2 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC()));
2520         assert(st2.timezone is pst);
2521         assert(st2 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst));
2522     }
2523 
2524     @safe unittest
2525     {
2526         import core.time;
2527         assert(SysTime.fromUnixTime(0) == SysTime(DateTime(1970, 1, 1), UTC()));
2528         assert(SysTime.fromUnixTime(1) == SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()));
2529         assert(SysTime.fromUnixTime(-1) == SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()));
2530 
2531         auto st = SysTime.fromUnixTime(0);
2532         auto dt = cast(DateTime) st;
2533         assert(dt <= DateTime(1970, 2, 1) && dt >= DateTime(1969, 12, 31));
2534         assert(st.timezone is LocalTime());
2535 
2536         auto aest = new immutable SimpleTimeZone(hours(10));
2537         assert(SysTime.fromUnixTime(-36000) == SysTime(DateTime(1970, 1, 1), aest));
2538     }
2539 
2540 
2541     /++
2542         Returns a `timeval` which represents this $(LREF SysTime).
2543 
2544         Note that like all conversions in std.datetime, this is a truncating
2545         conversion.
2546 
2547         If `timeval.tv_sec` is int, and the result can't fit in an int, then
2548         the closest value that can be held in 32 bits will be used for
2549         `tv_sec`. (so `int.max` if it goes over and `int.min` if it
2550         goes under).
2551       +/
2552     timeval toTimeVal() @safe const pure nothrow scope
2553     {
2554         immutable tv_sec = toUnixTime!(typeof(timeval.tv_sec))();
2555         immutable fracHNSecs = removeUnitsFromHNSecs!"seconds"(_stdTime - 621_355_968_000_000_000L);
2556         immutable tv_usec = cast(typeof(timeval.tv_usec))convert!("hnsecs", "usecs")(fracHNSecs);
2557         return timeval(tv_sec, tv_usec);
2558     }
2559 
2560     @safe unittest
2561     {
2562         import core.time;
2563         assert(SysTime(DateTime(1970, 1, 1), UTC()).toTimeVal() == timeval(0, 0));
2564         assert(SysTime(DateTime(1970, 1, 1), hnsecs(9), UTC()).toTimeVal() == timeval(0, 0));
2565         assert(SysTime(DateTime(1970, 1, 1), hnsecs(10), UTC()).toTimeVal() == timeval(0, 1));
2566         assert(SysTime(DateTime(1970, 1, 1), usecs(7), UTC()).toTimeVal() == timeval(0, 7));
2567 
2568         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toTimeVal() == timeval(1, 0));
2569         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(9), UTC()).toTimeVal() == timeval(1, 0));
2570         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(10), UTC()).toTimeVal() == timeval(1, 1));
2571         assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), usecs(7), UTC()).toTimeVal() == timeval(1, 7));
2572 
2573         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toTimeVal() == timeval(0, 0));
2574         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_990), UTC()).toTimeVal() == timeval(0, -1));
2575 
2576         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toTimeVal() == timeval(0, -1));
2577         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999), UTC()).toTimeVal() == timeval(0, -999_001));
2578         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toTimeVal() == timeval(0, -1000));
2579         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toTimeVal() == timeval(-1, 0));
2580         assert(SysTime(DateTime(1969, 12, 31, 23, 59, 58), usecs(17), UTC()).toTimeVal() == timeval(-1, -999_983));
2581 
2582         static void testScope(scope ref SysTime st) @safe
2583         {
2584             auto result = st.toTimeVal();
2585         }
2586     }
2587 
2588 
2589     version (StdDdoc)
2590     {
2591         version (Windows) private struct timespec {}
2592         /++
2593             Returns a `timespec` which represents this $(LREF SysTime).
2594 
2595             $(BLUE This function is Posix-Only.)
2596           +/
2597         timespec toTimeSpec() @safe const pure nothrow scope;
2598     }
2599     else version (Posix)
2600     {
2601         timespec toTimeSpec() @safe const pure nothrow scope
2602         {
2603             immutable tv_sec = toUnixTime!(typeof(timespec.tv_sec))();
2604             immutable fracHNSecs = removeUnitsFromHNSecs!"seconds"(_stdTime - 621_355_968_000_000_000L);
2605             immutable tv_nsec = cast(typeof(timespec.tv_nsec))convert!("hnsecs", "nsecs")(fracHNSecs);
2606             return timespec(tv_sec, tv_nsec);
2607         }
2608 
2609         @safe unittest
2610         {
2611             import core.time;
2612             assert(SysTime(DateTime(1970, 1, 1), UTC()).toTimeSpec() == timespec(0, 0));
2613             assert(SysTime(DateTime(1970, 1, 1), hnsecs(9), UTC()).toTimeSpec() == timespec(0, 900));
2614             assert(SysTime(DateTime(1970, 1, 1), hnsecs(10), UTC()).toTimeSpec() == timespec(0, 1000));
2615             assert(SysTime(DateTime(1970, 1, 1), usecs(7), UTC()).toTimeSpec() == timespec(0, 7000));
2616 
2617             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), UTC()).toTimeSpec() == timespec(1, 0));
2618             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(9), UTC()).toTimeSpec() == timespec(1, 900));
2619             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), hnsecs(10), UTC()).toTimeSpec() == timespec(1, 1000));
2620             assert(SysTime(DateTime(1970, 1, 1, 0, 0, 1), usecs(7), UTC()).toTimeSpec() == timespec(1, 7000));
2621 
2622             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toTimeSpec() ==
2623                    timespec(0, -100));
2624             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), hnsecs(9_999_990), UTC()).toTimeSpec() ==
2625                    timespec(0, -1000));
2626 
2627             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999_999), UTC()).toTimeSpec() ==
2628                    timespec(0, -1_000));
2629             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), usecs(999), UTC()).toTimeSpec() ==
2630                    timespec(0, -999_001_000));
2631             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), msecs(999), UTC()).toTimeSpec() ==
2632                    timespec(0, -1_000_000));
2633             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 59), UTC()).toTimeSpec() ==
2634                    timespec(-1, 0));
2635             assert(SysTime(DateTime(1969, 12, 31, 23, 59, 58), usecs(17), UTC()).toTimeSpec() ==
2636                    timespec(-1, -999_983_000));
2637 
2638             static void testScope(scope ref SysTime st) @safe
2639             {
2640                 auto result = st.toTimeSpec();
2641             }
2642         }
2643     }
2644 
2645     /++
2646         Returns a `tm` which represents this $(LREF SysTime).
2647       +/
2648     tm toTM() @safe const nothrow scope
2649     {
2650         auto dateTime = cast(DateTime) this;
2651         tm timeInfo;
2652 
2653         timeInfo.tm_sec = dateTime.second;
2654         timeInfo.tm_min = dateTime.minute;
2655         timeInfo.tm_hour = dateTime.hour;
2656         timeInfo.tm_mday = dateTime.day;
2657         timeInfo.tm_mon = dateTime.month - 1;
2658         timeInfo.tm_year = dateTime.year - 1900;
2659         timeInfo.tm_wday = dateTime.dayOfWeek;
2660         timeInfo.tm_yday = dateTime.dayOfYear - 1;
2661         timeInfo.tm_isdst = _timezone.dstInEffect(_stdTime);
2662 
2663         version (Posix)
2664         {
2665             import std.utf : toUTFz;
2666             timeInfo.tm_gmtoff = cast(int) convert!("hnsecs", "seconds")(adjTime - _stdTime);
2667             auto zone = timeInfo.tm_isdst ? _timezone.dstName : _timezone.stdName;
2668             timeInfo.tm_zone = zone.toUTFz!(char*)();
2669         }
2670 
2671         return timeInfo;
2672     }
2673 
2674     @system unittest
2675     {
2676         import std.conv : to;
2677         import core.time;
2678 
2679         version (Posix)
2680         {
2681             import std.datetime.timezone : clearTZEnvVar, setTZEnvVar;
2682             setTZEnvVar("America/Los_Angeles");
2683             scope(exit) clearTZEnvVar();
2684         }
2685 
2686         {
2687             auto timeInfo = SysTime(DateTime(1970, 1, 1)).toTM();
2688 
2689             assert(timeInfo.tm_sec == 0);
2690             assert(timeInfo.tm_min == 0);
2691             assert(timeInfo.tm_hour == 0);
2692             assert(timeInfo.tm_mday == 1);
2693             assert(timeInfo.tm_mon == 0);
2694             assert(timeInfo.tm_year == 70);
2695             assert(timeInfo.tm_wday == 4);
2696             assert(timeInfo.tm_yday == 0);
2697 
2698             version (Posix)
2699                 assert(timeInfo.tm_isdst == 0);
2700             else version (Windows)
2701                 assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
2702 
2703             version (Posix)
2704             {
2705                 assert(timeInfo.tm_gmtoff == -8 * 60 * 60);
2706                 assert(to!string(timeInfo.tm_zone) == "PST");
2707             }
2708         }
2709 
2710         {
2711             auto timeInfo = SysTime(DateTime(2010, 7, 4, 12, 15, 7), hnsecs(15)).toTM();
2712 
2713             assert(timeInfo.tm_sec == 7);
2714             assert(timeInfo.tm_min == 15);
2715             assert(timeInfo.tm_hour == 12);
2716             assert(timeInfo.tm_mday == 4);
2717             assert(timeInfo.tm_mon == 6);
2718             assert(timeInfo.tm_year == 110);
2719             assert(timeInfo.tm_wday == 0);
2720             assert(timeInfo.tm_yday == 184);
2721 
2722             version (Posix)
2723                 assert(timeInfo.tm_isdst == 1);
2724             else version (Windows)
2725                 assert(timeInfo.tm_isdst == 0 || timeInfo.tm_isdst == 1);
2726 
2727             version (Posix)
2728             {
2729                 assert(timeInfo.tm_gmtoff == -7 * 60 * 60);
2730                 assert(to!string(timeInfo.tm_zone) == "PDT");
2731             }
2732         }
2733 
2734         // This is more to verify that SysTime.init.toTM() doesn't segfault and
2735         // does something sane rather than that the value is anything
2736         // particularly useful.
2737         {
2738             auto timeInfo = SysTime.init.toTM();
2739 
2740             assert(timeInfo.tm_sec == 0);
2741             assert(timeInfo.tm_min == 0);
2742             assert(timeInfo.tm_hour == 0);
2743             assert(timeInfo.tm_mday == 1);
2744             assert(timeInfo.tm_mon == 0);
2745             assert(timeInfo.tm_year == -1899);
2746             assert(timeInfo.tm_wday == 1);
2747             assert(timeInfo.tm_yday == 0);
2748             assert(timeInfo.tm_isdst == 0);
2749 
2750             version (Posix)
2751             {
2752                 assert(timeInfo.tm_gmtoff == 0);
2753                 assert(to!string(timeInfo.tm_zone) == "SysTime.init's timezone");
2754             }
2755         }
2756 
2757         static void testScope(scope ref SysTime st) @safe
2758         {
2759             auto result = st.toTM();
2760         }
2761     }
2762 
2763 
2764     /++
2765         Adds the given number of years or months to this $(LREF SysTime). A
2766         negative number will subtract.
2767 
2768         Note that if day overflow is allowed, and the date with the adjusted
2769         year/month overflows the number of days in the new month, then the month
2770         will be incremented by one, and the day set to the number of days
2771         overflowed. (e.g. if the day were 31 and the new month were June, then
2772         the month would be incremented to July, and the new day would be 1). If
2773         day overflow is not allowed, then the day will be set to the last valid
2774         day in the month (e.g. June 31st would become June 30th).
2775 
2776         Params:
2777             units         = The type of units to add ("years" or "months").
2778             value         = The number of months or years to add to this
2779                             $(LREF SysTime).
2780             allowOverflow = Whether the days should be allowed to overflow,
2781                             causing the month to increment.
2782       +/
2783     ref SysTime add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow scope
2784         if (units == "years" || units == "months")
2785     {
2786         auto hnsecs = adjTime;
2787         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
2788 
2789         if (hnsecs < 0)
2790         {
2791             hnsecs += convert!("hours", "hnsecs")(24);
2792             --days;
2793         }
2794 
2795         auto date = Date(cast(int) days);
2796         date.add!units(value, allowOverflow);
2797         days = date.dayOfGregorianCal - 1;
2798 
2799         if (days < 0)
2800         {
2801             hnsecs -= convert!("hours", "hnsecs")(24);
2802             ++days;
2803         }
2804 
2805         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
2806 
2807         adjTime = newDaysHNSecs + hnsecs;
2808 
2809         return this;
2810     }
2811 
2812     @safe unittest
2813     {
2814         auto st1 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
2815         st1.add!"months"(11);
2816         assert(st1 == SysTime(DateTime(2010, 12, 1, 12, 30, 33)));
2817 
2818         auto st2 = SysTime(DateTime(2010, 1, 1, 12, 30, 33));
2819         st2.add!"months"(-11);
2820         assert(st2 == SysTime(DateTime(2009, 2, 1, 12, 30, 33)));
2821 
2822         auto st3 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
2823         st3.add!"years"(1);
2824         assert(st3 == SysTime(DateTime(2001, 3, 1, 12, 30, 33)));
2825 
2826         auto st4 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
2827         st4.add!"years"(1, AllowDayOverflow.no);
2828         assert(st4 == SysTime(DateTime(2001, 2, 28, 12, 30, 33)));
2829     }
2830 
2831     // Test add!"years"() with AllowDayOverflow.yes
2832     @safe unittest
2833     {
2834         import core.time;
2835         // Test A.D.
2836         {
2837             auto sysTime = SysTime(Date(1999, 7, 6));
2838             sysTime.add!"years"(7);
2839             assert(sysTime == SysTime(Date(2006, 7, 6)));
2840             sysTime.add!"years"(-9);
2841             assert(sysTime == SysTime(Date(1997, 7, 6)));
2842         }
2843 
2844         {
2845             auto sysTime = SysTime(Date(1999, 2, 28));
2846             sysTime.add!"years"(1);
2847             assert(sysTime == SysTime(Date(2000, 2, 28)));
2848         }
2849 
2850         {
2851             auto sysTime = SysTime(Date(2000, 2, 29));
2852             sysTime.add!"years"(-1);
2853             assert(sysTime == SysTime(Date(1999, 3, 1)));
2854         }
2855 
2856         {
2857             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234));
2858             sysTime.add!"years"(7);
2859             assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234)));
2860             sysTime.add!"years"(-9);
2861             assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234)));
2862         }
2863 
2864         {
2865             auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207));
2866             sysTime.add!"years"(1);
2867             assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207)));
2868         }
2869 
2870         {
2871             auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207));
2872             sysTime.add!"years"(-1);
2873             assert(sysTime == SysTime(DateTime(1999, 3, 1, 0, 7, 2), usecs(1207)));
2874         }
2875 
2876         // Test B.C.
2877         {
2878             auto sysTime = SysTime(Date(-1999, 7, 6));
2879             sysTime.add!"years"(-7);
2880             assert(sysTime == SysTime(Date(-2006, 7, 6)));
2881             sysTime.add!"years"(9);
2882             assert(sysTime == SysTime(Date(-1997, 7, 6)));
2883         }
2884 
2885         {
2886             auto sysTime = SysTime(Date(-1999, 2, 28));
2887             sysTime.add!"years"(-1);
2888             assert(sysTime == SysTime(Date(-2000, 2, 28)));
2889         }
2890 
2891         {
2892             auto sysTime = SysTime(Date(-2000, 2, 29));
2893             sysTime.add!"years"(1);
2894             assert(sysTime == SysTime(Date(-1999, 3, 1)));
2895         }
2896 
2897         {
2898             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234));
2899             sysTime.add!"years"(-7);
2900             assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234)));
2901             sysTime.add!"years"(9);
2902             assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234)));
2903         }
2904 
2905         {
2906             auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3));
2907             sysTime.add!"years"(-1);
2908             assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3)));
2909         }
2910 
2911         {
2912             auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3));
2913             sysTime.add!"years"(1);
2914             assert(sysTime == SysTime(DateTime(-1999, 3, 1, 3, 3, 3), hnsecs(3)));
2915         }
2916 
2917         // Test Both
2918         {
2919             auto sysTime = SysTime(Date(4, 7, 6));
2920             sysTime.add!"years"(-5);
2921             assert(sysTime == SysTime(Date(-1, 7, 6)));
2922             sysTime.add!"years"(5);
2923             assert(sysTime == SysTime(Date(4, 7, 6)));
2924         }
2925 
2926         {
2927             auto sysTime = SysTime(Date(-4, 7, 6));
2928             sysTime.add!"years"(5);
2929             assert(sysTime == SysTime(Date(1, 7, 6)));
2930             sysTime.add!"years"(-5);
2931             assert(sysTime == SysTime(Date(-4, 7, 6)));
2932         }
2933 
2934         {
2935             auto sysTime = SysTime(Date(4, 7, 6));
2936             sysTime.add!"years"(-8);
2937             assert(sysTime == SysTime(Date(-4, 7, 6)));
2938             sysTime.add!"years"(8);
2939             assert(sysTime == SysTime(Date(4, 7, 6)));
2940         }
2941 
2942         {
2943             auto sysTime = SysTime(Date(-4, 7, 6));
2944             sysTime.add!"years"(8);
2945             assert(sysTime == SysTime(Date(4, 7, 6)));
2946             sysTime.add!"years"(-8);
2947             assert(sysTime == SysTime(Date(-4, 7, 6)));
2948         }
2949 
2950         {
2951             auto sysTime = SysTime(Date(-4, 2, 29));
2952             sysTime.add!"years"(5);
2953             assert(sysTime == SysTime(Date(1, 3, 1)));
2954         }
2955 
2956         {
2957             auto sysTime = SysTime(Date(4, 2, 29));
2958             sysTime.add!"years"(-5);
2959             assert(sysTime == SysTime(Date(-1, 3, 1)));
2960         }
2961 
2962         {
2963             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
2964             sysTime.add!"years"(-1);
2965             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2966             sysTime.add!"years"(1);
2967             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2968         }
2969 
2970         {
2971             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2972             sysTime.add!"years"(-1);
2973             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2974             sysTime.add!"years"(1);
2975             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2976         }
2977 
2978         {
2979             auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0));
2980             sysTime.add!"years"(1);
2981             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
2982             sysTime.add!"years"(-1);
2983             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
2984         }
2985 
2986         {
2987             auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999));
2988             sysTime.add!"years"(1);
2989             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2990             sysTime.add!"years"(-1);
2991             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
2992         }
2993 
2994         {
2995             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
2996             sysTime.add!"years"(-5);
2997             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
2998             sysTime.add!"years"(5);
2999             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
3000         }
3001 
3002         {
3003             auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329));
3004             sysTime.add!"years"(5);
3005             assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329)));
3006             sysTime.add!"years"(-5);
3007             assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)));
3008         }
3009 
3010         {
3011             auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555));
3012             sysTime.add!"years"(5);
3013             assert(sysTime == SysTime(DateTime(1, 3, 1, 5, 5, 5), msecs(555)));
3014         }
3015 
3016         {
3017             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
3018             sysTime.add!"years"(-5);
3019             assert(sysTime == SysTime(DateTime(-1, 3, 1, 5, 5, 5), msecs(555)));
3020         }
3021 
3022         {
3023             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
3024             sysTime.add!"years"(-5).add!"years"(7);
3025             assert(sysTime == SysTime(DateTime(6, 3, 1, 5, 5, 5), msecs(555)));
3026         }
3027 
3028         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3029         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3030         static assert(!__traits(compiles, cst.add!"years"(4)));
3031         static assert(!__traits(compiles, ist.add!"years"(4)));
3032 
3033         static void testScope(scope ref SysTime st) @safe
3034         {
3035             auto result = st.add!"years"(42);
3036         }
3037     }
3038 
3039     // Test add!"years"() with AllowDayOverflow.no
3040     @safe unittest
3041     {
3042         import core.time;
3043         // Test A.D.
3044         {
3045             auto sysTime = SysTime(Date(1999, 7, 6));
3046             sysTime.add!"years"(7, AllowDayOverflow.no);
3047             assert(sysTime == SysTime(Date(2006, 7, 6)));
3048             sysTime.add!"years"(-9, AllowDayOverflow.no);
3049             assert(sysTime == SysTime(Date(1997, 7, 6)));
3050         }
3051 
3052         {
3053             auto sysTime = SysTime(Date(1999, 2, 28));
3054             sysTime.add!"years"(1, AllowDayOverflow.no);
3055             assert(sysTime == SysTime(Date(2000, 2, 28)));
3056         }
3057 
3058         {
3059             auto sysTime = SysTime(Date(2000, 2, 29));
3060             sysTime.add!"years"(-1, AllowDayOverflow.no);
3061             assert(sysTime == SysTime(Date(1999, 2, 28)));
3062         }
3063 
3064         {
3065             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 7, 3), msecs(234));
3066             sysTime.add!"years"(7, AllowDayOverflow.no);
3067             assert(sysTime == SysTime(DateTime(2006, 7, 6, 12, 7, 3), msecs(234)));
3068             sysTime.add!"years"(-9, AllowDayOverflow.no);
3069             assert(sysTime == SysTime(DateTime(1997, 7, 6, 12, 7, 3), msecs(234)));
3070         }
3071 
3072         {
3073             auto sysTime = SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207));
3074             sysTime.add!"years"(1, AllowDayOverflow.no);
3075             assert(sysTime == SysTime(DateTime(2000, 2, 28, 0, 7, 2), usecs(1207)));
3076         }
3077 
3078         {
3079             auto sysTime = SysTime(DateTime(2000, 2, 29, 0, 7, 2), usecs(1207));
3080             sysTime.add!"years"(-1, AllowDayOverflow.no);
3081             assert(sysTime == SysTime(DateTime(1999, 2, 28, 0, 7, 2), usecs(1207)));
3082         }
3083 
3084         // Test B.C.
3085         {
3086             auto sysTime = SysTime(Date(-1999, 7, 6));
3087             sysTime.add!"years"(-7, AllowDayOverflow.no);
3088             assert(sysTime == SysTime(Date(-2006, 7, 6)));
3089             sysTime.add!"years"(9, AllowDayOverflow.no);
3090             assert(sysTime == SysTime(Date(-1997, 7, 6)));
3091         }
3092 
3093         {
3094             auto sysTime = SysTime(Date(-1999, 2, 28));
3095             sysTime.add!"years"(-1, AllowDayOverflow.no);
3096             assert(sysTime == SysTime(Date(-2000, 2, 28)));
3097         }
3098 
3099         {
3100             auto sysTime = SysTime(Date(-2000, 2, 29));
3101             sysTime.add!"years"(1, AllowDayOverflow.no);
3102             assert(sysTime == SysTime(Date(-1999, 2, 28)));
3103         }
3104 
3105         {
3106             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 7, 3), msecs(234));
3107             sysTime.add!"years"(-7, AllowDayOverflow.no);
3108             assert(sysTime == SysTime(DateTime(-2006, 7, 6, 12, 7, 3), msecs(234)));
3109             sysTime.add!"years"(9, AllowDayOverflow.no);
3110             assert(sysTime == SysTime(DateTime(-1997, 7, 6, 12, 7, 3), msecs(234)));
3111         }
3112 
3113         {
3114             auto sysTime = SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3));
3115             sysTime.add!"years"(-1, AllowDayOverflow.no);
3116             assert(sysTime == SysTime(DateTime(-2000, 2, 28, 3, 3, 3), hnsecs(3)));
3117         }
3118 
3119         {
3120             auto sysTime = SysTime(DateTime(-2000, 2, 29, 3, 3, 3), hnsecs(3));
3121             sysTime.add!"years"(1, AllowDayOverflow.no);
3122             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 3, 3, 3), hnsecs(3)));
3123         }
3124 
3125         // Test Both
3126         {
3127             auto sysTime = SysTime(Date(4, 7, 6));
3128             sysTime.add!"years"(-5, AllowDayOverflow.no);
3129             assert(sysTime == SysTime(Date(-1, 7, 6)));
3130             sysTime.add!"years"(5, AllowDayOverflow.no);
3131             assert(sysTime == SysTime(Date(4, 7, 6)));
3132         }
3133 
3134         {
3135             auto sysTime = SysTime(Date(-4, 7, 6));
3136             sysTime.add!"years"(5, AllowDayOverflow.no);
3137             assert(sysTime == SysTime(Date(1, 7, 6)));
3138             sysTime.add!"years"(-5, AllowDayOverflow.no);
3139             assert(sysTime == SysTime(Date(-4, 7, 6)));
3140         }
3141 
3142         {
3143             auto sysTime = SysTime(Date(4, 7, 6));
3144             sysTime.add!"years"(-8, AllowDayOverflow.no);
3145             assert(sysTime == SysTime(Date(-4, 7, 6)));
3146             sysTime.add!"years"(8, AllowDayOverflow.no);
3147             assert(sysTime == SysTime(Date(4, 7, 6)));
3148         }
3149 
3150         {
3151             auto sysTime = SysTime(Date(-4, 7, 6));
3152             sysTime.add!"years"(8, AllowDayOverflow.no);
3153             assert(sysTime == SysTime(Date(4, 7, 6)));
3154             sysTime.add!"years"(-8, AllowDayOverflow.no);
3155             assert(sysTime == SysTime(Date(-4, 7, 6)));
3156         }
3157 
3158         {
3159             auto sysTime = SysTime(Date(-4, 2, 29));
3160             sysTime.add!"years"(5, AllowDayOverflow.no);
3161             assert(sysTime == SysTime(Date(1, 2, 28)));
3162         }
3163 
3164         {
3165             auto sysTime = SysTime(Date(4, 2, 29));
3166             sysTime.add!"years"(-5, AllowDayOverflow.no);
3167             assert(sysTime == SysTime(Date(-1, 2, 28)));
3168         }
3169 
3170         {
3171             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3172             sysTime.add!"years"(-1, AllowDayOverflow.no);
3173             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
3174             sysTime.add!"years"(1, AllowDayOverflow.no);
3175             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3176         }
3177 
3178         {
3179             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3180             sysTime.add!"years"(-1, AllowDayOverflow.no);
3181             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3182             sysTime.add!"years"(1, AllowDayOverflow.no);
3183             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3184         }
3185 
3186         {
3187             auto sysTime = SysTime(DateTime(0, 1, 1, 0, 0, 0));
3188             sysTime.add!"years"(1, AllowDayOverflow.no);
3189             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3190             sysTime.add!"years"(-1, AllowDayOverflow.no);
3191             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
3192         }
3193 
3194         {
3195             auto sysTime = SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3196             sysTime.add!"years"(1, AllowDayOverflow.no);
3197             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3198             sysTime.add!"years"(-1, AllowDayOverflow.no);
3199             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3200         }
3201 
3202         {
3203             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
3204             sysTime.add!"years"(-5);
3205             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
3206             sysTime.add!"years"(5);
3207             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
3208         }
3209 
3210         {
3211             auto sysTime = SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329));
3212             sysTime.add!"years"(-5, AllowDayOverflow.no);
3213             assert(sysTime == SysTime(DateTime(-1, 7, 6, 14, 7, 1), usecs(54329)));
3214             sysTime.add!"years"(5, AllowDayOverflow.no);
3215             assert(sysTime == SysTime(DateTime(4, 7, 6, 14, 7, 1), usecs(54329)));
3216         }
3217 
3218         {
3219             auto sysTime = SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329));
3220             sysTime.add!"years"(5, AllowDayOverflow.no);
3221             assert(sysTime == SysTime(DateTime(1, 7, 6, 14, 7, 1), usecs(54329)));
3222             sysTime.add!"years"(-5, AllowDayOverflow.no);
3223             assert(sysTime == SysTime(DateTime(-4, 7, 6, 14, 7, 1), usecs(54329)));
3224         }
3225 
3226         {
3227             auto sysTime = SysTime(DateTime(-4, 2, 29, 5, 5, 5), msecs(555));
3228             sysTime.add!"years"(5, AllowDayOverflow.no);
3229             assert(sysTime == SysTime(DateTime(1, 2, 28, 5, 5, 5), msecs(555)));
3230         }
3231 
3232         {
3233             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
3234             sysTime.add!"years"(-5, AllowDayOverflow.no);
3235             assert(sysTime == SysTime(DateTime(-1, 2, 28, 5, 5, 5), msecs(555)));
3236         }
3237 
3238         {
3239             auto sysTime = SysTime(DateTime(4, 2, 29, 5, 5, 5), msecs(555));
3240             sysTime.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no);
3241             assert(sysTime == SysTime(DateTime(6, 2, 28, 5, 5, 5), msecs(555)));
3242         }
3243     }
3244 
3245     // Test add!"months"() with AllowDayOverflow.yes
3246     @safe unittest
3247     {
3248         import core.time;
3249         // Test A.D.
3250         {
3251             auto sysTime = SysTime(Date(1999, 7, 6));
3252             sysTime.add!"months"(3);
3253             assert(sysTime == SysTime(Date(1999, 10, 6)));
3254             sysTime.add!"months"(-4);
3255             assert(sysTime == SysTime(Date(1999, 6, 6)));
3256         }
3257 
3258         {
3259             auto sysTime = SysTime(Date(1999, 7, 6));
3260             sysTime.add!"months"(6);
3261             assert(sysTime == SysTime(Date(2000, 1, 6)));
3262             sysTime.add!"months"(-6);
3263             assert(sysTime == SysTime(Date(1999, 7, 6)));
3264         }
3265 
3266         {
3267             auto sysTime = SysTime(Date(1999, 7, 6));
3268             sysTime.add!"months"(27);
3269             assert(sysTime == SysTime(Date(2001, 10, 6)));
3270             sysTime.add!"months"(-28);
3271             assert(sysTime == SysTime(Date(1999, 6, 6)));
3272         }
3273 
3274         {
3275             auto sysTime = SysTime(Date(1999, 5, 31));
3276             sysTime.add!"months"(1);
3277             assert(sysTime == SysTime(Date(1999, 7, 1)));
3278         }
3279 
3280         {
3281             auto sysTime = SysTime(Date(1999, 5, 31));
3282             sysTime.add!"months"(-1);
3283             assert(sysTime == SysTime(Date(1999, 5, 1)));
3284         }
3285 
3286         {
3287             auto sysTime = SysTime(Date(1999, 2, 28));
3288             sysTime.add!"months"(12);
3289             assert(sysTime == SysTime(Date(2000, 2, 28)));
3290         }
3291 
3292         {
3293             auto sysTime = SysTime(Date(2000, 2, 29));
3294             sysTime.add!"months"(12);
3295             assert(sysTime == SysTime(Date(2001, 3, 1)));
3296         }
3297 
3298         {
3299             auto sysTime = SysTime(Date(1999, 7, 31));
3300             sysTime.add!"months"(1);
3301             assert(sysTime == SysTime(Date(1999, 8, 31)));
3302             sysTime.add!"months"(1);
3303             assert(sysTime == SysTime(Date(1999, 10, 1)));
3304         }
3305 
3306         {
3307             auto sysTime = SysTime(Date(1998, 8, 31));
3308             sysTime.add!"months"(13);
3309             assert(sysTime == SysTime(Date(1999, 10, 1)));
3310             sysTime.add!"months"(-13);
3311             assert(sysTime == SysTime(Date(1998, 9, 1)));
3312         }
3313 
3314         {
3315             auto sysTime = SysTime(Date(1997, 12, 31));
3316             sysTime.add!"months"(13);
3317             assert(sysTime == SysTime(Date(1999, 1, 31)));
3318             sysTime.add!"months"(-13);
3319             assert(sysTime == SysTime(Date(1997, 12, 31)));
3320         }
3321 
3322         {
3323             auto sysTime = SysTime(Date(1997, 12, 31));
3324             sysTime.add!"months"(14);
3325             assert(sysTime == SysTime(Date(1999, 3, 3)));
3326             sysTime.add!"months"(-14);
3327             assert(sysTime == SysTime(Date(1998, 1, 3)));
3328         }
3329 
3330         {
3331             auto sysTime = SysTime(Date(1998, 12, 31));
3332             sysTime.add!"months"(14);
3333             assert(sysTime == SysTime(Date(2000, 3, 2)));
3334             sysTime.add!"months"(-14);
3335             assert(sysTime == SysTime(Date(1999, 1, 2)));
3336         }
3337 
3338         {
3339             auto sysTime = SysTime(Date(1999, 12, 31));
3340             sysTime.add!"months"(14);
3341             assert(sysTime == SysTime(Date(2001, 3, 3)));
3342             sysTime.add!"months"(-14);
3343             assert(sysTime == SysTime(Date(2000, 1, 3)));
3344         }
3345 
3346         {
3347             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
3348             sysTime.add!"months"(3);
3349             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
3350             sysTime.add!"months"(-4);
3351             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
3352         }
3353 
3354         {
3355             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
3356             sysTime.add!"months"(14);
3357             assert(sysTime == SysTime(DateTime(2000, 3, 2, 7, 7, 7), hnsecs(422202)));
3358             sysTime.add!"months"(-14);
3359             assert(sysTime == SysTime(DateTime(1999, 1, 2, 7, 7, 7), hnsecs(422202)));
3360         }
3361 
3362         {
3363             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
3364             sysTime.add!"months"(14);
3365             assert(sysTime == SysTime(DateTime(2001, 3, 3, 7, 7, 7), hnsecs(422202)));
3366             sysTime.add!"months"(-14);
3367             assert(sysTime == SysTime(DateTime(2000, 1, 3, 7, 7, 7), hnsecs(422202)));
3368         }
3369 
3370         // Test B.C.
3371         {
3372             auto sysTime = SysTime(Date(-1999, 7, 6));
3373             sysTime.add!"months"(3);
3374             assert(sysTime == SysTime(Date(-1999, 10, 6)));
3375             sysTime.add!"months"(-4);
3376             assert(sysTime == SysTime(Date(-1999, 6, 6)));
3377         }
3378 
3379         {
3380             auto sysTime = SysTime(Date(-1999, 7, 6));
3381             sysTime.add!"months"(6);
3382             assert(sysTime == SysTime(Date(-1998, 1, 6)));
3383             sysTime.add!"months"(-6);
3384             assert(sysTime == SysTime(Date(-1999, 7, 6)));
3385         }
3386 
3387         {
3388             auto sysTime = SysTime(Date(-1999, 7, 6));
3389             sysTime.add!"months"(-27);
3390             assert(sysTime == SysTime(Date(-2001, 4, 6)));
3391             sysTime.add!"months"(28);
3392             assert(sysTime == SysTime(Date(-1999, 8, 6)));
3393         }
3394 
3395         {
3396             auto sysTime = SysTime(Date(-1999, 5, 31));
3397             sysTime.add!"months"(1);
3398             assert(sysTime == SysTime(Date(-1999, 7, 1)));
3399         }
3400 
3401         {
3402             auto sysTime = SysTime(Date(-1999, 5, 31));
3403             sysTime.add!"months"(-1);
3404             assert(sysTime == SysTime(Date(-1999, 5, 1)));
3405         }
3406 
3407         {
3408             auto sysTime = SysTime(Date(-1999, 2, 28));
3409             sysTime.add!"months"(-12);
3410             assert(sysTime == SysTime(Date(-2000, 2, 28)));
3411         }
3412 
3413         {
3414             auto sysTime = SysTime(Date(-2000, 2, 29));
3415             sysTime.add!"months"(-12);
3416             assert(sysTime == SysTime(Date(-2001, 3, 1)));
3417         }
3418 
3419         {
3420             auto sysTime = SysTime(Date(-1999, 7, 31));
3421             sysTime.add!"months"(1);
3422             assert(sysTime == SysTime(Date(-1999, 8, 31)));
3423             sysTime.add!"months"(1);
3424             assert(sysTime == SysTime(Date(-1999, 10, 1)));
3425         }
3426 
3427         {
3428             auto sysTime = SysTime(Date(-1998, 8, 31));
3429             sysTime.add!"months"(13);
3430             assert(sysTime == SysTime(Date(-1997, 10, 1)));
3431             sysTime.add!"months"(-13);
3432             assert(sysTime == SysTime(Date(-1998, 9, 1)));
3433         }
3434 
3435         {
3436             auto sysTime = SysTime(Date(-1997, 12, 31));
3437             sysTime.add!"months"(13);
3438             assert(sysTime == SysTime(Date(-1995, 1, 31)));
3439             sysTime.add!"months"(-13);
3440             assert(sysTime == SysTime(Date(-1997, 12, 31)));
3441         }
3442 
3443         {
3444             auto sysTime = SysTime(Date(-1997, 12, 31));
3445             sysTime.add!"months"(14);
3446             assert(sysTime == SysTime(Date(-1995, 3, 3)));
3447             sysTime.add!"months"(-14);
3448             assert(sysTime == SysTime(Date(-1996, 1, 3)));
3449         }
3450 
3451         {
3452             auto sysTime = SysTime(Date(-2002, 12, 31));
3453             sysTime.add!"months"(14);
3454             assert(sysTime == SysTime(Date(-2000, 3, 2)));
3455             sysTime.add!"months"(-14);
3456             assert(sysTime == SysTime(Date(-2001, 1, 2)));
3457         }
3458 
3459         {
3460             auto sysTime = SysTime(Date(-2001, 12, 31));
3461             sysTime.add!"months"(14);
3462             assert(sysTime == SysTime(Date(-1999, 3, 3)));
3463             sysTime.add!"months"(-14);
3464             assert(sysTime == SysTime(Date(-2000, 1, 3)));
3465         }
3466 
3467         {
3468             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
3469             sysTime.add!"months"(3);
3470             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
3471             sysTime.add!"months"(-4);
3472             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
3473         }
3474 
3475         {
3476             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
3477             sysTime.add!"months"(14);
3478             assert(sysTime == SysTime(DateTime(-2000, 3, 2, 7, 7, 7), hnsecs(422202)));
3479             sysTime.add!"months"(-14);
3480             assert(sysTime == SysTime(DateTime(-2001, 1, 2, 7, 7, 7), hnsecs(422202)));
3481         }
3482 
3483         {
3484             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
3485             sysTime.add!"months"(14);
3486             assert(sysTime == SysTime(DateTime(-1999, 3, 3, 7, 7, 7), hnsecs(422202)));
3487             sysTime.add!"months"(-14);
3488             assert(sysTime == SysTime(DateTime(-2000, 1, 3, 7, 7, 7), hnsecs(422202)));
3489         }
3490 
3491         // Test Both
3492         {
3493             auto sysTime = SysTime(Date(1, 1, 1));
3494             sysTime.add!"months"(-1);
3495             assert(sysTime == SysTime(Date(0, 12, 1)));
3496             sysTime.add!"months"(1);
3497             assert(sysTime == SysTime(Date(1, 1, 1)));
3498         }
3499 
3500         {
3501             auto sysTime = SysTime(Date(4, 1, 1));
3502             sysTime.add!"months"(-48);
3503             assert(sysTime == SysTime(Date(0, 1, 1)));
3504             sysTime.add!"months"(48);
3505             assert(sysTime == SysTime(Date(4, 1, 1)));
3506         }
3507 
3508         {
3509             auto sysTime = SysTime(Date(4, 3, 31));
3510             sysTime.add!"months"(-49);
3511             assert(sysTime == SysTime(Date(0, 3, 2)));
3512             sysTime.add!"months"(49);
3513             assert(sysTime == SysTime(Date(4, 4, 2)));
3514         }
3515 
3516         {
3517             auto sysTime = SysTime(Date(4, 3, 31));
3518             sysTime.add!"months"(-85);
3519             assert(sysTime == SysTime(Date(-3, 3, 3)));
3520             sysTime.add!"months"(85);
3521             assert(sysTime == SysTime(Date(4, 4, 3)));
3522         }
3523 
3524         {
3525             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3526             sysTime.add!"months"(-1);
3527             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3528             sysTime.add!"months"(1);
3529             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3530         }
3531 
3532         {
3533             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3534             sysTime.add!"months"(-1);
3535             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3536             sysTime.add!"months"(1);
3537             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3538         }
3539 
3540         {
3541             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
3542             sysTime.add!"months"(1);
3543             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3544             sysTime.add!"months"(-1);
3545             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3546         }
3547 
3548         {
3549             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
3550             sysTime.add!"months"(1);
3551             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3552             sysTime.add!"months"(-1);
3553             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3554         }
3555 
3556         {
3557             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
3558             sysTime.add!"months"(-1);
3559             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17)));
3560             sysTime.add!"months"(1);
3561             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
3562         }
3563 
3564         {
3565             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
3566             sysTime.add!"months"(-85);
3567             assert(sysTime == SysTime(DateTime(-3, 3, 3, 12, 11, 10), msecs(9)));
3568             sysTime.add!"months"(85);
3569             assert(sysTime == SysTime(DateTime(4, 4, 3, 12, 11, 10), msecs(9)));
3570         }
3571 
3572         {
3573             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3574             sysTime.add!"months"(85);
3575             assert(sysTime == SysTime(DateTime(4, 5, 1, 12, 11, 10), msecs(9)));
3576             sysTime.add!"months"(-85);
3577             assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9)));
3578         }
3579 
3580         {
3581             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3582             sysTime.add!"months"(85).add!"months"(-83);
3583             assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), msecs(9)));
3584         }
3585 
3586         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3587         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3588         static assert(!__traits(compiles, cst.add!"months"(4)));
3589         static assert(!__traits(compiles, ist.add!"months"(4)));
3590 
3591         static void testScope(scope ref SysTime st) @safe
3592         {
3593             auto result = st.add!"months"(42);
3594         }
3595     }
3596 
3597     // Test add!"months"() with AllowDayOverflow.no
3598     @safe unittest
3599     {
3600         import core.time;
3601         // Test A.D.
3602         {
3603             auto sysTime = SysTime(Date(1999, 7, 6));
3604             sysTime.add!"months"(3, AllowDayOverflow.no);
3605             assert(sysTime == SysTime(Date(1999, 10, 6)));
3606             sysTime.add!"months"(-4, AllowDayOverflow.no);
3607             assert(sysTime == SysTime(Date(1999, 6, 6)));
3608         }
3609 
3610         {
3611             auto sysTime = SysTime(Date(1999, 7, 6));
3612             sysTime.add!"months"(6, AllowDayOverflow.no);
3613             assert(sysTime == SysTime(Date(2000, 1, 6)));
3614             sysTime.add!"months"(-6, AllowDayOverflow.no);
3615             assert(sysTime == SysTime(Date(1999, 7, 6)));
3616         }
3617 
3618         {
3619             auto sysTime = SysTime(Date(1999, 7, 6));
3620             sysTime.add!"months"(27, AllowDayOverflow.no);
3621             assert(sysTime == SysTime(Date(2001, 10, 6)));
3622             sysTime.add!"months"(-28, AllowDayOverflow.no);
3623             assert(sysTime == SysTime(Date(1999, 6, 6)));
3624         }
3625 
3626         {
3627             auto sysTime = SysTime(Date(1999, 5, 31));
3628             sysTime.add!"months"(1, AllowDayOverflow.no);
3629             assert(sysTime == SysTime(Date(1999, 6, 30)));
3630         }
3631 
3632         {
3633             auto sysTime = SysTime(Date(1999, 5, 31));
3634             sysTime.add!"months"(-1, AllowDayOverflow.no);
3635             assert(sysTime == SysTime(Date(1999, 4, 30)));
3636         }
3637 
3638         {
3639             auto sysTime = SysTime(Date(1999, 2, 28));
3640             sysTime.add!"months"(12, AllowDayOverflow.no);
3641             assert(sysTime == SysTime(Date(2000, 2, 28)));
3642         }
3643 
3644         {
3645             auto sysTime = SysTime(Date(2000, 2, 29));
3646             sysTime.add!"months"(12, AllowDayOverflow.no);
3647             assert(sysTime == SysTime(Date(2001, 2, 28)));
3648         }
3649 
3650         {
3651             auto sysTime = SysTime(Date(1999, 7, 31));
3652             sysTime.add!"months"(1, AllowDayOverflow.no);
3653             assert(sysTime == SysTime(Date(1999, 8, 31)));
3654             sysTime.add!"months"(1, AllowDayOverflow.no);
3655             assert(sysTime == SysTime(Date(1999, 9, 30)));
3656         }
3657 
3658         {
3659             auto sysTime = SysTime(Date(1998, 8, 31));
3660             sysTime.add!"months"(13, AllowDayOverflow.no);
3661             assert(sysTime == SysTime(Date(1999, 9, 30)));
3662             sysTime.add!"months"(-13, AllowDayOverflow.no);
3663             assert(sysTime == SysTime(Date(1998, 8, 30)));
3664         }
3665 
3666         {
3667             auto sysTime = SysTime(Date(1997, 12, 31));
3668             sysTime.add!"months"(13, AllowDayOverflow.no);
3669             assert(sysTime == SysTime(Date(1999, 1, 31)));
3670             sysTime.add!"months"(-13, AllowDayOverflow.no);
3671             assert(sysTime == SysTime(Date(1997, 12, 31)));
3672         }
3673 
3674         {
3675             auto sysTime = SysTime(Date(1997, 12, 31));
3676             sysTime.add!"months"(14, AllowDayOverflow.no);
3677             assert(sysTime == SysTime(Date(1999, 2, 28)));
3678             sysTime.add!"months"(-14, AllowDayOverflow.no);
3679             assert(sysTime == SysTime(Date(1997, 12, 28)));
3680         }
3681 
3682         {
3683             auto sysTime = SysTime(Date(1998, 12, 31));
3684             sysTime.add!"months"(14, AllowDayOverflow.no);
3685             assert(sysTime == SysTime(Date(2000, 2, 29)));
3686             sysTime.add!"months"(-14, AllowDayOverflow.no);
3687             assert(sysTime == SysTime(Date(1998, 12, 29)));
3688         }
3689 
3690         {
3691             auto sysTime = SysTime(Date(1999, 12, 31));
3692             sysTime.add!"months"(14, AllowDayOverflow.no);
3693             assert(sysTime == SysTime(Date(2001, 2, 28)));
3694             sysTime.add!"months"(-14, AllowDayOverflow.no);
3695             assert(sysTime == SysTime(Date(1999, 12, 28)));
3696         }
3697 
3698         {
3699             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
3700             sysTime.add!"months"(3, AllowDayOverflow.no);
3701             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
3702             sysTime.add!"months"(-4, AllowDayOverflow.no);
3703             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
3704         }
3705 
3706         {
3707             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
3708             sysTime.add!"months"(14, AllowDayOverflow.no);
3709             assert(sysTime == SysTime(DateTime(2000, 2, 29, 7, 7, 7), hnsecs(422202)));
3710             sysTime.add!"months"(-14, AllowDayOverflow.no);
3711             assert(sysTime == SysTime(DateTime(1998, 12, 29, 7, 7, 7), hnsecs(422202)));
3712         }
3713 
3714         {
3715             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
3716             sysTime.add!"months"(14, AllowDayOverflow.no);
3717             assert(sysTime == SysTime(DateTime(2001, 2, 28, 7, 7, 7), hnsecs(422202)));
3718             sysTime.add!"months"(-14, AllowDayOverflow.no);
3719             assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202)));
3720         }
3721 
3722         // Test B.C.
3723         {
3724             auto sysTime = SysTime(Date(-1999, 7, 6));
3725             sysTime.add!"months"(3, AllowDayOverflow.no);
3726             assert(sysTime == SysTime(Date(-1999, 10, 6)));
3727             sysTime.add!"months"(-4, AllowDayOverflow.no);
3728             assert(sysTime == SysTime(Date(-1999, 6, 6)));
3729         }
3730 
3731         {
3732             auto sysTime = SysTime(Date(-1999, 7, 6));
3733             sysTime.add!"months"(6, AllowDayOverflow.no);
3734             assert(sysTime == SysTime(Date(-1998, 1, 6)));
3735             sysTime.add!"months"(-6, AllowDayOverflow.no);
3736             assert(sysTime == SysTime(Date(-1999, 7, 6)));
3737         }
3738 
3739         {
3740             auto sysTime = SysTime(Date(-1999, 7, 6));
3741             sysTime.add!"months"(-27, AllowDayOverflow.no);
3742             assert(sysTime == SysTime(Date(-2001, 4, 6)));
3743             sysTime.add!"months"(28, AllowDayOverflow.no);
3744             assert(sysTime == SysTime(Date(-1999, 8, 6)));
3745         }
3746 
3747         {
3748             auto sysTime = SysTime(Date(-1999, 5, 31));
3749             sysTime.add!"months"(1, AllowDayOverflow.no);
3750             assert(sysTime == SysTime(Date(-1999, 6, 30)));
3751         }
3752 
3753         {
3754             auto sysTime = SysTime(Date(-1999, 5, 31));
3755             sysTime.add!"months"(-1, AllowDayOverflow.no);
3756             assert(sysTime == SysTime(Date(-1999, 4, 30)));
3757         }
3758 
3759         {
3760             auto sysTime = SysTime(Date(-1999, 2, 28));
3761             sysTime.add!"months"(-12, AllowDayOverflow.no);
3762             assert(sysTime == SysTime(Date(-2000, 2, 28)));
3763         }
3764 
3765         {
3766             auto sysTime = SysTime(Date(-2000, 2, 29));
3767             sysTime.add!"months"(-12, AllowDayOverflow.no);
3768             assert(sysTime == SysTime(Date(-2001, 2, 28)));
3769         }
3770 
3771         {
3772             auto sysTime = SysTime(Date(-1999, 7, 31));
3773             sysTime.add!"months"(1, AllowDayOverflow.no);
3774             assert(sysTime == SysTime(Date(-1999, 8, 31)));
3775             sysTime.add!"months"(1, AllowDayOverflow.no);
3776             assert(sysTime == SysTime(Date(-1999, 9, 30)));
3777         }
3778 
3779         {
3780             auto sysTime = SysTime(Date(-1998, 8, 31));
3781             sysTime.add!"months"(13, AllowDayOverflow.no);
3782             assert(sysTime == SysTime(Date(-1997, 9, 30)));
3783             sysTime.add!"months"(-13, AllowDayOverflow.no);
3784             assert(sysTime == SysTime(Date(-1998, 8, 30)));
3785         }
3786 
3787         {
3788             auto sysTime = SysTime(Date(-1997, 12, 31));
3789             sysTime.add!"months"(13, AllowDayOverflow.no);
3790             assert(sysTime == SysTime(Date(-1995, 1, 31)));
3791             sysTime.add!"months"(-13, AllowDayOverflow.no);
3792             assert(sysTime == SysTime(Date(-1997, 12, 31)));
3793         }
3794 
3795         {
3796             auto sysTime = SysTime(Date(-1997, 12, 31));
3797             sysTime.add!"months"(14, AllowDayOverflow.no);
3798             assert(sysTime == SysTime(Date(-1995, 2, 28)));
3799             sysTime.add!"months"(-14, AllowDayOverflow.no);
3800             assert(sysTime == SysTime(Date(-1997, 12, 28)));
3801         }
3802 
3803         {
3804             auto sysTime = SysTime(Date(-2002, 12, 31));
3805             sysTime.add!"months"(14, AllowDayOverflow.no);
3806             assert(sysTime == SysTime(Date(-2000, 2, 29)));
3807             sysTime.add!"months"(-14, AllowDayOverflow.no);
3808             assert(sysTime == SysTime(Date(-2002, 12, 29)));
3809         }
3810 
3811         {
3812             auto sysTime = SysTime(Date(-2001, 12, 31));
3813             sysTime.add!"months"(14, AllowDayOverflow.no);
3814             assert(sysTime == SysTime(Date(-1999, 2, 28)));
3815             sysTime.add!"months"(-14, AllowDayOverflow.no);
3816             assert(sysTime == SysTime(Date(-2001, 12, 28)));
3817         }
3818 
3819         {
3820             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
3821             sysTime.add!"months"(3, AllowDayOverflow.no);
3822             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
3823             sysTime.add!"months"(-4, AllowDayOverflow.no);
3824             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
3825         }
3826 
3827         {
3828             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
3829             sysTime.add!"months"(14, AllowDayOverflow.no);
3830             assert(sysTime == SysTime(DateTime(-2000, 2, 29, 7, 7, 7), hnsecs(422202)));
3831             sysTime.add!"months"(-14, AllowDayOverflow.no);
3832             assert(sysTime == SysTime(DateTime(-2002, 12, 29, 7, 7, 7), hnsecs(422202)));
3833         }
3834 
3835         {
3836             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
3837             sysTime.add!"months"(14, AllowDayOverflow.no);
3838             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 7, 7), hnsecs(422202)));
3839             sysTime.add!"months"(-14, AllowDayOverflow.no);
3840             assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202)));
3841         }
3842 
3843         // Test Both
3844         {
3845             auto sysTime = SysTime(Date(1, 1, 1));
3846             sysTime.add!"months"(-1, AllowDayOverflow.no);
3847             assert(sysTime == SysTime(Date(0, 12, 1)));
3848             sysTime.add!"months"(1, AllowDayOverflow.no);
3849             assert(sysTime == SysTime(Date(1, 1, 1)));
3850         }
3851 
3852         {
3853             auto sysTime = SysTime(Date(4, 1, 1));
3854             sysTime.add!"months"(-48, AllowDayOverflow.no);
3855             assert(sysTime == SysTime(Date(0, 1, 1)));
3856             sysTime.add!"months"(48, AllowDayOverflow.no);
3857             assert(sysTime == SysTime(Date(4, 1, 1)));
3858         }
3859 
3860         {
3861             auto sysTime = SysTime(Date(4, 3, 31));
3862             sysTime.add!"months"(-49, AllowDayOverflow.no);
3863             assert(sysTime == SysTime(Date(0, 2, 29)));
3864             sysTime.add!"months"(49, AllowDayOverflow.no);
3865             assert(sysTime == SysTime(Date(4, 3, 29)));
3866         }
3867 
3868         {
3869             auto sysTime = SysTime(Date(4, 3, 31));
3870             sysTime.add!"months"(-85, AllowDayOverflow.no);
3871             assert(sysTime == SysTime(Date(-3, 2, 28)));
3872             sysTime.add!"months"(85, AllowDayOverflow.no);
3873             assert(sysTime == SysTime(Date(4, 3, 28)));
3874         }
3875 
3876         {
3877             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
3878             sysTime.add!"months"(-1, AllowDayOverflow.no);
3879             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3880             sysTime.add!"months"(1, AllowDayOverflow.no);
3881             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3882         }
3883 
3884         {
3885             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
3886             sysTime.add!"months"(-1, AllowDayOverflow.no);
3887             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3888             sysTime.add!"months"(1, AllowDayOverflow.no);
3889             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3890         }
3891 
3892         {
3893             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
3894             sysTime.add!"months"(1, AllowDayOverflow.no);
3895             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
3896             sysTime.add!"months"(-1, AllowDayOverflow.no);
3897             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
3898         }
3899 
3900         {
3901             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
3902             sysTime.add!"months"(1, AllowDayOverflow.no);
3903             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
3904             sysTime.add!"months"(-1, AllowDayOverflow.no);
3905             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
3906         }
3907 
3908         {
3909             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
3910             sysTime.add!"months"(-1, AllowDayOverflow.no);
3911             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 7, 9), hnsecs(17)));
3912             sysTime.add!"months"(1, AllowDayOverflow.no);
3913             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
3914         }
3915 
3916         {
3917             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
3918             sysTime.add!"months"(-85, AllowDayOverflow.no);
3919             assert(sysTime == SysTime(DateTime(-3, 2, 28, 12, 11, 10), msecs(9)));
3920             sysTime.add!"months"(85, AllowDayOverflow.no);
3921             assert(sysTime == SysTime(DateTime(4, 3, 28, 12, 11, 10), msecs(9)));
3922         }
3923 
3924         {
3925             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3926             sysTime.add!"months"(85, AllowDayOverflow.no);
3927             assert(sysTime == SysTime(DateTime(4, 4, 30, 12, 11, 10), msecs(9)));
3928             sysTime.add!"months"(-85, AllowDayOverflow.no);
3929             assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9)));
3930         }
3931 
3932         {
3933             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
3934             sysTime.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no);
3935             assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9)));
3936         }
3937     }
3938 
3939 
3940     /++
3941         Adds the given number of years or months to this $(LREF SysTime). A
3942         negative number will subtract.
3943 
3944         The difference between rolling and adding is that rolling does not
3945         affect larger units. Rolling a $(LREF SysTime) 12 months
3946         gets the exact same $(LREF SysTime). However, the days can still be
3947         affected due to the differing number of days in each month.
3948 
3949         Because there are no units larger than years, there is no difference
3950         between adding and rolling years.
3951 
3952         Params:
3953             units         = The type of units to add ("years" or "months").
3954             value         = The number of months or years to add to this
3955                             $(LREF SysTime).
3956             allowOverflow = Whether the days should be allowed to overflow,
3957                             causing the month to increment.
3958       +/
3959     ref SysTime roll(string units)
3960                     (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow scope
3961     if (units == "years")
3962     {
3963         return add!"years"(value, allowOverflow);
3964     }
3965 
3966     ///
3967     @safe unittest
3968     {
3969         import std.datetime.date : AllowDayOverflow, DateTime;
3970 
3971         auto st1 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
3972         st1.roll!"months"(1);
3973         assert(st1 == SysTime(DateTime(2010, 2, 1, 12, 33, 33)));
3974 
3975         auto st2 = SysTime(DateTime(2010, 1, 1, 12, 33, 33));
3976         st2.roll!"months"(-1);
3977         assert(st2 == SysTime(DateTime(2010, 12, 1, 12, 33, 33)));
3978 
3979         auto st3 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
3980         st3.roll!"months"(1);
3981         assert(st3 == SysTime(DateTime(1999, 3, 1, 12, 33, 33)));
3982 
3983         auto st4 = SysTime(DateTime(1999, 1, 29, 12, 33, 33));
3984         st4.roll!"months"(1, AllowDayOverflow.no);
3985         assert(st4 == SysTime(DateTime(1999, 2, 28, 12, 33, 33)));
3986 
3987         auto st5 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
3988         st5.roll!"years"(1);
3989         assert(st5 == SysTime(DateTime(2001, 3, 1, 12, 30, 33)));
3990 
3991         auto st6 = SysTime(DateTime(2000, 2, 29, 12, 30, 33));
3992         st6.roll!"years"(1, AllowDayOverflow.no);
3993         assert(st6 == SysTime(DateTime(2001, 2, 28, 12, 30, 33)));
3994     }
3995 
3996     @safe unittest
3997     {
3998         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
3999         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4000         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4001         st.roll!"years"(4);
4002         static assert(!__traits(compiles, cst.roll!"years"(4)));
4003         static assert(!__traits(compiles, ist.roll!"years"(4)));
4004 
4005         static void testScope(scope ref SysTime st) @safe
4006         {
4007             auto result = st.roll!"years"(42);
4008         }
4009     }
4010 
4011 
4012     // Shares documentation with "years" overload.
4013     ref SysTime roll(string units)
4014                     (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow scope
4015     if (units == "months")
4016     {
4017         auto hnsecs = adjTime;
4018         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
4019 
4020         if (hnsecs < 0)
4021         {
4022             hnsecs += convert!("hours", "hnsecs")(24);
4023             --days;
4024         }
4025 
4026         auto date = Date(cast(int) days);
4027         date.roll!"months"(value, allowOverflow);
4028         days = date.dayOfGregorianCal - 1;
4029 
4030         if (days < 0)
4031         {
4032             hnsecs -= convert!("hours", "hnsecs")(24);
4033             ++days;
4034         }
4035 
4036         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
4037         adjTime = newDaysHNSecs + hnsecs;
4038         return this;
4039     }
4040 
4041     // Test roll!"months"() with AllowDayOverflow.yes
4042     @safe unittest
4043     {
4044         import core.time;
4045         // Test A.D.
4046         {
4047             auto sysTime = SysTime(Date(1999, 7, 6));
4048             sysTime.roll!"months"(3);
4049             assert(sysTime == SysTime(Date(1999, 10, 6)));
4050             sysTime.roll!"months"(-4);
4051             assert(sysTime == SysTime(Date(1999, 6, 6)));
4052         }
4053 
4054         {
4055             auto sysTime = SysTime(Date(1999, 7, 6));
4056             sysTime.roll!"months"(6);
4057             assert(sysTime == SysTime(Date(1999, 1, 6)));
4058             sysTime.roll!"months"(-6);
4059             assert(sysTime == SysTime(Date(1999, 7, 6)));
4060         }
4061 
4062         {
4063             auto sysTime = SysTime(Date(1999, 7, 6));
4064             sysTime.roll!"months"(27);
4065             assert(sysTime == SysTime(Date(1999, 10, 6)));
4066             sysTime.roll!"months"(-28);
4067             assert(sysTime == SysTime(Date(1999, 6, 6)));
4068         }
4069 
4070         {
4071             auto sysTime = SysTime(Date(1999, 5, 31));
4072             sysTime.roll!"months"(1);
4073             assert(sysTime == SysTime(Date(1999, 7, 1)));
4074         }
4075 
4076         {
4077             auto sysTime = SysTime(Date(1999, 5, 31));
4078             sysTime.roll!"months"(-1);
4079             assert(sysTime == SysTime(Date(1999, 5, 1)));
4080         }
4081 
4082         {
4083             auto sysTime = SysTime(Date(1999, 2, 28));
4084             sysTime.roll!"months"(12);
4085             assert(sysTime == SysTime(Date(1999, 2, 28)));
4086         }
4087 
4088         {
4089             auto sysTime = SysTime(Date(2000, 2, 29));
4090             sysTime.roll!"months"(12);
4091             assert(sysTime == SysTime(Date(2000, 2, 29)));
4092         }
4093 
4094         {
4095             auto sysTime = SysTime(Date(1999, 7, 31));
4096             sysTime.roll!"months"(1);
4097             assert(sysTime == SysTime(Date(1999, 8, 31)));
4098             sysTime.roll!"months"(1);
4099             assert(sysTime == SysTime(Date(1999, 10, 1)));
4100         }
4101 
4102         {
4103             auto sysTime = SysTime(Date(1998, 8, 31));
4104             sysTime.roll!"months"(13);
4105             assert(sysTime == SysTime(Date(1998, 10, 1)));
4106             sysTime.roll!"months"(-13);
4107             assert(sysTime == SysTime(Date(1998, 9, 1)));
4108         }
4109 
4110         {
4111             auto sysTime = SysTime(Date(1997, 12, 31));
4112             sysTime.roll!"months"(13);
4113             assert(sysTime == SysTime(Date(1997, 1, 31)));
4114             sysTime.roll!"months"(-13);
4115             assert(sysTime == SysTime(Date(1997, 12, 31)));
4116         }
4117 
4118         {
4119             auto sysTime = SysTime(Date(1997, 12, 31));
4120             sysTime.roll!"months"(14);
4121             assert(sysTime == SysTime(Date(1997, 3, 3)));
4122             sysTime.roll!"months"(-14);
4123             assert(sysTime == SysTime(Date(1997, 1, 3)));
4124         }
4125 
4126         {
4127             auto sysTime = SysTime(Date(1998, 12, 31));
4128             sysTime.roll!"months"(14);
4129             assert(sysTime == SysTime(Date(1998, 3, 3)));
4130             sysTime.roll!"months"(-14);
4131             assert(sysTime == SysTime(Date(1998, 1, 3)));
4132         }
4133 
4134         {
4135             auto sysTime = SysTime(Date(1999, 12, 31));
4136             sysTime.roll!"months"(14);
4137             assert(sysTime == SysTime(Date(1999, 3, 3)));
4138             sysTime.roll!"months"(-14);
4139             assert(sysTime == SysTime(Date(1999, 1, 3)));
4140         }
4141 
4142         {
4143             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
4144             sysTime.roll!"months"(3);
4145             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
4146             sysTime.roll!"months"(-4);
4147             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
4148         }
4149 
4150         {
4151             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
4152             sysTime.roll!"months"(14);
4153             assert(sysTime == SysTime(DateTime(1998, 3, 3, 7, 7, 7), hnsecs(422202)));
4154             sysTime.roll!"months"(-14);
4155             assert(sysTime == SysTime(DateTime(1998, 1, 3, 7, 7, 7), hnsecs(422202)));
4156         }
4157 
4158         {
4159             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
4160             sysTime.roll!"months"(14);
4161             assert(sysTime == SysTime(DateTime(1999, 3, 3, 7, 7, 7), hnsecs(422202)));
4162             sysTime.roll!"months"(-14);
4163             assert(sysTime == SysTime(DateTime(1999, 1, 3, 7, 7, 7), hnsecs(422202)));
4164         }
4165 
4166         // Test B.C.
4167         {
4168             auto sysTime = SysTime(Date(-1999, 7, 6));
4169             sysTime.roll!"months"(3);
4170             assert(sysTime == SysTime(Date(-1999, 10, 6)));
4171             sysTime.roll!"months"(-4);
4172             assert(sysTime == SysTime(Date(-1999, 6, 6)));
4173         }
4174 
4175         {
4176             auto sysTime = SysTime(Date(-1999, 7, 6));
4177             sysTime.roll!"months"(6);
4178             assert(sysTime == SysTime(Date(-1999, 1, 6)));
4179             sysTime.roll!"months"(-6);
4180             assert(sysTime == SysTime(Date(-1999, 7, 6)));
4181         }
4182 
4183         {
4184             auto sysTime = SysTime(Date(-1999, 7, 6));
4185             sysTime.roll!"months"(-27);
4186             assert(sysTime == SysTime(Date(-1999, 4, 6)));
4187             sysTime.roll!"months"(28);
4188             assert(sysTime == SysTime(Date(-1999, 8, 6)));
4189         }
4190 
4191         {
4192             auto sysTime = SysTime(Date(-1999, 5, 31));
4193             sysTime.roll!"months"(1);
4194             assert(sysTime == SysTime(Date(-1999, 7, 1)));
4195         }
4196 
4197         {
4198             auto sysTime = SysTime(Date(-1999, 5, 31));
4199             sysTime.roll!"months"(-1);
4200             assert(sysTime == SysTime(Date(-1999, 5, 1)));
4201         }
4202 
4203         {
4204             auto sysTime = SysTime(Date(-1999, 2, 28));
4205             sysTime.roll!"months"(-12);
4206             assert(sysTime == SysTime(Date(-1999, 2, 28)));
4207         }
4208 
4209         {
4210             auto sysTime = SysTime(Date(-2000, 2, 29));
4211             sysTime.roll!"months"(-12);
4212             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4213         }
4214 
4215         {
4216             auto sysTime = SysTime(Date(-1999, 7, 31));
4217             sysTime.roll!"months"(1);
4218             assert(sysTime == SysTime(Date(-1999, 8, 31)));
4219             sysTime.roll!"months"(1);
4220             assert(sysTime == SysTime(Date(-1999, 10, 1)));
4221         }
4222 
4223         {
4224             auto sysTime = SysTime(Date(-1998, 8, 31));
4225             sysTime.roll!"months"(13);
4226             assert(sysTime == SysTime(Date(-1998, 10, 1)));
4227             sysTime.roll!"months"(-13);
4228             assert(sysTime == SysTime(Date(-1998, 9, 1)));
4229         }
4230 
4231         {
4232             auto sysTime = SysTime(Date(-1997, 12, 31));
4233             sysTime.roll!"months"(13);
4234             assert(sysTime == SysTime(Date(-1997, 1, 31)));
4235             sysTime.roll!"months"(-13);
4236             assert(sysTime == SysTime(Date(-1997, 12, 31)));
4237         }
4238 
4239         {
4240             auto sysTime = SysTime(Date(-1997, 12, 31));
4241             sysTime.roll!"months"(14);
4242             assert(sysTime == SysTime(Date(-1997, 3, 3)));
4243             sysTime.roll!"months"(-14);
4244             assert(sysTime == SysTime(Date(-1997, 1, 3)));
4245         }
4246 
4247         {
4248             auto sysTime = SysTime(Date(-2002, 12, 31));
4249             sysTime.roll!"months"(14);
4250             assert(sysTime == SysTime(Date(-2002, 3, 3)));
4251             sysTime.roll!"months"(-14);
4252             assert(sysTime == SysTime(Date(-2002, 1, 3)));
4253         }
4254 
4255         {
4256             auto sysTime = SysTime(Date(-2001, 12, 31));
4257             sysTime.roll!"months"(14);
4258             assert(sysTime == SysTime(Date(-2001, 3, 3)));
4259             sysTime.roll!"months"(-14);
4260             assert(sysTime == SysTime(Date(-2001, 1, 3)));
4261         }
4262 
4263         {
4264             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
4265             sysTime.roll!"months"(-1);
4266             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0)));
4267             sysTime.roll!"months"(1);
4268             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
4269         }
4270 
4271         {
4272             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
4273             sysTime.roll!"months"(-1);
4274             assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4275             sysTime.roll!"months"(1);
4276             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4277         }
4278 
4279         {
4280             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
4281             sysTime.roll!"months"(1);
4282             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
4283             sysTime.roll!"months"(-1);
4284             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
4285         }
4286 
4287         {
4288             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
4289             sysTime.roll!"months"(1);
4290             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4291             sysTime.roll!"months"(-1);
4292             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4293         }
4294 
4295         {
4296             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), hnsecs(5007));
4297             sysTime.roll!"months"(3);
4298             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), hnsecs(5007)));
4299             sysTime.roll!"months"(-4);
4300             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), hnsecs(5007)));
4301         }
4302 
4303         {
4304             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
4305             sysTime.roll!"months"(14);
4306             assert(sysTime == SysTime(DateTime(-2002, 3, 3, 7, 7, 7), hnsecs(422202)));
4307             sysTime.roll!"months"(-14);
4308             assert(sysTime == SysTime(DateTime(-2002, 1, 3, 7, 7, 7), hnsecs(422202)));
4309         }
4310 
4311         {
4312             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
4313             sysTime.roll!"months"(14);
4314             assert(sysTime == SysTime(DateTime(-2001, 3, 3, 7, 7, 7), hnsecs(422202)));
4315             sysTime.roll!"months"(-14);
4316             assert(sysTime == SysTime(DateTime(-2001, 1, 3, 7, 7, 7), hnsecs(422202)));
4317         }
4318 
4319         // Test Both
4320         {
4321             auto sysTime = SysTime(Date(1, 1, 1));
4322             sysTime.roll!"months"(-1);
4323             assert(sysTime == SysTime(Date(1, 12, 1)));
4324             sysTime.roll!"months"(1);
4325             assert(sysTime == SysTime(Date(1, 1, 1)));
4326         }
4327 
4328         {
4329             auto sysTime = SysTime(Date(4, 1, 1));
4330             sysTime.roll!"months"(-48);
4331             assert(sysTime == SysTime(Date(4, 1, 1)));
4332             sysTime.roll!"months"(48);
4333             assert(sysTime == SysTime(Date(4, 1, 1)));
4334         }
4335 
4336         {
4337             auto sysTime = SysTime(Date(4, 3, 31));
4338             sysTime.roll!"months"(-49);
4339             assert(sysTime == SysTime(Date(4, 3, 2)));
4340             sysTime.roll!"months"(49);
4341             assert(sysTime == SysTime(Date(4, 4, 2)));
4342         }
4343 
4344         {
4345             auto sysTime = SysTime(Date(4, 3, 31));
4346             sysTime.roll!"months"(-85);
4347             assert(sysTime == SysTime(Date(4, 3, 2)));
4348             sysTime.roll!"months"(85);
4349             assert(sysTime == SysTime(Date(4, 4, 2)));
4350         }
4351 
4352         {
4353             auto sysTime = SysTime(Date(-1, 1, 1));
4354             sysTime.roll!"months"(-1);
4355             assert(sysTime == SysTime(Date(-1, 12, 1)));
4356             sysTime.roll!"months"(1);
4357             assert(sysTime == SysTime(Date(-1, 1, 1)));
4358         }
4359 
4360         {
4361             auto sysTime = SysTime(Date(-4, 1, 1));
4362             sysTime.roll!"months"(-48);
4363             assert(sysTime == SysTime(Date(-4, 1, 1)));
4364             sysTime.roll!"months"(48);
4365             assert(sysTime == SysTime(Date(-4, 1, 1)));
4366         }
4367 
4368         {
4369             auto sysTime = SysTime(Date(-4, 3, 31));
4370             sysTime.roll!"months"(-49);
4371             assert(sysTime == SysTime(Date(-4, 3, 2)));
4372             sysTime.roll!"months"(49);
4373             assert(sysTime == SysTime(Date(-4, 4, 2)));
4374         }
4375 
4376         {
4377             auto sysTime = SysTime(Date(-4, 3, 31));
4378             sysTime.roll!"months"(-85);
4379             assert(sysTime == SysTime(Date(-4, 3, 2)));
4380             sysTime.roll!"months"(85);
4381             assert(sysTime == SysTime(Date(-4, 4, 2)));
4382         }
4383 
4384         {
4385             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
4386             sysTime.roll!"months"(-1);
4387             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17)));
4388             sysTime.roll!"months"(1);
4389             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
4390         }
4391 
4392         {
4393             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
4394             sysTime.roll!"months"(-85);
4395             assert(sysTime == SysTime(DateTime(4, 3, 2, 12, 11, 10), msecs(9)));
4396             sysTime.roll!"months"(85);
4397             assert(sysTime == SysTime(DateTime(4, 4, 2, 12, 11, 10), msecs(9)));
4398         }
4399 
4400         {
4401             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4402             sysTime.roll!"months"(85);
4403             assert(sysTime == SysTime(DateTime(-3, 5, 1, 12, 11, 10), msecs(9)));
4404             sysTime.roll!"months"(-85);
4405             assert(sysTime == SysTime(DateTime(-3, 4, 1, 12, 11, 10), msecs(9)));
4406         }
4407 
4408         {
4409             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4410             sysTime.roll!"months"(85).roll!"months"(-83);
4411             assert(sysTime == SysTime(DateTime(-3, 6, 1, 12, 11, 10), msecs(9)));
4412         }
4413 
4414         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4415         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
4416         static assert(!__traits(compiles, cst.roll!"months"(4)));
4417         static assert(!__traits(compiles, ist.roll!"months"(4)));
4418 
4419         static void testScope(scope ref SysTime st) @safe
4420         {
4421             auto result = st.roll!"months"(42);
4422         }
4423     }
4424 
4425     // Test roll!"months"() with AllowDayOverflow.no
4426     @safe unittest
4427     {
4428         import core.time;
4429         // Test A.D.
4430         {
4431             auto sysTime = SysTime(Date(1999, 7, 6));
4432             sysTime.roll!"months"(3, AllowDayOverflow.no);
4433             assert(sysTime == SysTime(Date(1999, 10, 6)));
4434             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4435             assert(sysTime == SysTime(Date(1999, 6, 6)));
4436         }
4437 
4438         {
4439             auto sysTime = SysTime(Date(1999, 7, 6));
4440             sysTime.roll!"months"(6, AllowDayOverflow.no);
4441             assert(sysTime == SysTime(Date(1999, 1, 6)));
4442             sysTime.roll!"months"(-6, AllowDayOverflow.no);
4443             assert(sysTime == SysTime(Date(1999, 7, 6)));
4444         }
4445 
4446         {
4447             auto sysTime = SysTime(Date(1999, 7, 6));
4448             sysTime.roll!"months"(27, AllowDayOverflow.no);
4449             assert(sysTime == SysTime(Date(1999, 10, 6)));
4450             sysTime.roll!"months"(-28, AllowDayOverflow.no);
4451             assert(sysTime == SysTime(Date(1999, 6, 6)));
4452         }
4453 
4454         {
4455             auto sysTime = SysTime(Date(1999, 5, 31));
4456             sysTime.roll!"months"(1, AllowDayOverflow.no);
4457             assert(sysTime == SysTime(Date(1999, 6, 30)));
4458         }
4459 
4460         {
4461             auto sysTime = SysTime(Date(1999, 5, 31));
4462             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4463             assert(sysTime == SysTime(Date(1999, 4, 30)));
4464         }
4465 
4466         {
4467             auto sysTime = SysTime(Date(1999, 2, 28));
4468             sysTime.roll!"months"(12, AllowDayOverflow.no);
4469             assert(sysTime == SysTime(Date(1999, 2, 28)));
4470         }
4471 
4472         {
4473             auto sysTime = SysTime(Date(2000, 2, 29));
4474             sysTime.roll!"months"(12, AllowDayOverflow.no);
4475             assert(sysTime == SysTime(Date(2000, 2, 29)));
4476         }
4477 
4478         {
4479             auto sysTime = SysTime(Date(1999, 7, 31));
4480             sysTime.roll!"months"(1, AllowDayOverflow.no);
4481             assert(sysTime == SysTime(Date(1999, 8, 31)));
4482             sysTime.roll!"months"(1, AllowDayOverflow.no);
4483             assert(sysTime == SysTime(Date(1999, 9, 30)));
4484         }
4485 
4486         {
4487             auto sysTime = SysTime(Date(1998, 8, 31));
4488             sysTime.roll!"months"(13, AllowDayOverflow.no);
4489             assert(sysTime == SysTime(Date(1998, 9, 30)));
4490             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4491             assert(sysTime == SysTime(Date(1998, 8, 30)));
4492         }
4493 
4494         {
4495             auto sysTime = SysTime(Date(1997, 12, 31));
4496             sysTime.roll!"months"(13, AllowDayOverflow.no);
4497             assert(sysTime == SysTime(Date(1997, 1, 31)));
4498             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4499             assert(sysTime == SysTime(Date(1997, 12, 31)));
4500         }
4501 
4502         {
4503             auto sysTime = SysTime(Date(1997, 12, 31));
4504             sysTime.roll!"months"(14, AllowDayOverflow.no);
4505             assert(sysTime == SysTime(Date(1997, 2, 28)));
4506             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4507             assert(sysTime == SysTime(Date(1997, 12, 28)));
4508         }
4509 
4510         {
4511             auto sysTime = SysTime(Date(1998, 12, 31));
4512             sysTime.roll!"months"(14, AllowDayOverflow.no);
4513             assert(sysTime == SysTime(Date(1998, 2, 28)));
4514             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4515             assert(sysTime == SysTime(Date(1998, 12, 28)));
4516         }
4517 
4518         {
4519             auto sysTime = SysTime(Date(1999, 12, 31));
4520             sysTime.roll!"months"(14, AllowDayOverflow.no);
4521             assert(sysTime == SysTime(Date(1999, 2, 28)));
4522             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4523             assert(sysTime == SysTime(Date(1999, 12, 28)));
4524         }
4525 
4526         {
4527             auto sysTime = SysTime(DateTime(1999, 7, 6, 12, 2, 7), usecs(5007));
4528             sysTime.roll!"months"(3, AllowDayOverflow.no);
4529             assert(sysTime == SysTime(DateTime(1999, 10, 6, 12, 2, 7), usecs(5007)));
4530             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4531             assert(sysTime == SysTime(DateTime(1999, 6, 6, 12, 2, 7), usecs(5007)));
4532         }
4533 
4534         {
4535             auto sysTime = SysTime(DateTime(1998, 12, 31, 7, 7, 7), hnsecs(422202));
4536             sysTime.roll!"months"(14, AllowDayOverflow.no);
4537             assert(sysTime == SysTime(DateTime(1998, 2, 28, 7, 7, 7), hnsecs(422202)));
4538             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4539             assert(sysTime == SysTime(DateTime(1998, 12, 28, 7, 7, 7), hnsecs(422202)));
4540         }
4541 
4542         {
4543             auto sysTime = SysTime(DateTime(1999, 12, 31, 7, 7, 7), hnsecs(422202));
4544             sysTime.roll!"months"(14, AllowDayOverflow.no);
4545             assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 7, 7), hnsecs(422202)));
4546             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4547             assert(sysTime == SysTime(DateTime(1999, 12, 28, 7, 7, 7), hnsecs(422202)));
4548         }
4549 
4550         // Test B.C.
4551         {
4552             auto sysTime = SysTime(Date(-1999, 7, 6));
4553             sysTime.roll!"months"(3, AllowDayOverflow.no);
4554             assert(sysTime == SysTime(Date(-1999, 10, 6)));
4555             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4556             assert(sysTime == SysTime(Date(-1999, 6, 6)));
4557         }
4558 
4559         {
4560             auto sysTime = SysTime(Date(-1999, 7, 6));
4561             sysTime.roll!"months"(6, AllowDayOverflow.no);
4562             assert(sysTime == SysTime(Date(-1999, 1, 6)));
4563             sysTime.roll!"months"(-6, AllowDayOverflow.no);
4564             assert(sysTime == SysTime(Date(-1999, 7, 6)));
4565         }
4566 
4567         {
4568             auto sysTime = SysTime(Date(-1999, 7, 6));
4569             sysTime.roll!"months"(-27, AllowDayOverflow.no);
4570             assert(sysTime == SysTime(Date(-1999, 4, 6)));
4571             sysTime.roll!"months"(28, AllowDayOverflow.no);
4572             assert(sysTime == SysTime(Date(-1999, 8, 6)));
4573         }
4574 
4575         {
4576             auto sysTime = SysTime(Date(-1999, 5, 31));
4577             sysTime.roll!"months"(1, AllowDayOverflow.no);
4578             assert(sysTime == SysTime(Date(-1999, 6, 30)));
4579         }
4580 
4581         {
4582             auto sysTime = SysTime(Date(-1999, 5, 31));
4583             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4584             assert(sysTime == SysTime(Date(-1999, 4, 30)));
4585         }
4586 
4587         {
4588             auto sysTime = SysTime(Date(-1999, 2, 28));
4589             sysTime.roll!"months"(-12, AllowDayOverflow.no);
4590             assert(sysTime == SysTime(Date(-1999, 2, 28)));
4591         }
4592 
4593         {
4594             auto sysTime = SysTime(Date(-2000, 2, 29));
4595             sysTime.roll!"months"(-12, AllowDayOverflow.no);
4596             assert(sysTime == SysTime(Date(-2000, 2, 29)));
4597         }
4598 
4599         {
4600             auto sysTime = SysTime(Date(-1999, 7, 31));
4601             sysTime.roll!"months"(1, AllowDayOverflow.no);
4602             assert(sysTime == SysTime(Date(-1999, 8, 31)));
4603             sysTime.roll!"months"(1, AllowDayOverflow.no);
4604             assert(sysTime == SysTime(Date(-1999, 9, 30)));
4605         }
4606 
4607         {
4608             auto sysTime = SysTime(Date(-1998, 8, 31));
4609             sysTime.roll!"months"(13, AllowDayOverflow.no);
4610             assert(sysTime == SysTime(Date(-1998, 9, 30)));
4611             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4612             assert(sysTime == SysTime(Date(-1998, 8, 30)));
4613         }
4614 
4615         {
4616             auto sysTime = SysTime(Date(-1997, 12, 31));
4617             sysTime.roll!"months"(13, AllowDayOverflow.no);
4618             assert(sysTime == SysTime(Date(-1997, 1, 31)));
4619             sysTime.roll!"months"(-13, AllowDayOverflow.no);
4620             assert(sysTime == SysTime(Date(-1997, 12, 31)));
4621         }
4622 
4623         {
4624             auto sysTime = SysTime(Date(-1997, 12, 31));
4625             sysTime.roll!"months"(14, AllowDayOverflow.no);
4626             assert(sysTime == SysTime(Date(-1997, 2, 28)));
4627             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4628             assert(sysTime == SysTime(Date(-1997, 12, 28)));
4629         }
4630 
4631         {
4632             auto sysTime = SysTime(Date(-2002, 12, 31));
4633             sysTime.roll!"months"(14, AllowDayOverflow.no);
4634             assert(sysTime == SysTime(Date(-2002, 2, 28)));
4635             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4636             assert(sysTime == SysTime(Date(-2002, 12, 28)));
4637         }
4638 
4639         {
4640             auto sysTime = SysTime(Date(-2001, 12, 31));
4641             sysTime.roll!"months"(14, AllowDayOverflow.no);
4642             assert(sysTime == SysTime(Date(-2001, 2, 28)));
4643             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4644             assert(sysTime == SysTime(Date(-2001, 12, 28)));
4645         }
4646 
4647         {
4648             auto sysTime = SysTime(DateTime(-1999, 7, 6, 12, 2, 7), usecs(5007));
4649             sysTime.roll!"months"(3, AllowDayOverflow.no);
4650             assert(sysTime == SysTime(DateTime(-1999, 10, 6, 12, 2, 7), usecs(5007)));
4651             sysTime.roll!"months"(-4, AllowDayOverflow.no);
4652             assert(sysTime == SysTime(DateTime(-1999, 6, 6, 12, 2, 7), usecs(5007)));
4653         }
4654 
4655         {
4656             auto sysTime = SysTime(DateTime(-2002, 12, 31, 7, 7, 7), hnsecs(422202));
4657             sysTime.roll!"months"(14, AllowDayOverflow.no);
4658             assert(sysTime == SysTime(DateTime(-2002, 2, 28, 7, 7, 7), hnsecs(422202)));
4659             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4660             assert(sysTime == SysTime(DateTime(-2002, 12, 28, 7, 7, 7), hnsecs(422202)));
4661         }
4662 
4663         {
4664             auto sysTime = SysTime(DateTime(-2001, 12, 31, 7, 7, 7), hnsecs(422202));
4665             sysTime.roll!"months"(14, AllowDayOverflow.no);
4666             assert(sysTime == SysTime(DateTime(-2001, 2, 28, 7, 7, 7), hnsecs(422202)));
4667             sysTime.roll!"months"(-14, AllowDayOverflow.no);
4668             assert(sysTime == SysTime(DateTime(-2001, 12, 28, 7, 7, 7), hnsecs(422202)));
4669         }
4670 
4671         // Test Both
4672         {
4673             auto sysTime = SysTime(Date(1, 1, 1));
4674             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4675             assert(sysTime == SysTime(Date(1, 12, 1)));
4676             sysTime.roll!"months"(1, AllowDayOverflow.no);
4677             assert(sysTime == SysTime(Date(1, 1, 1)));
4678         }
4679 
4680         {
4681             auto sysTime = SysTime(Date(4, 1, 1));
4682             sysTime.roll!"months"(-48, AllowDayOverflow.no);
4683             assert(sysTime == SysTime(Date(4, 1, 1)));
4684             sysTime.roll!"months"(48, AllowDayOverflow.no);
4685             assert(sysTime == SysTime(Date(4, 1, 1)));
4686         }
4687 
4688         {
4689             auto sysTime = SysTime(Date(4, 3, 31));
4690             sysTime.roll!"months"(-49, AllowDayOverflow.no);
4691             assert(sysTime == SysTime(Date(4, 2, 29)));
4692             sysTime.roll!"months"(49, AllowDayOverflow.no);
4693             assert(sysTime == SysTime(Date(4, 3, 29)));
4694         }
4695 
4696         {
4697             auto sysTime = SysTime(Date(4, 3, 31));
4698             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4699             assert(sysTime == SysTime(Date(4, 2, 29)));
4700             sysTime.roll!"months"(85, AllowDayOverflow.no);
4701             assert(sysTime == SysTime(Date(4, 3, 29)));
4702         }
4703 
4704         {
4705             auto sysTime = SysTime(Date(-1, 1, 1));
4706             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4707             assert(sysTime == SysTime(Date(-1, 12, 1)));
4708             sysTime.roll!"months"(1, AllowDayOverflow.no);
4709             assert(sysTime == SysTime(Date(-1, 1, 1)));
4710         }
4711 
4712         {
4713             auto sysTime = SysTime(Date(-4, 1, 1));
4714             sysTime.roll!"months"(-48, AllowDayOverflow.no);
4715             assert(sysTime == SysTime(Date(-4, 1, 1)));
4716             sysTime.roll!"months"(48, AllowDayOverflow.no);
4717             assert(sysTime == SysTime(Date(-4, 1, 1)));
4718         }
4719 
4720         {
4721             auto sysTime = SysTime(Date(-4, 3, 31));
4722             sysTime.roll!"months"(-49, AllowDayOverflow.no);
4723             assert(sysTime == SysTime(Date(-4, 2, 29)));
4724             sysTime.roll!"months"(49, AllowDayOverflow.no);
4725             assert(sysTime == SysTime(Date(-4, 3, 29)));
4726         }
4727 
4728         {
4729             auto sysTime = SysTime(Date(-4, 3, 31));
4730             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4731             assert(sysTime == SysTime(Date(-4, 2, 29)));
4732             sysTime.roll!"months"(85, AllowDayOverflow.no);
4733             assert(sysTime == SysTime(Date(-4, 3, 29)));
4734         }
4735 
4736         {
4737             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
4738             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4739             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 0, 0)));
4740             sysTime.roll!"months"(1, AllowDayOverflow.no);
4741             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
4742         }
4743 
4744         {
4745             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
4746             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4747             assert(sysTime == SysTime(DateTime(1, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4748             sysTime.roll!"months"(1, AllowDayOverflow.no);
4749             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4750         }
4751 
4752         {
4753             auto sysTime = SysTime(DateTime(0, 12, 1, 0, 0, 0));
4754             sysTime.roll!"months"(1, AllowDayOverflow.no);
4755             assert(sysTime == SysTime(DateTime(0, 1, 1, 0, 0, 0)));
4756             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4757             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
4758         }
4759 
4760         {
4761             auto sysTime = SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999));
4762             sysTime.roll!"months"(1, AllowDayOverflow.no);
4763             assert(sysTime == SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
4764             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4765             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
4766         }
4767 
4768         {
4769             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17));
4770             sysTime.roll!"months"(-1, AllowDayOverflow.no);
4771             assert(sysTime == SysTime(DateTime(1, 12, 1, 0, 7, 9), hnsecs(17)));
4772             sysTime.roll!"months"(1, AllowDayOverflow.no);
4773             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 7, 9), hnsecs(17)));
4774         }
4775 
4776         {
4777             auto sysTime = SysTime(DateTime(4, 3, 31, 12, 11, 10), msecs(9));
4778             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4779             assert(sysTime == SysTime(DateTime(4, 2, 29, 12, 11, 10), msecs(9)));
4780             sysTime.roll!"months"(85, AllowDayOverflow.no);
4781             assert(sysTime == SysTime(DateTime(4, 3, 29, 12, 11, 10), msecs(9)));
4782         }
4783 
4784         {
4785             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4786             sysTime.roll!"months"(85, AllowDayOverflow.no);
4787             assert(sysTime == SysTime(DateTime(-3, 4, 30, 12, 11, 10), msecs(9)));
4788             sysTime.roll!"months"(-85, AllowDayOverflow.no);
4789             assert(sysTime == SysTime(DateTime(-3, 3, 30, 12, 11, 10), msecs(9)));
4790         }
4791 
4792         {
4793             auto sysTime = SysTime(DateTime(-3, 3, 31, 12, 11, 10), msecs(9));
4794             sysTime.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no);
4795             assert(sysTime == SysTime(DateTime(-3, 5, 30, 12, 11, 10), msecs(9)));
4796         }
4797     }
4798 
4799 
4800     /++
4801         Adds the given number of units to this $(LREF SysTime). A negative number
4802         will subtract.
4803 
4804         The difference between rolling and adding is that rolling does not
4805         affect larger units. For instance, rolling a $(LREF SysTime) one
4806         year's worth of days gets the exact same $(LREF SysTime).
4807 
4808         Accepted units are `"days"`, `"minutes"`, `"hours"`,
4809         `"minutes"`, `"seconds"`, `"msecs"`, `"usecs"`, and
4810         `"hnsecs"`.
4811 
4812         Note that when rolling msecs, usecs or hnsecs, they all add up to a
4813         second. So, for example, rolling 1000 msecs is exactly the same as
4814         rolling 100,000 usecs.
4815 
4816         Params:
4817             units = The units to add.
4818             value = The number of $(D_PARAM units) to add to this
4819                     $(LREF SysTime).
4820       +/
4821     ref SysTime roll(string units)(long value) @safe nothrow scope
4822         if (units == "days")
4823     {
4824         auto hnsecs = adjTime;
4825         auto gdays = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
4826 
4827         if (hnsecs < 0)
4828         {
4829             hnsecs += convert!("hours", "hnsecs")(24);
4830             --gdays;
4831         }
4832 
4833         auto date = Date(cast(int) gdays);
4834         date.roll!"days"(value);
4835         gdays = date.dayOfGregorianCal - 1;
4836 
4837         if (gdays < 0)
4838         {
4839             hnsecs -= convert!("hours", "hnsecs")(24);
4840             ++gdays;
4841         }
4842 
4843         immutable newDaysHNSecs = convert!("days", "hnsecs")(gdays);
4844         adjTime = newDaysHNSecs + hnsecs;
4845         return  this;
4846     }
4847 
4848     ///
4849     @safe unittest
4850     {
4851         import core.time : msecs, hnsecs;
4852         import std.datetime.date : DateTime;
4853 
4854         auto st1 = SysTime(DateTime(2010, 1, 1, 11, 23, 12));
4855         st1.roll!"days"(1);
4856         assert(st1 == SysTime(DateTime(2010, 1, 2, 11, 23, 12)));
4857         st1.roll!"days"(365);
4858         assert(st1 == SysTime(DateTime(2010, 1, 26, 11, 23, 12)));
4859         st1.roll!"days"(-32);
4860         assert(st1 == SysTime(DateTime(2010, 1, 25, 11, 23, 12)));
4861 
4862         auto st2 = SysTime(DateTime(2010, 7, 4, 12, 0, 0));
4863         st2.roll!"hours"(1);
4864         assert(st2 == SysTime(DateTime(2010, 7, 4, 13, 0, 0)));
4865 
4866         auto st3 = SysTime(DateTime(2010, 2, 12, 12, 0, 0));
4867         st3.roll!"hours"(-1);
4868         assert(st3 == SysTime(DateTime(2010, 2, 12, 11, 0, 0)));
4869 
4870         auto st4 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
4871         st4.roll!"minutes"(1);
4872         assert(st4 == SysTime(DateTime(2009, 12, 31, 0, 1, 0)));
4873 
4874         auto st5 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
4875         st5.roll!"minutes"(-1);
4876         assert(st5 == SysTime(DateTime(2010, 1, 1, 0, 59, 0)));
4877 
4878         auto st6 = SysTime(DateTime(2009, 12, 31, 0, 0, 0));
4879         st6.roll!"seconds"(1);
4880         assert(st6 == SysTime(DateTime(2009, 12, 31, 0, 0, 1)));
4881 
4882         auto st7 = SysTime(DateTime(2010, 1, 1, 0, 0, 0));
4883         st7.roll!"seconds"(-1);
4884         assert(st7 == SysTime(DateTime(2010, 1, 1, 0, 0, 59)));
4885 
4886         auto dt = DateTime(2010, 1, 1, 0, 0, 0);
4887         auto st8 = SysTime(dt);
4888         st8.roll!"msecs"(1);
4889         assert(st8 == SysTime(dt, msecs(1)));
4890 
4891         auto st9 = SysTime(dt);
4892         st9.roll!"msecs"(-1);
4893         assert(st9 == SysTime(dt, msecs(999)));
4894 
4895         auto st10 = SysTime(dt);
4896         st10.roll!"hnsecs"(1);
4897         assert(st10 == SysTime(dt, hnsecs(1)));
4898 
4899         auto st11 = SysTime(dt);
4900         st11.roll!"hnsecs"(-1);
4901         assert(st11 == SysTime(dt, hnsecs(9_999_999)));
4902     }
4903 
4904     @safe unittest
4905     {
4906         import core.time;
4907         // Test A.D.
4908         {
4909             auto sysTime = SysTime(Date(1999, 2, 28));
4910             sysTime.roll!"days"(1);
4911             assert(sysTime == SysTime(Date(1999, 2, 1)));
4912             sysTime.roll!"days"(-1);
4913             assert(sysTime == SysTime(Date(1999, 2, 28)));
4914         }
4915 
4916         {
4917             auto sysTime = SysTime(Date(2000, 2, 28));
4918             sysTime.roll!"days"(1);
4919             assert(sysTime == SysTime(Date(2000, 2, 29)));
4920             sysTime.roll!"days"(1);
4921             assert(sysTime == SysTime(Date(2000, 2, 1)));
4922             sysTime.roll!"days"(-1);
4923             assert(sysTime == SysTime(Date(2000, 2, 29)));
4924         }
4925 
4926         {
4927             auto sysTime = SysTime(Date(1999, 6, 30));
4928             sysTime.roll!"days"(1);
4929             assert(sysTime == SysTime(Date(1999, 6, 1)));
4930             sysTime.roll!"days"(-1);
4931             assert(sysTime == SysTime(Date(1999, 6, 30)));
4932         }
4933 
4934         {
4935             auto sysTime = SysTime(Date(1999, 7, 31));
4936             sysTime.roll!"days"(1);
4937             assert(sysTime == SysTime(Date(1999, 7, 1)));
4938             sysTime.roll!"days"(-1);
4939             assert(sysTime == SysTime(Date(1999, 7, 31)));
4940         }
4941 
4942         {
4943             auto sysTime = SysTime(Date(1999, 1, 1));
4944             sysTime.roll!"days"(-1);
4945             assert(sysTime == SysTime(Date(1999, 1, 31)));
4946             sysTime.roll!"days"(1);
4947             assert(sysTime == SysTime(Date(1999, 1, 1)));
4948         }
4949 
4950         {
4951             auto sysTime = SysTime(Date(1999, 7, 6));
4952             sysTime.roll!"days"(9);
4953             assert(sysTime == SysTime(Date(1999, 7, 15)));
4954             sysTime.roll!"days"(-11);
4955             assert(sysTime == SysTime(Date(1999, 7, 4)));
4956             sysTime.roll!"days"(30);
4957             assert(sysTime == SysTime(Date(1999, 7, 3)));
4958             sysTime.roll!"days"(-3);
4959             assert(sysTime == SysTime(Date(1999, 7, 31)));
4960         }
4961 
4962         {
4963             auto sysTime = SysTime(Date(1999, 7, 6));
4964             sysTime.roll!"days"(365);
4965             assert(sysTime == SysTime(Date(1999, 7, 30)));
4966             sysTime.roll!"days"(-365);
4967             assert(sysTime == SysTime(Date(1999, 7, 6)));
4968             sysTime.roll!"days"(366);
4969             assert(sysTime == SysTime(Date(1999, 7, 31)));
4970             sysTime.roll!"days"(730);
4971             assert(sysTime == SysTime(Date(1999, 7, 17)));
4972             sysTime.roll!"days"(-1096);
4973             assert(sysTime == SysTime(Date(1999, 7, 6)));
4974         }
4975 
4976         {
4977             auto sysTime = SysTime(Date(1999, 2, 6));
4978             sysTime.roll!"days"(365);
4979             assert(sysTime == SysTime(Date(1999, 2, 7)));
4980             sysTime.roll!"days"(-365);
4981             assert(sysTime == SysTime(Date(1999, 2, 6)));
4982             sysTime.roll!"days"(366);
4983             assert(sysTime == SysTime(Date(1999, 2, 8)));
4984             sysTime.roll!"days"(730);
4985             assert(sysTime == SysTime(Date(1999, 2, 10)));
4986             sysTime.roll!"days"(-1096);
4987             assert(sysTime == SysTime(Date(1999, 2, 6)));
4988         }
4989 
4990         {
4991             auto sysTime = SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578));
4992             sysTime.roll!"days"(1);
4993             assert(sysTime == SysTime(DateTime(1999, 2, 1, 7, 9, 2), usecs(234578)));
4994             sysTime.roll!"days"(-1);
4995             assert(sysTime == SysTime(DateTime(1999, 2, 28, 7, 9, 2), usecs(234578)));
4996         }
4997 
4998         {
4999             auto sysTime = SysTime(DateTime(1999, 7, 6, 7, 9, 2), usecs(234578));
5000             sysTime.roll!"days"(9);
5001             assert(sysTime == SysTime(DateTime(1999, 7, 15, 7, 9, 2), usecs(234578)));
5002             sysTime.roll!"days"(-11);
5003             assert(sysTime == SysTime(DateTime(1999, 7, 4, 7, 9, 2), usecs(234578)));
5004             sysTime.roll!"days"(30);
5005             assert(sysTime == SysTime(DateTime(1999, 7, 3, 7, 9, 2), usecs(234578)));
5006             sysTime.roll!"days"(-3);
5007             assert(sysTime == SysTime(DateTime(1999, 7, 31, 7, 9, 2), usecs(234578)));
5008         }
5009 
5010         // Test B.C.
5011         {
5012             auto sysTime = SysTime(Date(-1999, 2, 28));
5013             sysTime.roll!"days"(1);
5014             assert(sysTime == SysTime(Date(-1999, 2, 1)));
5015             sysTime.roll!"days"(-1);
5016             assert(sysTime == SysTime(Date(-1999, 2, 28)));
5017         }
5018 
5019         {
5020             auto sysTime = SysTime(Date(-2000, 2, 28));
5021             sysTime.roll!"days"(1);
5022             assert(sysTime == SysTime(Date(-2000, 2, 29)));
5023             sysTime.roll!"days"(1);
5024             assert(sysTime == SysTime(Date(-2000, 2, 1)));
5025             sysTime.roll!"days"(-1);
5026             assert(sysTime == SysTime(Date(-2000, 2, 29)));
5027         }
5028 
5029         {
5030             auto sysTime = SysTime(Date(-1999, 6, 30));
5031             sysTime.roll!"days"(1);
5032             assert(sysTime == SysTime(Date(-1999, 6, 1)));
5033             sysTime.roll!"days"(-1);
5034             assert(sysTime == SysTime(Date(-1999, 6, 30)));
5035         }
5036 
5037         {
5038             auto sysTime = SysTime(Date(-1999, 7, 31));
5039             sysTime.roll!"days"(1);
5040             assert(sysTime == SysTime(Date(-1999, 7, 1)));
5041             sysTime.roll!"days"(-1);
5042             assert(sysTime == SysTime(Date(-1999, 7, 31)));
5043         }
5044 
5045         {
5046             auto sysTime = SysTime(Date(-1999, 1, 1));
5047             sysTime.roll!"days"(-1);
5048             assert(sysTime == SysTime(Date(-1999, 1, 31)));
5049             sysTime.roll!"days"(1);
5050             assert(sysTime == SysTime(Date(-1999, 1, 1)));
5051         }
5052 
5053         {
5054             auto sysTime = SysTime(Date(-1999, 7, 6));
5055             sysTime.roll!"days"(9);
5056             assert(sysTime == SysTime(Date(-1999, 7, 15)));
5057             sysTime.roll!"days"(-11);
5058             assert(sysTime == SysTime(Date(-1999, 7, 4)));
5059             sysTime.roll!"days"(30);
5060             assert(sysTime == SysTime(Date(-1999, 7, 3)));
5061             sysTime.roll!"days"(-3);
5062             assert(sysTime == SysTime(Date(-1999, 7, 31)));
5063         }
5064 
5065         {
5066             auto sysTime = SysTime(Date(-1999, 7, 6));
5067             sysTime.roll!"days"(365);
5068             assert(sysTime == SysTime(Date(-1999, 7, 30)));
5069             sysTime.roll!"days"(-365);
5070             assert(sysTime == SysTime(Date(-1999, 7, 6)));
5071             sysTime.roll!"days"(366);
5072             assert(sysTime == SysTime(Date(-1999, 7, 31)));
5073             sysTime.roll!"days"(730);
5074             assert(sysTime == SysTime(Date(-1999, 7, 17)));
5075             sysTime.roll!"days"(-1096);
5076             assert(sysTime == SysTime(Date(-1999, 7, 6)));
5077         }
5078 
5079         {
5080             auto sysTime = SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578));
5081             sysTime.roll!"days"(1);
5082             assert(sysTime == SysTime(DateTime(-1999, 2, 1, 7, 9, 2), usecs(234578)));
5083             sysTime.roll!"days"(-1);
5084             assert(sysTime == SysTime(DateTime(-1999, 2, 28, 7, 9, 2), usecs(234578)));
5085         }
5086 
5087         {
5088             auto sysTime = SysTime(DateTime(-1999, 7, 6, 7, 9, 2), usecs(234578));
5089             sysTime.roll!"days"(9);
5090             assert(sysTime == SysTime(DateTime(-1999, 7, 15, 7, 9, 2), usecs(234578)));
5091             sysTime.roll!"days"(-11);
5092             assert(sysTime == SysTime(DateTime(-1999, 7, 4, 7, 9, 2), usecs(234578)));
5093             sysTime.roll!"days"(30);
5094             assert(sysTime == SysTime(DateTime(-1999, 7, 3, 7, 9, 2), usecs(234578)));
5095             sysTime.roll!"days"(-3);
5096         }
5097 
5098         // Test Both
5099         {
5100             auto sysTime = SysTime(Date(1, 7, 6));
5101             sysTime.roll!"days"(-365);
5102             assert(sysTime == SysTime(Date(1, 7, 13)));
5103             sysTime.roll!"days"(365);
5104             assert(sysTime == SysTime(Date(1, 7, 6)));
5105             sysTime.roll!"days"(-731);
5106             assert(sysTime == SysTime(Date(1, 7, 19)));
5107             sysTime.roll!"days"(730);
5108             assert(sysTime == SysTime(Date(1, 7, 5)));
5109         }
5110 
5111         {
5112             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5113             sysTime.roll!"days"(-1);
5114             assert(sysTime == SysTime(DateTime(1, 1, 31, 0, 0, 0)));
5115             sysTime.roll!"days"(1);
5116             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5117         }
5118 
5119         {
5120             auto sysTime = SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999));
5121             sysTime.roll!"days"(-1);
5122             assert(sysTime == SysTime(DateTime(1, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
5123             sysTime.roll!"days"(1);
5124             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
5125         }
5126 
5127         {
5128             auto sysTime = SysTime(DateTime(0, 12, 31, 0, 0, 0));
5129             sysTime.roll!"days"(1);
5130             assert(sysTime == SysTime(DateTime(0, 12, 1, 0, 0, 0)));
5131             sysTime.roll!"days"(-1);
5132             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0)));
5133         }
5134 
5135         {
5136             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5137             sysTime.roll!"days"(1);
5138             assert(sysTime == SysTime(DateTime(0, 12, 1, 23, 59, 59), hnsecs(9_999_999)));
5139             sysTime.roll!"days"(-1);
5140             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5141         }
5142 
5143         {
5144             auto sysTime = SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22));
5145             sysTime.roll!"days"(-365);
5146             assert(sysTime == SysTime(DateTime(1, 7, 13, 13, 13, 9), msecs(22)));
5147             sysTime.roll!"days"(365);
5148             assert(sysTime == SysTime(DateTime(1, 7, 6, 13, 13, 9), msecs(22)));
5149             sysTime.roll!"days"(-731);
5150             assert(sysTime == SysTime(DateTime(1, 7, 19, 13, 13, 9), msecs(22)));
5151             sysTime.roll!"days"(730);
5152             assert(sysTime == SysTime(DateTime(1, 7, 5, 13, 13, 9), msecs(22)));
5153         }
5154 
5155         {
5156             auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22));
5157             sysTime.roll!"days"(-365);
5158             assert(sysTime == SysTime(DateTime(0, 7, 13, 13, 13, 9), msecs(22)));
5159             sysTime.roll!"days"(365);
5160             assert(sysTime == SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22)));
5161             sysTime.roll!"days"(-731);
5162             assert(sysTime == SysTime(DateTime(0, 7, 19, 13, 13, 9), msecs(22)));
5163             sysTime.roll!"days"(730);
5164             assert(sysTime == SysTime(DateTime(0, 7, 5, 13, 13, 9), msecs(22)));
5165         }
5166 
5167         {
5168             auto sysTime = SysTime(DateTime(0, 7, 6, 13, 13, 9), msecs(22));
5169             sysTime.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730);
5170             assert(sysTime == SysTime(DateTime(0, 7, 8, 13, 13, 9), msecs(22)));
5171         }
5172 
5173         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5174         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5175         static assert(!__traits(compiles, cst.roll!"days"(4)));
5176         static assert(!__traits(compiles, ist.roll!"days"(4)));
5177 
5178         static void testScope(scope ref SysTime st) @safe
5179         {
5180             auto result = st.roll!"days"(42);
5181         }
5182     }
5183 
5184 
5185     // Shares documentation with "days" version.
5186     ref SysTime roll(string units)(long value) @safe nothrow scope
5187         if (units == "hours" || units == "minutes" || units == "seconds")
5188     {
5189         try
5190         {
5191             auto hnsecs = adjTime;
5192             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
5193 
5194             if (hnsecs < 0)
5195             {
5196                 hnsecs += convert!("hours", "hnsecs")(24);
5197                 --days;
5198             }
5199 
5200             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
5201             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
5202             immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
5203 
5204             auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
5205                                           cast(int) minute, cast(int) second));
5206             dateTime.roll!units(value);
5207             --days;
5208 
5209             hnsecs += convert!("hours", "hnsecs")(dateTime.hour);
5210             hnsecs += convert!("minutes", "hnsecs")(dateTime.minute);
5211             hnsecs += convert!("seconds", "hnsecs")(dateTime.second);
5212 
5213             if (days < 0)
5214             {
5215                 hnsecs -= convert!("hours", "hnsecs")(24);
5216                 ++days;
5217             }
5218 
5219             immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
5220             adjTime = newDaysHNSecs + hnsecs;
5221             return this;
5222         }
5223         catch (Exception e)
5224             assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw.");
5225     }
5226 
5227     // Test roll!"hours"().
5228     @safe unittest
5229     {
5230         import core.time;
5231         static void testST(SysTime orig, int hours, SysTime expected, size_t line = __LINE__) @safe
5232         {
5233             orig.roll!"hours"(hours);
5234             if (orig != expected)
5235                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5236         }
5237 
5238         // Test A.D.
5239         immutable d = msecs(45);
5240         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
5241         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5242         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
5243         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
5244         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d));
5245         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d));
5246         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d));
5247         testST(beforeAD, 6, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d));
5248         testST(beforeAD, 7, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d));
5249         testST(beforeAD, 8, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
5250         testST(beforeAD, 9, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d));
5251         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
5252         testST(beforeAD, 11, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5253         testST(beforeAD, 12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5254         testST(beforeAD, 13, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
5255         testST(beforeAD, 14, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d));
5256         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d));
5257         testST(beforeAD, 16, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
5258         testST(beforeAD, 17, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d));
5259         testST(beforeAD, 18, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d));
5260         testST(beforeAD, 19, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d));
5261         testST(beforeAD, 20, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d));
5262         testST(beforeAD, 21, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d));
5263         testST(beforeAD, 22, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
5264         testST(beforeAD, 23, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
5265         testST(beforeAD, 24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5266         testST(beforeAD, 25, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
5267         testST(beforeAD, 50, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
5268         testST(beforeAD, 10_000, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
5269 
5270         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
5271         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
5272         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 9, 30, 33), d));
5273         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 8, 30, 33), d));
5274         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 7, 30, 33), d));
5275         testST(beforeAD, -6, SysTime(DateTime(1999, 7, 6, 6, 30, 33), d));
5276         testST(beforeAD, -7, SysTime(DateTime(1999, 7, 6, 5, 30, 33), d));
5277         testST(beforeAD, -8, SysTime(DateTime(1999, 7, 6, 4, 30, 33), d));
5278         testST(beforeAD, -9, SysTime(DateTime(1999, 7, 6, 3, 30, 33), d));
5279         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 2, 30, 33), d));
5280         testST(beforeAD, -11, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
5281         testST(beforeAD, -12, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5282         testST(beforeAD, -13, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5283         testST(beforeAD, -14, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
5284         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 21, 30, 33), d));
5285         testST(beforeAD, -16, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
5286         testST(beforeAD, -17, SysTime(DateTime(1999, 7, 6, 19, 30, 33), d));
5287         testST(beforeAD, -18, SysTime(DateTime(1999, 7, 6, 18, 30, 33), d));
5288         testST(beforeAD, -19, SysTime(DateTime(1999, 7, 6, 17, 30, 33), d));
5289         testST(beforeAD, -20, SysTime(DateTime(1999, 7, 6, 16, 30, 33), d));
5290         testST(beforeAD, -21, SysTime(DateTime(1999, 7, 6, 15, 30, 33), d));
5291         testST(beforeAD, -22, SysTime(DateTime(1999, 7, 6, 14, 30, 33), d));
5292         testST(beforeAD, -23, SysTime(DateTime(1999, 7, 6, 13, 30, 33), d));
5293         testST(beforeAD, -24, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5294         testST(beforeAD, -25, SysTime(DateTime(1999, 7, 6, 11, 30, 33), d));
5295         testST(beforeAD, -50, SysTime(DateTime(1999, 7, 6, 10, 30, 33), d));
5296         testST(beforeAD, -10_000, SysTime(DateTime(1999, 7, 6, 20, 30, 33), d));
5297 
5298         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 1, 30, 33), d));
5299         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5300         testST(SysTime(DateTime(1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5301 
5302         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 30, 33), d));
5303         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(1999, 7, 6, 23, 30, 33), d));
5304         testST(SysTime(DateTime(1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(1999, 7, 6, 22, 30, 33), d));
5305 
5306         testST(SysTime(DateTime(1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 7, 31, 0, 30, 33), d));
5307         testST(SysTime(DateTime(1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(1999, 8, 1, 23, 30, 33), d));
5308 
5309         testST(SysTime(DateTime(1999, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(1999, 12, 31, 0, 30, 33), d));
5310         testST(SysTime(DateTime(2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(2000, 1, 1, 23, 30, 33), d));
5311 
5312         testST(SysTime(DateTime(1999, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(1999, 2, 28, 0, 30, 33), d));
5313         testST(SysTime(DateTime(1999, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(1999, 3, 2, 23, 30, 33), d));
5314 
5315         testST(SysTime(DateTime(2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(2000, 2, 28, 0, 30, 33), d));
5316         testST(SysTime(DateTime(2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(2000, 3, 1, 23, 30, 33), d));
5317 
5318         // Test B.C.
5319         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5320         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5321         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
5322         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
5323         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d));
5324         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d));
5325         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d));
5326         testST(beforeBC, 6, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d));
5327         testST(beforeBC, 7, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d));
5328         testST(beforeBC, 8, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
5329         testST(beforeBC, 9, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d));
5330         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
5331         testST(beforeBC, 11, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5332         testST(beforeBC, 12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5333         testST(beforeBC, 13, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
5334         testST(beforeBC, 14, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d));
5335         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d));
5336         testST(beforeBC, 16, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
5337         testST(beforeBC, 17, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d));
5338         testST(beforeBC, 18, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d));
5339         testST(beforeBC, 19, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d));
5340         testST(beforeBC, 20, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d));
5341         testST(beforeBC, 21, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d));
5342         testST(beforeBC, 22, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
5343         testST(beforeBC, 23, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
5344         testST(beforeBC, 24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5345         testST(beforeBC, 25, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
5346         testST(beforeBC, 50, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
5347         testST(beforeBC, 10_000, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
5348 
5349         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
5350         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
5351         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 9, 30, 33), d));
5352         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 8, 30, 33), d));
5353         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 7, 30, 33), d));
5354         testST(beforeBC, -6, SysTime(DateTime(-1999, 7, 6, 6, 30, 33), d));
5355         testST(beforeBC, -7, SysTime(DateTime(-1999, 7, 6, 5, 30, 33), d));
5356         testST(beforeBC, -8, SysTime(DateTime(-1999, 7, 6, 4, 30, 33), d));
5357         testST(beforeBC, -9, SysTime(DateTime(-1999, 7, 6, 3, 30, 33), d));
5358         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 2, 30, 33), d));
5359         testST(beforeBC, -11, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
5360         testST(beforeBC, -12, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5361         testST(beforeBC, -13, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5362         testST(beforeBC, -14, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
5363         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 21, 30, 33), d));
5364         testST(beforeBC, -16, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
5365         testST(beforeBC, -17, SysTime(DateTime(-1999, 7, 6, 19, 30, 33), d));
5366         testST(beforeBC, -18, SysTime(DateTime(-1999, 7, 6, 18, 30, 33), d));
5367         testST(beforeBC, -19, SysTime(DateTime(-1999, 7, 6, 17, 30, 33), d));
5368         testST(beforeBC, -20, SysTime(DateTime(-1999, 7, 6, 16, 30, 33), d));
5369         testST(beforeBC, -21, SysTime(DateTime(-1999, 7, 6, 15, 30, 33), d));
5370         testST(beforeBC, -22, SysTime(DateTime(-1999, 7, 6, 14, 30, 33), d));
5371         testST(beforeBC, -23, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), d));
5372         testST(beforeBC, -24, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5373         testST(beforeBC, -25, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), d));
5374         testST(beforeBC, -50, SysTime(DateTime(-1999, 7, 6, 10, 30, 33), d));
5375         testST(beforeBC, -10_000, SysTime(DateTime(-1999, 7, 6, 20, 30, 33), d));
5376 
5377         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 1, 30, 33), d));
5378         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5379         testST(SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5380 
5381         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 30, 33), d));
5382         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d));
5383         testST(SysTime(DateTime(-1999, 7, 6, 23, 30, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 22, 30, 33), d));
5384 
5385         testST(SysTime(DateTime(-1999, 7, 31, 23, 30, 33), d), 1, SysTime(DateTime(-1999, 7, 31, 0, 30, 33), d));
5386         testST(SysTime(DateTime(-1999, 8, 1, 0, 30, 33), d), -1, SysTime(DateTime(-1999, 8, 1, 23, 30, 33), d));
5387 
5388         testST(SysTime(DateTime(-2001, 12, 31, 23, 30, 33), d), 1, SysTime(DateTime(-2001, 12, 31, 0, 30, 33), d));
5389         testST(SysTime(DateTime(-2000, 1, 1, 0, 30, 33), d), -1, SysTime(DateTime(-2000, 1, 1, 23, 30, 33), d));
5390 
5391         testST(SysTime(DateTime(-2001, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2001, 2, 28, 0, 30, 33), d));
5392         testST(SysTime(DateTime(-2001, 3, 2, 0, 30, 33), d), -25, SysTime(DateTime(-2001, 3, 2, 23, 30, 33), d));
5393 
5394         testST(SysTime(DateTime(-2000, 2, 28, 23, 30, 33), d), 25, SysTime(DateTime(-2000, 2, 28, 0, 30, 33), d));
5395         testST(SysTime(DateTime(-2000, 3, 1, 0, 30, 33), d), -25, SysTime(DateTime(-2000, 3, 1, 23, 30, 33), d));
5396 
5397         // Test Both
5398         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 17_546, SysTime(DateTime(-1, 1, 1, 13, 30, 33), d));
5399         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -17_546, SysTime(DateTime(1, 1, 1, 11, 30, 33), d));
5400 
5401         {
5402             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5403             sysTime.roll!"hours"(-1);
5404             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 0, 0)));
5405             sysTime.roll!"hours"(1);
5406             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5407         }
5408 
5409         {
5410             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999));
5411             sysTime.roll!"hours"(-1);
5412             assert(sysTime == SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
5413             sysTime.roll!"hours"(1);
5414             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999)));
5415         }
5416 
5417         {
5418             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 0, 0));
5419             sysTime.roll!"hours"(1);
5420             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 0, 0)));
5421             sysTime.roll!"hours"(-1);
5422             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5423         }
5424 
5425         {
5426             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5427             sysTime.roll!"hours"(1);
5428             assert(sysTime == SysTime(DateTime(0, 12, 31, 0, 59, 59), hnsecs(9_999_999)));
5429             sysTime.roll!"hours"(-1);
5430             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5431         }
5432 
5433         {
5434             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5435             sysTime.roll!"hours"(1).roll!"hours"(-67);
5436             assert(sysTime == SysTime(DateTime(0, 12, 31, 5, 59, 59), hnsecs(9_999_999)));
5437         }
5438 
5439         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5440         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5441         static assert(!__traits(compiles, cst.roll!"hours"(4)));
5442         static assert(!__traits(compiles, ist.roll!"hours"(4)));
5443 
5444         static void testScope(scope ref SysTime st) @safe
5445         {
5446             auto result = st.roll!"hours"(42);
5447         }
5448     }
5449 
5450     // Test roll!"minutes"().
5451     @safe unittest
5452     {
5453         import core.time;
5454         static void testST(SysTime orig, int minutes, SysTime expected, size_t line = __LINE__) @safe
5455         {
5456             orig.roll!"minutes"(minutes);
5457             if (orig != expected)
5458                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5459         }
5460 
5461         // Test A.D.
5462         immutable d = usecs(7203);
5463         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
5464         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5465         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5466         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 32, 33), d));
5467         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 33, 33), d));
5468         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 34, 33), d));
5469         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 35, 33), d));
5470         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 40, 33), d));
5471         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5472         testST(beforeAD, 29, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5473         testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5474         testST(beforeAD, 45, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5475         testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5476         testST(beforeAD, 75, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5477         testST(beforeAD, 90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5478         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 10, 33), d));
5479 
5480         testST(beforeAD, 689, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5481         testST(beforeAD, 690, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5482         testST(beforeAD, 691, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5483         testST(beforeAD, 960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5484         testST(beforeAD, 1439, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5485         testST(beforeAD, 1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5486         testST(beforeAD, 1441, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5487         testST(beforeAD, 2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5488 
5489         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5490         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 28, 33), d));
5491         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 27, 33), d));
5492         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 26, 33), d));
5493         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 25, 33), d));
5494         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 20, 33), d));
5495         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5496         testST(beforeAD, -29, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5497         testST(beforeAD, -30, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5498         testST(beforeAD, -45, SysTime(DateTime(1999, 7, 6, 12, 45, 33), d));
5499         testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5500         testST(beforeAD, -75, SysTime(DateTime(1999, 7, 6, 12, 15, 33), d));
5501         testST(beforeAD, -90, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5502         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 50, 33), d));
5503 
5504         testST(beforeAD, -749, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5505         testST(beforeAD, -750, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5506         testST(beforeAD, -751, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5507         testST(beforeAD, -960, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5508         testST(beforeAD, -1439, SysTime(DateTime(1999, 7, 6, 12, 31, 33), d));
5509         testST(beforeAD, -1440, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5510         testST(beforeAD, -1441, SysTime(DateTime(1999, 7, 6, 12, 29, 33), d));
5511         testST(beforeAD, -2880, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5512 
5513         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 12, 1, 33), d));
5514         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 33), d));
5515         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 12, 59, 33), d));
5516 
5517         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(1999, 7, 6, 11, 0, 33), d));
5518         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(1999, 7, 6, 11, 59, 33), d));
5519         testST(SysTime(DateTime(1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(1999, 7, 6, 11, 58, 33), d));
5520 
5521         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(1999, 7, 6, 0, 1, 33), d));
5522         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 33), d));
5523         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(1999, 7, 6, 0, 59, 33), d));
5524 
5525         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(1999, 7, 5, 23, 0, 33), d));
5526         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 33), d));
5527         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(1999, 7, 5, 23, 58, 33), d));
5528 
5529         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(1998, 12, 31, 23, 0, 33), d));
5530         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 33), d));
5531         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(1998, 12, 31, 23, 58, 33), d));
5532 
5533         // Test B.C.
5534         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5535         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5536         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5537         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 32, 33), d));
5538         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 33, 33), d));
5539         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 34, 33), d));
5540         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 35, 33), d));
5541         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 40, 33), d));
5542         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5543         testST(beforeBC, 29, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5544         testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5545         testST(beforeBC, 45, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5546         testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5547         testST(beforeBC, 75, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5548         testST(beforeBC, 90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5549         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 10, 33), d));
5550 
5551         testST(beforeBC, 689, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5552         testST(beforeBC, 690, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5553         testST(beforeBC, 691, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5554         testST(beforeBC, 960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5555         testST(beforeBC, 1439, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5556         testST(beforeBC, 1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5557         testST(beforeBC, 1441, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5558         testST(beforeBC, 2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5559 
5560         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5561         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 28, 33), d));
5562         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 27, 33), d));
5563         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 26, 33), d));
5564         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 25, 33), d));
5565         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 20, 33), d));
5566         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5567         testST(beforeBC, -29, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5568         testST(beforeBC, -30, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5569         testST(beforeBC, -45, SysTime(DateTime(-1999, 7, 6, 12, 45, 33), d));
5570         testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5571         testST(beforeBC, -75, SysTime(DateTime(-1999, 7, 6, 12, 15, 33), d));
5572         testST(beforeBC, -90, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5573         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 50, 33), d));
5574 
5575         testST(beforeBC, -749, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5576         testST(beforeBC, -750, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5577         testST(beforeBC, -751, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5578         testST(beforeBC, -960, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5579         testST(beforeBC, -1439, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), d));
5580         testST(beforeBC, -1440, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5581         testST(beforeBC, -1441, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), d));
5582         testST(beforeBC, -2880, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5583 
5584         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 1, 33), d));
5585         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d));
5586         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 59, 33), d));
5587 
5588         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 11, 0, 33), d));
5589         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d));
5590         testST(SysTime(DateTime(-1999, 7, 6, 11, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 11, 58, 33), d));
5591 
5592         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 1, 33), d));
5593         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d));
5594         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 33), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 59, 33), d));
5595 
5596         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 0, 33), d));
5597         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d));
5598         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 33), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 58, 33), d));
5599 
5600         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 0, 33), d));
5601         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d));
5602         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 33), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 58, 33), d));
5603 
5604         // Test Both
5605         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(1, 1, 1, 0, 59, 0)));
5606         testST(SysTime(DateTime(0, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5607 
5608         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), -1, SysTime(DateTime(0, 1, 1, 0, 59, 0)));
5609         testST(SysTime(DateTime(-1, 12, 31, 23, 59, 0)), 1, SysTime(DateTime(-1, 12, 31, 23, 0, 0)));
5610 
5611         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 1_052_760, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d));
5612         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -1_052_760, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5613 
5614         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 1_052_782, SysTime(DateTime(-1, 1, 1, 11, 52, 33), d));
5615         testST(SysTime(DateTime(1, 1, 1, 13, 52, 33), d), -1_052_782, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5616 
5617         {
5618             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5619             sysTime.roll!"minutes"(-1);
5620             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 0)));
5621             sysTime.roll!"minutes"(1);
5622             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5623         }
5624 
5625         {
5626             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999));
5627             sysTime.roll!"minutes"(-1);
5628             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 59, 59), hnsecs(9_999_999)));
5629             sysTime.roll!"minutes"(1);
5630             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999)));
5631         }
5632 
5633         {
5634             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 0));
5635             sysTime.roll!"minutes"(1);
5636             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 0)));
5637             sysTime.roll!"minutes"(-1);
5638             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0)));
5639         }
5640 
5641         {
5642             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5643             sysTime.roll!"minutes"(1);
5644             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 0, 59), hnsecs(9_999_999)));
5645             sysTime.roll!"minutes"(-1);
5646             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5647         }
5648 
5649         {
5650             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5651             sysTime.roll!"minutes"(1).roll!"minutes"(-79);
5652             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 41, 59), hnsecs(9_999_999)));
5653         }
5654 
5655         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5656         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5657         static assert(!__traits(compiles, cst.roll!"minutes"(4)));
5658         static assert(!__traits(compiles, ist.roll!"minutes"(4)));
5659 
5660         static void testScope(scope ref SysTime st) @safe
5661         {
5662             auto result = st.roll!"minutes"(42);
5663         }
5664     }
5665 
5666     // Test roll!"seconds"().
5667     @safe unittest
5668     {
5669         import core.time;
5670         static void testST(SysTime orig, int seconds, SysTime expected, size_t line = __LINE__) @safe
5671         {
5672             orig.roll!"seconds"(seconds);
5673             if (orig != expected)
5674                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5675         }
5676 
5677         // Test A.D.
5678         immutable d = msecs(274);
5679         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), d);
5680         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5681         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5682         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 35), d));
5683         testST(beforeAD, 3, SysTime(DateTime(1999, 7, 6, 12, 30, 36), d));
5684         testST(beforeAD, 4, SysTime(DateTime(1999, 7, 6, 12, 30, 37), d));
5685         testST(beforeAD, 5, SysTime(DateTime(1999, 7, 6, 12, 30, 38), d));
5686         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 43), d));
5687         testST(beforeAD, 15, SysTime(DateTime(1999, 7, 6, 12, 30, 48), d));
5688         testST(beforeAD, 26, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5689         testST(beforeAD, 27, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5690         testST(beforeAD, 30, SysTime(DateTime(1999, 7, 6, 12, 30, 3), d));
5691         testST(beforeAD, 59, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5692         testST(beforeAD, 60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5693         testST(beforeAD, 61, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5694 
5695         testST(beforeAD, 1766, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5696         testST(beforeAD, 1767, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5697         testST(beforeAD, 1768, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d));
5698         testST(beforeAD, 2007, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5699         testST(beforeAD, 3599, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5700         testST(beforeAD, 3600, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5701         testST(beforeAD, 3601, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5702         testST(beforeAD, 7200, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5703 
5704         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5705         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 31), d));
5706         testST(beforeAD, -3, SysTime(DateTime(1999, 7, 6, 12, 30, 30), d));
5707         testST(beforeAD, -4, SysTime(DateTime(1999, 7, 6, 12, 30, 29), d));
5708         testST(beforeAD, -5, SysTime(DateTime(1999, 7, 6, 12, 30, 28), d));
5709         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 23), d));
5710         testST(beforeAD, -15, SysTime(DateTime(1999, 7, 6, 12, 30, 18), d));
5711         testST(beforeAD, -33, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5712         testST(beforeAD, -34, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5713         testST(beforeAD, -35, SysTime(DateTime(1999, 7, 6, 12, 30, 58), d));
5714         testST(beforeAD, -59, SysTime(DateTime(1999, 7, 6, 12, 30, 34), d));
5715         testST(beforeAD, -60, SysTime(DateTime(1999, 7, 6, 12, 30, 33), d));
5716         testST(beforeAD, -61, SysTime(DateTime(1999, 7, 6, 12, 30, 32), d));
5717 
5718         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 30, 1), d));
5719         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 30, 0), d));
5720         testST(SysTime(DateTime(1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 30, 59), d));
5721 
5722         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 12, 0, 1), d));
5723         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 12, 0, 0), d));
5724         testST(SysTime(DateTime(1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 12, 0, 59), d));
5725 
5726         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(1999, 7, 6, 0, 0, 1), d));
5727         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(1999, 7, 6, 0, 0, 0), d));
5728         testST(SysTime(DateTime(1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(1999, 7, 6, 0, 0, 59), d));
5729 
5730         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(1999, 7, 5, 23, 59, 0), d));
5731         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(1999, 7, 5, 23, 59, 59), d));
5732         testST(SysTime(DateTime(1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(1999, 7, 5, 23, 59, 58), d));
5733 
5734         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(1998, 12, 31, 23, 59, 0), d));
5735         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(1998, 12, 31, 23, 59, 59), d));
5736         testST(SysTime(DateTime(1998, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(1998, 12, 31, 23, 59, 58), d));
5737 
5738         // Test B.C.
5739         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d);
5740         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5741         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5742         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 35), d));
5743         testST(beforeBC, 3, SysTime(DateTime(-1999, 7, 6, 12, 30, 36), d));
5744         testST(beforeBC, 4, SysTime(DateTime(-1999, 7, 6, 12, 30, 37), d));
5745         testST(beforeBC, 5, SysTime(DateTime(-1999, 7, 6, 12, 30, 38), d));
5746         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 43), d));
5747         testST(beforeBC, 15, SysTime(DateTime(-1999, 7, 6, 12, 30, 48), d));
5748         testST(beforeBC, 26, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5749         testST(beforeBC, 27, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5750         testST(beforeBC, 30, SysTime(DateTime(-1999, 7, 6, 12, 30, 3), d));
5751         testST(beforeBC, 59, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5752         testST(beforeBC, 60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5753         testST(beforeBC, 61, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5754 
5755         testST(beforeBC, 1766, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5756         testST(beforeBC, 1767, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5757         testST(beforeBC, 1768, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d));
5758         testST(beforeBC, 2007, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5759         testST(beforeBC, 3599, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5760         testST(beforeBC, 3600, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5761         testST(beforeBC, 3601, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5762         testST(beforeBC, 7200, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5763 
5764         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5765         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 31), d));
5766         testST(beforeBC, -3, SysTime(DateTime(-1999, 7, 6, 12, 30, 30), d));
5767         testST(beforeBC, -4, SysTime(DateTime(-1999, 7, 6, 12, 30, 29), d));
5768         testST(beforeBC, -5, SysTime(DateTime(-1999, 7, 6, 12, 30, 28), d));
5769         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 23), d));
5770         testST(beforeBC, -15, SysTime(DateTime(-1999, 7, 6, 12, 30, 18), d));
5771         testST(beforeBC, -33, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5772         testST(beforeBC, -34, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5773         testST(beforeBC, -35, SysTime(DateTime(-1999, 7, 6, 12, 30, 58), d));
5774         testST(beforeBC, -59, SysTime(DateTime(-1999, 7, 6, 12, 30, 34), d));
5775         testST(beforeBC, -60, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), d));
5776         testST(beforeBC, -61, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), d));
5777 
5778         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 1), d));
5779         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d));
5780         testST(SysTime(DateTime(-1999, 7, 6, 12, 30, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 59), d));
5781 
5782         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 12, 0, 1), d));
5783         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d));
5784         testST(SysTime(DateTime(-1999, 7, 6, 12, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 12, 0, 59), d));
5785 
5786         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 1, SysTime(DateTime(-1999, 7, 6, 0, 0, 1), d));
5787         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), 0, SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d));
5788         testST(SysTime(DateTime(-1999, 7, 6, 0, 0, 0), d), -1, SysTime(DateTime(-1999, 7, 6, 0, 0, 59), d));
5789 
5790         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 1, SysTime(DateTime(-1999, 7, 5, 23, 59, 0), d));
5791         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), 0, SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d));
5792         testST(SysTime(DateTime(-1999, 7, 5, 23, 59, 59), d), -1, SysTime(DateTime(-1999, 7, 5, 23, 59, 58), d));
5793 
5794         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-2000, 12, 31, 23, 59, 0), d));
5795         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), 0, SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d));
5796         testST(SysTime(DateTime(-2000, 12, 31, 23, 59, 59), d), -1, SysTime(DateTime(-2000, 12, 31, 23, 59, 58), d));
5797 
5798         // Test Both
5799         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(1, 1, 1, 0, 0, 59), d));
5800         testST(SysTime(DateTime(0, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(0, 12, 31, 23, 59, 0), d));
5801 
5802         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0), d), -1, SysTime(DateTime(0, 1, 1, 0, 0, 59), d));
5803         testST(SysTime(DateTime(-1, 12, 31, 23, 59, 59), d), 1, SysTime(DateTime(-1, 12, 31, 23, 59, 0), d));
5804 
5805         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_600L, SysTime(DateTime(-1, 1, 1, 11, 30, 33), d));
5806         testST(SysTime(DateTime(1, 1, 1, 13, 30, 33), d), -63_165_600L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5807 
5808         testST(SysTime(DateTime(-1, 1, 1, 11, 30, 33), d), 63_165_617L, SysTime(DateTime(-1, 1, 1, 11, 30, 50), d));
5809         testST(SysTime(DateTime(1, 1, 1, 13, 30, 50), d), -63_165_617L, SysTime(DateTime(1, 1, 1, 13, 30, 33), d));
5810 
5811         {
5812             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5813             sysTime.roll!"seconds"(-1);
5814             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59)));
5815             sysTime.roll!"seconds"(1);
5816             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5817         }
5818 
5819         {
5820             auto sysTime = SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999));
5821             sysTime.roll!"seconds"(-1);
5822             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 59), hnsecs(9_999_999)));
5823             sysTime.roll!"seconds"(1);
5824             assert(sysTime == SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
5825         }
5826 
5827         {
5828             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59));
5829             sysTime.roll!"seconds"(1);
5830             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0)));
5831             sysTime.roll!"seconds"(-1);
5832             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59)));
5833         }
5834 
5835         {
5836             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5837             sysTime.roll!"seconds"(1);
5838             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 0), hnsecs(9_999_999)));
5839             sysTime.roll!"seconds"(-1);
5840             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5841         }
5842 
5843         {
5844             auto sysTime = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5845             sysTime.roll!"seconds"(1).roll!"seconds"(-102);
5846             assert(sysTime == SysTime(DateTime(0, 12, 31, 23, 59, 18), hnsecs(9_999_999)));
5847         }
5848 
5849         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5850         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5851         static assert(!__traits(compiles, cst.roll!"seconds"(4)));
5852         static assert(!__traits(compiles, ist.roll!"seconds"(4)));
5853 
5854         static void testScope(scope ref SysTime st) @safe
5855         {
5856             auto result = st.roll!"seconds"(42);
5857         }
5858     }
5859 
5860 
5861     // Shares documentation with "days" version.
5862     ref SysTime roll(string units)(long value) @safe nothrow scope
5863         if (units == "msecs" || units == "usecs" || units == "hnsecs")
5864     {
5865         auto hnsecs = adjTime;
5866         immutable days = splitUnitsFromHNSecs!"days"(hnsecs);
5867         immutable negative = hnsecs < 0;
5868 
5869         if (negative)
5870             hnsecs += convert!("hours", "hnsecs")(24);
5871 
5872         immutable seconds = splitUnitsFromHNSecs!"seconds"(hnsecs);
5873         hnsecs += convert!(units, "hnsecs")(value);
5874         hnsecs %= convert!("seconds", "hnsecs")(1);
5875 
5876         if (hnsecs < 0)
5877             hnsecs += convert!("seconds", "hnsecs")(1);
5878         hnsecs += convert!("seconds", "hnsecs")(seconds);
5879 
5880         if (negative)
5881             hnsecs -= convert!("hours", "hnsecs")(24);
5882 
5883         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
5884         adjTime = newDaysHNSecs + hnsecs;
5885         return this;
5886     }
5887 
5888 
5889     // Test roll!"msecs"().
5890     @safe unittest
5891     {
5892         import core.time;
5893         static void testST(SysTime orig, int milliseconds, SysTime expected, size_t line = __LINE__) @safe
5894         {
5895             orig.roll!"msecs"(milliseconds);
5896             if (orig != expected)
5897                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
5898         }
5899 
5900         // Test A.D.
5901         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274));
5902         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5903         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275)));
5904         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(276)));
5905         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(284)));
5906         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(374)));
5907         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5908         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5909         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5910         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(275)));
5911         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5912         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5913         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5914         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(1)));
5915         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5916         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5917 
5918         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273)));
5919         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(272)));
5920         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(264)));
5921         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(174)));
5922         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5923         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5924         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5925         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(273)));
5926         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(274)));
5927         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5928         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5929         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
5930         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(999)));
5931 
5932         // Test B.C.
5933         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274));
5934         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5935         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275)));
5936         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(276)));
5937         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(284)));
5938         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(374)));
5939         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5940         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5941         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5942         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(275)));
5943         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5944         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5945         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5946         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(1)));
5947         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5948         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5949 
5950         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273)));
5951         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(272)));
5952         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(264)));
5953         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(174)));
5954         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5955         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5956         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5957         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(273)));
5958         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(274)));
5959         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5960         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5961         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
5962         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), msecs(999)));
5963 
5964         // Test Both
5965         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
5966         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(1)));
5967         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5968         testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(999)));
5969         testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(998)));
5970         testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5971         testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
5972         testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), msecs(445)));
5973 
5974         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5975         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_989_999)));
5976         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5977         testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999)));
5978         testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999)));
5979         testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5980         testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
5981         testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(5_549_999)));
5982 
5983         {
5984             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
5985             st.roll!"msecs"(1202).roll!"msecs"(-703);
5986             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(4_989_999)));
5987         }
5988 
5989         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5990         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
5991         static assert(!__traits(compiles, cst.roll!"msecs"(4)));
5992         static assert(!__traits(compiles, ist.roll!"msecs"(4)));
5993 
5994         static void testScope(scope ref SysTime st) @safe
5995         {
5996             auto result = st.roll!"msecs"(42);
5997         }
5998     }
5999 
6000     // Test roll!"usecs"().
6001     @safe unittest
6002     {
6003         import core.time;
6004         static void testST(SysTime orig, long microseconds, SysTime expected, size_t line = __LINE__) @safe
6005         {
6006             orig.roll!"usecs"(microseconds);
6007             if (orig != expected)
6008                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
6009         }
6010 
6011         // Test A.D.
6012         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274));
6013         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6014         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(275)));
6015         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(276)));
6016         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(284)));
6017         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(374)));
6018         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999)));
6019         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1000)));
6020         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1274)));
6021         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(1275)));
6022         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(2274)));
6023         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(26_999)));
6024         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_000)));
6025         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(27_001)));
6026         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(766_999)));
6027         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(767_000)));
6028         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6029         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6030         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6031 
6032         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(273)));
6033         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(272)));
6034         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(264)));
6035         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(174)));
6036         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
6037         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_999)));
6038         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_274)));
6039         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(999_273)));
6040         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(998_274)));
6041         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(967_000)));
6042         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(966_999)));
6043         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(167_000)));
6044         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(166_999)));
6045         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6046         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6047         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(274)));
6048 
6049         // Test B.C.
6050         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274));
6051         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6052         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(275)));
6053         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(276)));
6054         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(284)));
6055         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(374)));
6056         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999)));
6057         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1000)));
6058         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1274)));
6059         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(1275)));
6060         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(2274)));
6061         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(26_999)));
6062         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_000)));
6063         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(27_001)));
6064         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(766_999)));
6065         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(767_000)));
6066         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6067         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6068         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6069 
6070         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(273)));
6071         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(272)));
6072         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(264)));
6073         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(174)));
6074         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6075         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_999)));
6076         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_274)));
6077         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(999_273)));
6078         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(998_274)));
6079         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(967_000)));
6080         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(966_999)));
6081         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(167_000)));
6082         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(166_999)));
6083         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6084         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6085         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), usecs(274)));
6086 
6087         // Test Both
6088         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6089         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(1)));
6090         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6091         testST(beforeBoth1, -1, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_999)));
6092         testST(beforeBoth1, -2, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_998)));
6093         testST(beforeBoth1, -1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(999_000)));
6094         testST(beforeBoth1, -2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(998_000)));
6095         testST(beforeBoth1, -2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(997_445)));
6096         testST(beforeBoth1, -1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6097         testST(beforeBoth1, -2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6098         testST(beforeBoth1, -2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), usecs(666_667)));
6099 
6100         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6101         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_989)));
6102         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6103         testST(beforeBoth2, 1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9)));
6104         testST(beforeBoth2, 2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19)));
6105         testST(beforeBoth2, 1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9999)));
6106         testST(beforeBoth2, 2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(19_999)));
6107         testST(beforeBoth2, 2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(25_549)));
6108         testST(beforeBoth2, 1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6109         testST(beforeBoth2, 2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6110         testST(beforeBoth2, 2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(3_333_329)));
6111 
6112         {
6113             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6114             st.roll!"usecs"(9_020_027);
6115             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(200_269)));
6116         }
6117 
6118         {
6119             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6120             st.roll!"usecs"(9_020_027).roll!"usecs"(-70_034);
6121             assert(st == SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_499_929)));
6122         }
6123 
6124         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6125         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6126         static assert(!__traits(compiles, cst.roll!"usecs"(4)));
6127         static assert(!__traits(compiles, ist.roll!"usecs"(4)));
6128 
6129         static void testScope(scope ref SysTime st) @safe
6130         {
6131             auto result = st.roll!"usecs"(42);
6132         }
6133     }
6134 
6135     // Test roll!"hnsecs"().
6136     @safe unittest
6137     {
6138         import core.time;
6139         static void testST(SysTime orig, long hnsecs, SysTime expected, size_t line = __LINE__) @safe
6140         {
6141             orig.roll!"hnsecs"(hnsecs);
6142             if (orig != expected)
6143                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
6144         }
6145 
6146         // Test A.D.
6147         auto dtAD = DateTime(1999, 7, 6, 12, 30, 33);
6148         auto beforeAD = SysTime(dtAD, hnsecs(274));
6149         testST(beforeAD, 0, SysTime(dtAD, hnsecs(274)));
6150         testST(beforeAD, 1, SysTime(dtAD, hnsecs(275)));
6151         testST(beforeAD, 2, SysTime(dtAD, hnsecs(276)));
6152         testST(beforeAD, 10, SysTime(dtAD, hnsecs(284)));
6153         testST(beforeAD, 100, SysTime(dtAD, hnsecs(374)));
6154         testST(beforeAD, 725, SysTime(dtAD, hnsecs(999)));
6155         testST(beforeAD, 726, SysTime(dtAD, hnsecs(1000)));
6156         testST(beforeAD, 1000, SysTime(dtAD, hnsecs(1274)));
6157         testST(beforeAD, 1001, SysTime(dtAD, hnsecs(1275)));
6158         testST(beforeAD, 2000, SysTime(dtAD, hnsecs(2274)));
6159         testST(beforeAD, 26_725, SysTime(dtAD, hnsecs(26_999)));
6160         testST(beforeAD, 26_726, SysTime(dtAD, hnsecs(27_000)));
6161         testST(beforeAD, 26_727, SysTime(dtAD, hnsecs(27_001)));
6162         testST(beforeAD, 1_766_725, SysTime(dtAD, hnsecs(1_766_999)));
6163         testST(beforeAD, 1_766_726, SysTime(dtAD, hnsecs(1_767_000)));
6164         testST(beforeAD, 1_000_000, SysTime(dtAD, hnsecs(1_000_274)));
6165         testST(beforeAD, 60_000_000L, SysTime(dtAD, hnsecs(274)));
6166         testST(beforeAD, 3_600_000_000L, SysTime(dtAD, hnsecs(274)));
6167         testST(beforeAD, 600_000_000L, SysTime(dtAD, hnsecs(274)));
6168         testST(beforeAD, 36_000_000_000L, SysTime(dtAD, hnsecs(274)));
6169 
6170         testST(beforeAD, -1, SysTime(dtAD, hnsecs(273)));
6171         testST(beforeAD, -2, SysTime(dtAD, hnsecs(272)));
6172         testST(beforeAD, -10, SysTime(dtAD, hnsecs(264)));
6173         testST(beforeAD, -100, SysTime(dtAD, hnsecs(174)));
6174         testST(beforeAD, -274, SysTime(dtAD));
6175         testST(beforeAD, -275, SysTime(dtAD, hnsecs(9_999_999)));
6176         testST(beforeAD, -1000, SysTime(dtAD, hnsecs(9_999_274)));
6177         testST(beforeAD, -1001, SysTime(dtAD, hnsecs(9_999_273)));
6178         testST(beforeAD, -2000, SysTime(dtAD, hnsecs(9_998_274)));
6179         testST(beforeAD, -33_274, SysTime(dtAD, hnsecs(9_967_000)));
6180         testST(beforeAD, -33_275, SysTime(dtAD, hnsecs(9_966_999)));
6181         testST(beforeAD, -1_833_274, SysTime(dtAD, hnsecs(8_167_000)));
6182         testST(beforeAD, -1_833_275, SysTime(dtAD, hnsecs(8_166_999)));
6183         testST(beforeAD, -1_000_000, SysTime(dtAD, hnsecs(9_000_274)));
6184         testST(beforeAD, -60_000_000L, SysTime(dtAD, hnsecs(274)));
6185         testST(beforeAD, -3_600_000_000L, SysTime(dtAD, hnsecs(274)));
6186         testST(beforeAD, -600_000_000L, SysTime(dtAD, hnsecs(274)));
6187         testST(beforeAD, -36_000_000_000L, SysTime(dtAD, hnsecs(274)));
6188 
6189         // Test B.C.
6190         auto dtBC = DateTime(-1999, 7, 6, 12, 30, 33);
6191         auto beforeBC = SysTime(dtBC, hnsecs(274));
6192         testST(beforeBC, 0, SysTime(dtBC, hnsecs(274)));
6193         testST(beforeBC, 1, SysTime(dtBC, hnsecs(275)));
6194         testST(beforeBC, 2, SysTime(dtBC, hnsecs(276)));
6195         testST(beforeBC, 10, SysTime(dtBC, hnsecs(284)));
6196         testST(beforeBC, 100, SysTime(dtBC, hnsecs(374)));
6197         testST(beforeBC, 725, SysTime(dtBC, hnsecs(999)));
6198         testST(beforeBC, 726, SysTime(dtBC, hnsecs(1000)));
6199         testST(beforeBC, 1000, SysTime(dtBC, hnsecs(1274)));
6200         testST(beforeBC, 1001, SysTime(dtBC, hnsecs(1275)));
6201         testST(beforeBC, 2000, SysTime(dtBC, hnsecs(2274)));
6202         testST(beforeBC, 26_725, SysTime(dtBC, hnsecs(26_999)));
6203         testST(beforeBC, 26_726, SysTime(dtBC, hnsecs(27_000)));
6204         testST(beforeBC, 26_727, SysTime(dtBC, hnsecs(27_001)));
6205         testST(beforeBC, 1_766_725, SysTime(dtBC, hnsecs(1_766_999)));
6206         testST(beforeBC, 1_766_726, SysTime(dtBC, hnsecs(1_767_000)));
6207         testST(beforeBC, 1_000_000, SysTime(dtBC, hnsecs(1_000_274)));
6208         testST(beforeBC, 60_000_000L, SysTime(dtBC, hnsecs(274)));
6209         testST(beforeBC, 3_600_000_000L, SysTime(dtBC, hnsecs(274)));
6210         testST(beforeBC, 600_000_000L, SysTime(dtBC, hnsecs(274)));
6211         testST(beforeBC, 36_000_000_000L, SysTime(dtBC, hnsecs(274)));
6212 
6213         testST(beforeBC, -1, SysTime(dtBC, hnsecs(273)));
6214         testST(beforeBC, -2, SysTime(dtBC, hnsecs(272)));
6215         testST(beforeBC, -10, SysTime(dtBC, hnsecs(264)));
6216         testST(beforeBC, -100, SysTime(dtBC, hnsecs(174)));
6217         testST(beforeBC, -274, SysTime(dtBC));
6218         testST(beforeBC, -275, SysTime(dtBC, hnsecs(9_999_999)));
6219         testST(beforeBC, -1000, SysTime(dtBC, hnsecs(9_999_274)));
6220         testST(beforeBC, -1001, SysTime(dtBC, hnsecs(9_999_273)));
6221         testST(beforeBC, -2000, SysTime(dtBC, hnsecs(9_998_274)));
6222         testST(beforeBC, -33_274, SysTime(dtBC, hnsecs(9_967_000)));
6223         testST(beforeBC, -33_275, SysTime(dtBC, hnsecs(9_966_999)));
6224         testST(beforeBC, -1_833_274, SysTime(dtBC, hnsecs(8_167_000)));
6225         testST(beforeBC, -1_833_275, SysTime(dtBC, hnsecs(8_166_999)));
6226         testST(beforeBC, -1_000_000, SysTime(dtBC, hnsecs(9_000_274)));
6227         testST(beforeBC, -60_000_000L, SysTime(dtBC, hnsecs(274)));
6228         testST(beforeBC, -3_600_000_000L, SysTime(dtBC, hnsecs(274)));
6229         testST(beforeBC, -600_000_000L, SysTime(dtBC, hnsecs(274)));
6230         testST(beforeBC, -36_000_000_000L, SysTime(dtBC, hnsecs(274)));
6231 
6232         // Test Both
6233         auto dtBoth1 = DateTime(1, 1, 1, 0, 0, 0);
6234         auto beforeBoth1 = SysTime(dtBoth1);
6235         testST(beforeBoth1, 1, SysTime(dtBoth1, hnsecs(1)));
6236         testST(beforeBoth1, 0, SysTime(dtBoth1));
6237         testST(beforeBoth1, -1, SysTime(dtBoth1, hnsecs(9_999_999)));
6238         testST(beforeBoth1, -2, SysTime(dtBoth1, hnsecs(9_999_998)));
6239         testST(beforeBoth1, -1000, SysTime(dtBoth1, hnsecs(9_999_000)));
6240         testST(beforeBoth1, -2000, SysTime(dtBoth1, hnsecs(9_998_000)));
6241         testST(beforeBoth1, -2555, SysTime(dtBoth1, hnsecs(9_997_445)));
6242         testST(beforeBoth1, -1_000_000, SysTime(dtBoth1, hnsecs(9_000_000)));
6243         testST(beforeBoth1, -2_000_000, SysTime(dtBoth1, hnsecs(8_000_000)));
6244         testST(beforeBoth1, -2_333_333, SysTime(dtBoth1, hnsecs(7_666_667)));
6245         testST(beforeBoth1, -10_000_000, SysTime(dtBoth1));
6246         testST(beforeBoth1, -20_000_000, SysTime(dtBoth1));
6247         testST(beforeBoth1, -20_888_888, SysTime(dtBoth1, hnsecs(9_111_112)));
6248 
6249         auto dtBoth2 = DateTime(0, 12, 31, 23, 59, 59);
6250         auto beforeBoth2 = SysTime(dtBoth2, hnsecs(9_999_999));
6251         testST(beforeBoth2, -1, SysTime(dtBoth2, hnsecs(9_999_998)));
6252         testST(beforeBoth2, 0, SysTime(dtBoth2, hnsecs(9_999_999)));
6253         testST(beforeBoth2, 1, SysTime(dtBoth2));
6254         testST(beforeBoth2, 2, SysTime(dtBoth2, hnsecs(1)));
6255         testST(beforeBoth2, 1000, SysTime(dtBoth2, hnsecs(999)));
6256         testST(beforeBoth2, 2000, SysTime(dtBoth2, hnsecs(1999)));
6257         testST(beforeBoth2, 2555, SysTime(dtBoth2, hnsecs(2554)));
6258         testST(beforeBoth2, 1_000_000, SysTime(dtBoth2, hnsecs(999_999)));
6259         testST(beforeBoth2, 2_000_000, SysTime(dtBoth2, hnsecs(1_999_999)));
6260         testST(beforeBoth2, 2_333_333, SysTime(dtBoth2, hnsecs(2_333_332)));
6261         testST(beforeBoth2, 10_000_000, SysTime(dtBoth2, hnsecs(9_999_999)));
6262         testST(beforeBoth2, 20_000_000, SysTime(dtBoth2, hnsecs(9_999_999)));
6263         testST(beforeBoth2, 20_888_888, SysTime(dtBoth2, hnsecs(888_887)));
6264 
6265         {
6266             auto st = SysTime(dtBoth2, hnsecs(9_999_999));
6267             st.roll!"hnsecs"(70_777_222).roll!"hnsecs"(-222_555_292);
6268             assert(st == SysTime(dtBoth2, hnsecs(8_221_929)));
6269         }
6270 
6271         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6272         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6273         static assert(!__traits(compiles, cst.roll!"hnsecs"(4)));
6274         static assert(!__traits(compiles, ist.roll!"hnsecs"(4)));
6275 
6276         static void testScope(scope ref SysTime st) @safe
6277         {
6278             auto result = st.roll!"hnsecs"(42);
6279         }
6280     }
6281 
6282 
6283     /++
6284         Gives the result of adding or subtracting a $(REF Duration, core,time)
6285         from this $(LREF SysTime).
6286 
6287         The legal types of arithmetic for $(LREF SysTime) using this operator
6288         are
6289 
6290         $(BOOKTABLE,
6291         $(TR $(TD SysTime) $(TD +) $(TD Duration) $(TD -->) $(TD SysTime))
6292         $(TR $(TD SysTime) $(TD -) $(TD Duration) $(TD -->) $(TD SysTime))
6293         )
6294 
6295         Params:
6296             duration = The $(REF Duration, core,time) to add to or subtract from
6297                        this $(LREF SysTime).
6298       +/
6299     SysTime opBinary(string op)(Duration duration) @safe const pure nothrow return scope
6300         if (op == "+" || op == "-")
6301     {
6302         SysTime retval = SysTime(this._stdTime, this._timezone);
6303         immutable hnsecs = duration.total!"hnsecs";
6304         mixin("retval._stdTime " ~ op ~ "= hnsecs;");
6305         return retval;
6306     }
6307 
6308     ///
6309     @safe unittest
6310     {
6311         import core.time : hours, seconds;
6312         import std.datetime.date : DateTime;
6313 
6314         assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + seconds(1) ==
6315                SysTime(DateTime(2016, 1, 1, 0, 0, 0)));
6316 
6317         assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + hours(1) ==
6318                SysTime(DateTime(2016, 1, 1, 0, 59, 59)));
6319 
6320         assert(SysTime(DateTime(2016, 1, 1, 0, 0, 0)) - seconds(1) ==
6321                SysTime(DateTime(2015, 12, 31, 23, 59, 59)));
6322 
6323         assert(SysTime(DateTime(2016, 1, 1, 0, 59, 59)) - hours(1) ==
6324                SysTime(DateTime(2015, 12, 31, 23, 59, 59)));
6325     }
6326 
6327     @safe unittest
6328     {
6329         import core.time;
6330         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_678));
6331 
6332         assert(st + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
6333         assert(st + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
6334         assert(st + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
6335         assert(st + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
6336         assert(st + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
6337         assert(st + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
6338         assert(st + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
6339         assert(st + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
6340         assert(st + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
6341         assert(st + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
6342         assert(st + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
6343         assert(st + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
6344         assert(st + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
6345         assert(st + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
6346         assert(st + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
6347         assert(st + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671)));
6348 
6349         assert(st - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33), hnsecs(2_345_678)));
6350         assert(st - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33), hnsecs(2_345_678)));
6351         assert(st - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33), hnsecs(2_345_678)));
6352         assert(st - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33), hnsecs(2_345_678)));
6353         assert(st - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33), hnsecs(2_345_678)));
6354         assert(st - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33), hnsecs(2_345_678)));
6355         assert(st - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33), hnsecs(2_345_678)));
6356         assert(st - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33), hnsecs(2_345_678)));
6357         assert(st - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40), hnsecs(2_345_678)));
6358         assert(st - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26), hnsecs(2_345_678)));
6359         assert(st - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_415_678)));
6360         assert(st - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_275_678)));
6361         assert(st - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_748)));
6362         assert(st - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_608)));
6363         assert(st - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_685)));
6364         assert(st - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2_345_671)));
6365 
6366         static void testST(SysTime orig, long hnsecs, SysTime expected, size_t line = __LINE__) @safe
6367         {
6368             auto result = orig + dur!"hnsecs"(hnsecs);
6369             if (result != expected)
6370                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", result, expected), __FILE__, line);
6371         }
6372 
6373         // Test A.D.
6374         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
6375         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
6376         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
6377         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
6378         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
6379         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
6380         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
6381         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6382         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6383         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6384         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6385         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6386         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6387         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6388         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6389         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6390         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6391         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
6392         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
6393         testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
6394         testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
6395 
6396         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
6397         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
6398         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
6399         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
6400         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
6401         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6402         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6403         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6404         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6405         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6406         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6407         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6408         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6409         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6410         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
6411         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
6412         testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
6413         testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
6414 
6415         // Test B.C.
6416         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
6417         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
6418         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
6419         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
6420         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
6421         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
6422         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
6423         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6424         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6425         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6426         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6427         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6428         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6429         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6430         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6431         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6432         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6433         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
6434         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
6435         testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
6436         testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
6437 
6438         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
6439         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
6440         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
6441         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
6442         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6443         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6444         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6445         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6446         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6447         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6448         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6449         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6450         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6451         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6452         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
6453         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
6454         testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
6455         testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
6456 
6457         // Test Both
6458         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6459         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6460         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6461         testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6462         testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6463         testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
6464         testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
6465         testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
6466         testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
6467         testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
6468         testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
6469         testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6470         testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
6471         testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
6472 
6473         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6474         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6475         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6476         testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6477         testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6478         testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
6479         testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
6480         testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
6481         testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
6482         testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
6483         testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
6484         testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6485         testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
6486         testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887)));
6487 
6488         auto duration = dur!"seconds"(12);
6489         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6490         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6491         assert(cst + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45)));
6492         assert(ist + duration == SysTime(DateTime(1999, 7, 6, 12, 30, 45)));
6493         assert(cst - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21)));
6494         assert(ist - duration == SysTime(DateTime(1999, 7, 6, 12, 30, 21)));
6495 
6496         static void testScope(scope ref SysTime st, scope ref Duration d) @safe
6497         {
6498             auto result = st + d;
6499         }
6500     }
6501 
6502 
6503     /++
6504         Gives the result of adding or subtracting a $(REF Duration, core,time) from
6505         this $(LREF SysTime), as well as assigning the result to this
6506         $(LREF SysTime).
6507 
6508         The legal types of arithmetic for $(LREF SysTime) using this operator are
6509 
6510         $(BOOKTABLE,
6511         $(TR $(TD SysTime) $(TD +) $(TD Duration) $(TD -->) $(TD SysTime))
6512         $(TR $(TD SysTime) $(TD -) $(TD Duration) $(TD -->) $(TD SysTime))
6513         )
6514 
6515         Params:
6516             duration = The $(REF Duration, core,time) to add to or subtract from
6517                        this $(LREF SysTime).
6518       +/
6519     ref SysTime opOpAssign(string op)(Duration duration) @safe pure nothrow scope
6520         if (op == "+" || op == "-")
6521     {
6522         immutable hnsecs = duration.total!"hnsecs";
6523         mixin("_stdTime " ~ op ~ "= hnsecs;");
6524         return this;
6525     }
6526 
6527     @safe unittest
6528     {
6529         import core.time;
6530         auto before = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6531         assert(before + dur!"weeks"(7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
6532         assert(before + dur!"weeks"(-7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
6533         assert(before + dur!"days"(7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
6534         assert(before + dur!"days"(-7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
6535 
6536         assert(before + dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
6537         assert(before + dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
6538         assert(before + dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
6539         assert(before + dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
6540         assert(before + dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
6541         assert(before + dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
6542         assert(before + dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
6543         assert(before + dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
6544         assert(before + dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
6545         assert(before + dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
6546         assert(before + dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
6547         assert(before + dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
6548 
6549         assert(before - dur!"weeks"(-7) == SysTime(DateTime(1999, 8, 24, 12, 30, 33)));
6550         assert(before - dur!"weeks"(7) == SysTime(DateTime(1999, 5, 18, 12, 30, 33)));
6551         assert(before - dur!"days"(-7) == SysTime(DateTime(1999, 7, 13, 12, 30, 33)));
6552         assert(before - dur!"days"(7) == SysTime(DateTime(1999, 6, 29, 12, 30, 33)));
6553 
6554         assert(before - dur!"hours"(-7) == SysTime(DateTime(1999, 7, 6, 19, 30, 33)));
6555         assert(before - dur!"hours"(7) == SysTime(DateTime(1999, 7, 6, 5, 30, 33)));
6556         assert(before - dur!"minutes"(-7) == SysTime(DateTime(1999, 7, 6, 12, 37, 33)));
6557         assert(before - dur!"minutes"(7) == SysTime(DateTime(1999, 7, 6, 12, 23, 33)));
6558         assert(before - dur!"seconds"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 40)));
6559         assert(before - dur!"seconds"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 26)));
6560         assert(before - dur!"msecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), msecs(7)));
6561         assert(before - dur!"msecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), msecs(993)));
6562         assert(before - dur!"usecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), usecs(7)));
6563         assert(before - dur!"usecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), usecs(999_993)));
6564         assert(before - dur!"hnsecs"(-7) == SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(7)));
6565         assert(before - dur!"hnsecs"(7) == SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_993)));
6566 
6567         static void testST(SysTime orig, long hnsecs, SysTime expected, size_t line = __LINE__) @safe
6568         {
6569             auto r = orig += dur!"hnsecs"(hnsecs);
6570             if (orig != expected)
6571                 throw new AssertError(format("Failed 1. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
6572             if (r != expected)
6573                 throw new AssertError(format("Failed 2. actual [%s] != expected [%s]", r, expected), __FILE__, line);
6574         }
6575 
6576         // Test A.D.
6577         auto beforeAD = SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274));
6578         testST(beforeAD, 0, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(274)));
6579         testST(beforeAD, 1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(275)));
6580         testST(beforeAD, 2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(276)));
6581         testST(beforeAD, 10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(284)));
6582         testST(beforeAD, 100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(374)));
6583         testST(beforeAD, 725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(999)));
6584         testST(beforeAD, 726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6585         testST(beforeAD, 1000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6586         testST(beforeAD, 1001, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6587         testST(beforeAD, 2000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6588         testST(beforeAD, 26_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6589         testST(beforeAD, 26_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6590         testST(beforeAD, 26_727, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6591         testST(beforeAD, 1_766_725, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6592         testST(beforeAD, 1_766_726, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6593         testST(beforeAD, 1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6594         testST(beforeAD, 60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 39), hnsecs(274)));
6595         testST(beforeAD, 3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 36, 33), hnsecs(274)));
6596         testST(beforeAD, 600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 31, 33), hnsecs(274)));
6597         testST(beforeAD, 36_000_000_000L, SysTime(DateTime(1999, 7, 6, 13, 30, 33), hnsecs(274)));
6598 
6599         testST(beforeAD, -1, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(273)));
6600         testST(beforeAD, -2, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(272)));
6601         testST(beforeAD, -10, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(264)));
6602         testST(beforeAD, -100, SysTime(DateTime(1999, 7, 6, 12, 30, 33), hnsecs(174)));
6603         testST(beforeAD, -274, SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
6604         testST(beforeAD, -275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6605         testST(beforeAD, -1000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6606         testST(beforeAD, -1001, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6607         testST(beforeAD, -2000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6608         testST(beforeAD, -33_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6609         testST(beforeAD, -33_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6610         testST(beforeAD, -1_833_274, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6611         testST(beforeAD, -1_833_275, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6612         testST(beforeAD, -1_000_000, SysTime(DateTime(1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6613         testST(beforeAD, -60_000_000L, SysTime(DateTime(1999, 7, 6, 12, 30, 27), hnsecs(274)));
6614         testST(beforeAD, -3_600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 24, 33), hnsecs(274)));
6615         testST(beforeAD, -600_000_000L, SysTime(DateTime(1999, 7, 6, 12, 29, 33), hnsecs(274)));
6616         testST(beforeAD, -36_000_000_000L, SysTime(DateTime(1999, 7, 6, 11, 30, 33), hnsecs(274)));
6617 
6618         // Test B.C.
6619         auto beforeBC = SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274));
6620         testST(beforeBC, 0, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(274)));
6621         testST(beforeBC, 1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(275)));
6622         testST(beforeBC, 2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(276)));
6623         testST(beforeBC, 10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(284)));
6624         testST(beforeBC, 100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(374)));
6625         testST(beforeBC, 725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(999)));
6626         testST(beforeBC, 726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1000)));
6627         testST(beforeBC, 1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1274)));
6628         testST(beforeBC, 1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1275)));
6629         testST(beforeBC, 2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(2274)));
6630         testST(beforeBC, 26_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(26_999)));
6631         testST(beforeBC, 26_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_000)));
6632         testST(beforeBC, 26_727, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(27_001)));
6633         testST(beforeBC, 1_766_725, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_766_999)));
6634         testST(beforeBC, 1_766_726, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_767_000)));
6635         testST(beforeBC, 1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(1_000_274)));
6636         testST(beforeBC, 60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 39), hnsecs(274)));
6637         testST(beforeBC, 3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 36, 33), hnsecs(274)));
6638         testST(beforeBC, 600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 31, 33), hnsecs(274)));
6639         testST(beforeBC, 36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 13, 30, 33), hnsecs(274)));
6640 
6641         testST(beforeBC, -1, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(273)));
6642         testST(beforeBC, -2, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(272)));
6643         testST(beforeBC, -10, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(264)));
6644         testST(beforeBC, -100, SysTime(DateTime(-1999, 7, 6, 12, 30, 33), hnsecs(174)));
6645         testST(beforeBC, -274, SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
6646         testST(beforeBC, -275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_999)));
6647         testST(beforeBC, -1000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_274)));
6648         testST(beforeBC, -1001, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_999_273)));
6649         testST(beforeBC, -2000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_998_274)));
6650         testST(beforeBC, -33_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_967_000)));
6651         testST(beforeBC, -33_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_966_999)));
6652         testST(beforeBC, -1_833_274, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_167_000)));
6653         testST(beforeBC, -1_833_275, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(8_166_999)));
6654         testST(beforeBC, -1_000_000, SysTime(DateTime(-1999, 7, 6, 12, 30, 32), hnsecs(9_000_274)));
6655         testST(beforeBC, -60_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 30, 27), hnsecs(274)));
6656         testST(beforeBC, -3_600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 24, 33), hnsecs(274)));
6657         testST(beforeBC, -600_000_000L, SysTime(DateTime(-1999, 7, 6, 12, 29, 33), hnsecs(274)));
6658         testST(beforeBC, -36_000_000_000L, SysTime(DateTime(-1999, 7, 6, 11, 30, 33), hnsecs(274)));
6659 
6660         // Test Both
6661         auto beforeBoth1 = SysTime(DateTime(1, 1, 1, 0, 0, 0));
6662         testST(beforeBoth1, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6663         testST(beforeBoth1, 0, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6664         testST(beforeBoth1, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6665         testST(beforeBoth1, -2, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6666         testST(beforeBoth1, -1000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_000)));
6667         testST(beforeBoth1, -2000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_998_000)));
6668         testST(beforeBoth1, -2555, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_997_445)));
6669         testST(beforeBoth1, -1_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_000_000)));
6670         testST(beforeBoth1, -2_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(8_000_000)));
6671         testST(beforeBoth1, -2_333_333, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(7_666_667)));
6672         testST(beforeBoth1, -10_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
6673         testST(beforeBoth1, -20_000_000, SysTime(DateTime(0, 12, 31, 23, 59, 58)));
6674         testST(beforeBoth1, -20_888_888, SysTime(DateTime(0, 12, 31, 23, 59, 57), hnsecs(9_111_112)));
6675 
6676         auto beforeBoth2 = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6677         testST(beforeBoth2, -1, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)));
6678         testST(beforeBoth2, 0, SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
6679         testST(beforeBoth2, 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
6680         testST(beforeBoth2, 2, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
6681         testST(beforeBoth2, 1000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999)));
6682         testST(beforeBoth2, 2000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1999)));
6683         testST(beforeBoth2, 2555, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2554)));
6684         testST(beforeBoth2, 1_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(999_999)));
6685         testST(beforeBoth2, 2_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1_999_999)));
6686         testST(beforeBoth2, 2_333_333, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(2_333_332)));
6687         testST(beforeBoth2, 10_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
6688         testST(beforeBoth2, 20_000_000, SysTime(DateTime(1, 1, 1, 0, 0, 1), hnsecs(9_999_999)));
6689         testST(beforeBoth2, 20_888_888, SysTime(DateTime(1, 1, 1, 0, 0, 2), hnsecs(888_887)));
6690 
6691         {
6692             auto st = SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999));
6693             (st += dur!"hnsecs"(52)) += dur!"seconds"(-907);
6694             assert(st == SysTime(DateTime(0, 12, 31, 23, 44, 53), hnsecs(51)));
6695         }
6696 
6697         auto duration = dur!"seconds"(12);
6698         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6699         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6700         static assert(!__traits(compiles, cst += duration));
6701         static assert(!__traits(compiles, ist += duration));
6702         static assert(!__traits(compiles, cst -= duration));
6703         static assert(!__traits(compiles, ist -= duration));
6704 
6705         static void testScope(scope ref SysTime st, scope ref Duration d) @safe
6706         {
6707             auto result1 = st += d;
6708             auto result2 = st -= d;
6709         }
6710     }
6711 
6712 
6713     /++
6714         Gives the difference between two $(LREF SysTime)s.
6715 
6716         The legal types of arithmetic for $(LREF SysTime) using this operator
6717         are
6718 
6719         $(BOOKTABLE,
6720         $(TR $(TD SysTime) $(TD -) $(TD SysTime) $(TD -->) $(TD duration))
6721         )
6722       +/
6723     Duration opBinary(string op)(SysTime rhs) @safe const pure nothrow scope
6724         if (op == "-")
6725     {
6726         return dur!"hnsecs"(_stdTime - rhs._stdTime);
6727     }
6728 
6729     @safe unittest
6730     {
6731         import core.time;
6732         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1998, 7, 6, 12, 30, 33)) ==
6733                dur!"seconds"(31_536_000));
6734         assert(SysTime(DateTime(1998, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6735                dur!"seconds"(-31_536_000));
6736 
6737         assert(SysTime(DateTime(1999, 8, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6738                dur!"seconds"(26_78_400));
6739         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 8, 6, 12, 30, 33)) ==
6740                dur!"seconds"(-26_78_400));
6741 
6742         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 5, 12, 30, 33)) ==
6743                dur!"seconds"(86_400));
6744         assert(SysTime(DateTime(1999, 7, 5, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6745                dur!"seconds"(-86_400));
6746 
6747         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 11, 30, 33)) ==
6748                dur!"seconds"(3600));
6749         assert(SysTime(DateTime(1999, 7, 6, 11, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6750                dur!"seconds"(-3600));
6751 
6752         assert(SysTime(DateTime(1999, 7, 6, 12, 31, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6753                dur!"seconds"(60));
6754         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 31, 33)) ==
6755                dur!"seconds"(-60));
6756 
6757         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 34)) - SysTime(DateTime(1999, 7, 6, 12, 30, 33)) ==
6758                dur!"seconds"(1));
6759         assert(SysTime(DateTime(1999, 7, 6, 12, 30, 33)) - SysTime(DateTime(1999, 7, 6, 12, 30, 34)) ==
6760                dur!"seconds"(-1));
6761 
6762         {
6763             auto dt = DateTime(1999, 7, 6, 12, 30, 33);
6764             assert(SysTime(dt, msecs(532)) - SysTime(dt) == msecs(532));
6765             assert(SysTime(dt) - SysTime(dt, msecs(532)) == msecs(-532));
6766 
6767             assert(SysTime(dt, usecs(333_347)) - SysTime(dt) == usecs(333_347));
6768             assert(SysTime(dt) - SysTime(dt, usecs(333_347)) == usecs(-333_347));
6769 
6770             assert(SysTime(dt, hnsecs(1_234_567)) - SysTime(dt) == hnsecs(1_234_567));
6771             assert(SysTime(dt) - SysTime(dt, hnsecs(1_234_567)) == hnsecs(-1_234_567));
6772         }
6773 
6774         assert(SysTime(DateTime(1, 1, 1, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(45033));
6775         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(1, 1, 1, 12, 30, 33)) == dur!"seconds"(-45033));
6776         assert(SysTime(DateTime(0, 12, 31, 12, 30, 33)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) == dur!"seconds"(-41367));
6777         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 12, 30, 33)) == dur!"seconds"(41367));
6778 
6779         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)) - SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) ==
6780                dur!"hnsecs"(1));
6781         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)) - SysTime(DateTime(1, 1, 1, 0, 0, 0)) ==
6782                dur!"hnsecs"(-1));
6783 
6784         version (Posix)
6785         {
6786             import std.datetime.timezone : PosixTimeZone;
6787             immutable tz = PosixTimeZone.getTimeZone("America/Los_Angeles");
6788         }
6789         else version (Windows)
6790         {
6791             import std.datetime.timezone : WindowsTimeZone;
6792             immutable tz = WindowsTimeZone.getTimeZone("Pacific Standard Time");
6793         }
6794 
6795         {
6796             auto dt = DateTime(2011, 1, 13, 8, 17, 2);
6797             auto d = msecs(296);
6798             assert(SysTime(dt, d, tz) - SysTime(dt, d, tz) == Duration.zero);
6799             assert(SysTime(dt, d, tz) - SysTime(dt, d, UTC()) == hours(8));
6800             assert(SysTime(dt, d, UTC()) - SysTime(dt, d, tz) == hours(-8));
6801         }
6802 
6803         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6804         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6805         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6806         assert(st - st == Duration.zero);
6807         assert(cst - st == Duration.zero);
6808         assert(ist - st == Duration.zero);
6809 
6810         assert(st - cst == Duration.zero);
6811         assert(cst - cst == Duration.zero);
6812         assert(ist - cst == Duration.zero);
6813 
6814         assert(st - ist == Duration.zero);
6815         assert(cst - ist == Duration.zero);
6816         assert(ist - ist == Duration.zero);
6817 
6818         static void testScope(scope ref SysTime left, scope ref SysTime right) @safe
6819         {
6820             auto result = left - right;
6821         }
6822     }
6823 
6824 
6825     /++
6826         Returns the difference between the two $(LREF SysTime)s in months.
6827 
6828         To get the difference in years, subtract the year property
6829         of two $(LREF SysTime)s. To get the difference in days or weeks,
6830         subtract the $(LREF SysTime)s themselves and use the
6831         $(REF Duration, core,time) that results. Because converting between
6832         months and smaller units requires a specific date (which
6833         $(REF Duration, core,time)s don't have), getting the difference in
6834         months requires some math using both the year and month properties, so
6835         this is a convenience function for getting the difference in months.
6836 
6837         Note that the number of days in the months or how far into the month
6838         either date is is irrelevant. It is the difference in the month property
6839         combined with the difference in years * 12. So, for instance,
6840         December 31st and January 1st are one month apart just as December 1st
6841         and January 31st are one month apart.
6842 
6843         Params:
6844             rhs = The $(LREF SysTime) to subtract from this one.
6845       +/
6846     int diffMonths(scope SysTime rhs) @safe const nothrow scope
6847     {
6848         return (cast(Date) this).diffMonths(cast(Date) rhs);
6849     }
6850 
6851     ///
6852     @safe unittest
6853     {
6854         import core.time;
6855         import std.datetime.date : Date;
6856 
6857         assert(SysTime(Date(1999, 2, 1)).diffMonths(
6858                    SysTime(Date(1999, 1, 31))) == 1);
6859 
6860         assert(SysTime(Date(1999, 1, 31)).diffMonths(
6861                    SysTime(Date(1999, 2, 1))) == -1);
6862 
6863         assert(SysTime(Date(1999, 3, 1)).diffMonths(
6864                    SysTime(Date(1999, 1, 1))) == 2);
6865 
6866         assert(SysTime(Date(1999, 1, 1)).diffMonths(
6867                    SysTime(Date(1999, 3, 31))) == -2);
6868     }
6869 
6870     @safe unittest
6871     {
6872         import core.time;
6873         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6874         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6875         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6876         assert(st.diffMonths(st) == 0);
6877         assert(cst.diffMonths(st) == 0);
6878         assert(ist.diffMonths(st) == 0);
6879 
6880         assert(st.diffMonths(cst) == 0);
6881         assert(cst.diffMonths(cst) == 0);
6882         assert(ist.diffMonths(cst) == 0);
6883 
6884         assert(st.diffMonths(ist) == 0);
6885         assert(cst.diffMonths(ist) == 0);
6886         assert(ist.diffMonths(ist) == 0);
6887 
6888         static void testScope(scope ref SysTime left, scope ref SysTime right) @safe
6889         {
6890             auto result = left.diffMonths(right);
6891         }
6892     }
6893 
6894 
6895     /++
6896         Whether this $(LREF SysTime) is in a leap year.
6897      +/
6898     @property bool isLeapYear() @safe const nothrow scope
6899     {
6900         return (cast(Date) this).isLeapYear;
6901     }
6902 
6903     @safe unittest
6904     {
6905         import core.time;
6906         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6907         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6908         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6909         assert(!st.isLeapYear);
6910         assert(!cst.isLeapYear);
6911         assert(!ist.isLeapYear);
6912 
6913         static void testScope(scope ref SysTime st) @safe
6914         {
6915             auto result = st.isLeapYear;
6916         }
6917     }
6918 
6919 
6920     /++
6921         Day of the week this $(LREF SysTime) is on.
6922       +/
6923     @property DayOfWeek dayOfWeek() @safe const nothrow scope
6924     {
6925         return getDayOfWeek(dayOfGregorianCal);
6926     }
6927 
6928     @safe unittest
6929     {
6930         import core.time;
6931         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6932         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6933         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6934         assert(st.dayOfWeek == DayOfWeek.tue);
6935         assert(cst.dayOfWeek == DayOfWeek.tue);
6936         assert(ist.dayOfWeek == DayOfWeek.tue);
6937 
6938         static void testScope(scope ref SysTime st) @safe
6939         {
6940             auto result = st.dayOfWeek;
6941         }
6942     }
6943 
6944 
6945     /++
6946         Day of the year this $(LREF SysTime) is on.
6947       +/
6948     @property ushort dayOfYear() @safe const nothrow scope
6949     {
6950         return (cast(Date) this).dayOfYear;
6951     }
6952 
6953     ///
6954     @safe unittest
6955     {
6956         import core.time;
6957         import std.datetime.date : DateTime;
6958 
6959         assert(SysTime(DateTime(1999, 1, 1, 12, 22, 7)).dayOfYear == 1);
6960         assert(SysTime(DateTime(1999, 12, 31, 7, 2, 59)).dayOfYear == 365);
6961         assert(SysTime(DateTime(2000, 12, 31, 21, 20, 0)).dayOfYear == 366);
6962     }
6963 
6964     @safe unittest
6965     {
6966         import core.time;
6967         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6968         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6969         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
6970         assert(st.dayOfYear == 187);
6971         assert(cst.dayOfYear == 187);
6972         assert(ist.dayOfYear == 187);
6973 
6974         static void testScope(scope ref SysTime st) @safe
6975         {
6976             auto result = st.dayOfYear;
6977         }
6978     }
6979 
6980 
6981     /++
6982         Day of the year.
6983 
6984         Params:
6985             day = The day of the year to set which day of the year this
6986                   $(LREF SysTime) is on.
6987       +/
6988     @property void dayOfYear(int day) @safe scope
6989     {
6990         immutable hnsecs = adjTime;
6991         immutable days = convert!("hnsecs", "days")(hnsecs);
6992         immutable theRest = hnsecs - convert!("days", "hnsecs")(days);
6993 
6994         auto date = Date(cast(int) days);
6995         date.dayOfYear = day;
6996 
6997         immutable newDaysHNSecs = convert!("days", "hnsecs")(date.dayOfGregorianCal - 1);
6998 
6999         adjTime = newDaysHNSecs + theRest;
7000     }
7001 
7002     @safe unittest
7003     {
7004         import core.time;
7005         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7006         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7007         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7008         st.dayOfYear = 12;
7009         assert(st.dayOfYear == 12);
7010         static assert(!__traits(compiles, cst.dayOfYear = 12));
7011         static assert(!__traits(compiles, ist.dayOfYear = 12));
7012 
7013         static void testScope(scope ref SysTime st) @safe
7014         {
7015             st.dayOfYear = 42;
7016         }
7017     }
7018 
7019 
7020     /++
7021         The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on.
7022      +/
7023     @property int dayOfGregorianCal() @safe const nothrow scope
7024     {
7025         immutable adjustedTime = adjTime;
7026 
7027         // We have to add one because 0 would be midnight, January 1st, 1 A.D.,
7028         // which would be the 1st day of the Gregorian Calendar, not the 0th. So,
7029         // simply casting to days is one day off.
7030         if (adjustedTime > 0)
7031             return cast(int) getUnitsFromHNSecs!"days"(adjustedTime) + 1;
7032 
7033         long hnsecs = adjustedTime;
7034         immutable days = cast(int) splitUnitsFromHNSecs!"days"(hnsecs);
7035 
7036         return hnsecs == 0 ? days + 1 : days;
7037     }
7038 
7039     ///
7040     @safe unittest
7041     {
7042         import core.time;
7043         import std.datetime.date : DateTime;
7044 
7045         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
7046         assert(SysTime(DateTime(1, 12, 31, 23, 59, 59)).dayOfGregorianCal == 365);
7047         assert(SysTime(DateTime(2, 1, 1, 2, 2, 2)).dayOfGregorianCal == 366);
7048 
7049         assert(SysTime(DateTime(0, 12, 31, 7, 7, 7)).dayOfGregorianCal == 0);
7050         assert(SysTime(DateTime(0, 1, 1, 19, 30, 0)).dayOfGregorianCal == -365);
7051         assert(SysTime(DateTime(-1, 12, 31, 4, 7, 0)).dayOfGregorianCal == -366);
7052 
7053         assert(SysTime(DateTime(2000, 1, 1, 9, 30, 20)).dayOfGregorianCal == 730_120);
7054         assert(SysTime(DateTime(2010, 12, 31, 15, 45, 50)).dayOfGregorianCal == 734_137);
7055     }
7056 
7057     @safe unittest
7058     {
7059         import core.time;
7060         // Test A.D.
7061         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1);
7062         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 1);
7063         assert(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 1);
7064 
7065         assert(SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1);
7066         assert(SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)).dayOfGregorianCal == 2);
7067         assert(SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 32);
7068         assert(SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 366);
7069         assert(SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 731);
7070         assert(SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1096);
7071         assert(SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 1462);
7072         assert(SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 17_898);
7073         assert(SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 35_065);
7074         assert(SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_160);
7075         assert(SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 36_525);
7076         assert(SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 37_986);
7077         assert(SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 72_684);
7078         assert(SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 73_049);
7079         assert(SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_208);
7080         assert(SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 109_573);
7081         assert(SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 145_732);
7082         assert(SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 146_098);
7083         assert(SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_257);
7084         assert(SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 182_622);
7085         assert(SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 364_878);
7086         assert(SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 365_243);
7087         assert(SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_023);
7088         assert(SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 584_389);
7089         assert(SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_596);
7090         assert(SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 693_961);
7091         assert(SysTime(DateTime(1945, 11, 12, 12, 2, 9), msecs(212)).dayOfGregorianCal == 710_347);
7092         assert(SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 729_755);
7093         assert(SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_120);
7094         assert(SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == 730_486);
7095 
7096         assert(SysTime(DateTime(2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_773);
7097         assert(SysTime(DateTime(2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_803);
7098         assert(SysTime(DateTime(2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_804);
7099         assert(SysTime(DateTime(2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_831);
7100         assert(SysTime(DateTime(2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_832);
7101         assert(SysTime(DateTime(2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_862);
7102         assert(SysTime(DateTime(2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_863);
7103         assert(SysTime(DateTime(2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_892);
7104         assert(SysTime(DateTime(2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_893);
7105         assert(SysTime(DateTime(2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_923);
7106         assert(SysTime(DateTime(2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_924);
7107         assert(SysTime(DateTime(2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_953);
7108         assert(SysTime(DateTime(2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_954);
7109         assert(SysTime(DateTime(2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_984);
7110         assert(SysTime(DateTime(2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 733_985);
7111         assert(SysTime(DateTime(2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_015);
7112         assert(SysTime(DateTime(2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_016);
7113         assert(SysTime(DateTime(2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_045);
7114         assert(SysTime(DateTime(2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_046);
7115         assert(SysTime(DateTime(2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_076);
7116         assert(SysTime(DateTime(2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_077);
7117         assert(SysTime(DateTime(2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_106);
7118         assert(SysTime(DateTime(2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_107);
7119         assert(SysTime(DateTime(2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == 734_137);
7120 
7121         assert(SysTime(DateTime(2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == 734_534);
7122         assert(SysTime(DateTime(2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == 734_561);
7123         assert(SysTime(DateTime(2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == 734_562);
7124         assert(SysTime(DateTime(2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == 734_563);
7125 
7126         // Test B.C.
7127         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == 0);
7128         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == 0);
7129         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59)).dayOfGregorianCal == 0);
7130         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0), hnsecs(1)).dayOfGregorianCal == 0);
7131         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).dayOfGregorianCal == 0);
7132 
7133         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_999)).dayOfGregorianCal == -366);
7134         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59), hnsecs(9_999_998)).dayOfGregorianCal == -366);
7135         assert(SysTime(DateTime(-1, 12, 31, 23, 59, 59)).dayOfGregorianCal == -366);
7136         assert(SysTime(DateTime(-1, 12, 31, 0, 0, 0)).dayOfGregorianCal == -366);
7137 
7138         assert(SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == 0);
7139         assert(SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1);
7140         assert(SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -30);
7141         assert(SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -31);
7142 
7143         assert(SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -366);
7144         assert(SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)).dayOfGregorianCal == -367);
7145         assert(SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730);
7146         assert(SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731);
7147         assert(SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1095);
7148         assert(SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1096);
7149         assert(SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1460);
7150         assert(SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1461);
7151         assert(SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1826);
7152         assert(SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -1827);
7153         assert(SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -2191);
7154         assert(SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -3652);
7155 
7156         assert(SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_262);
7157         assert(SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -18_627);
7158         assert(SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -35_794);
7159         assert(SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_160);
7160         assert(SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_524);
7161         assert(SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -36_889);
7162         assert(SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -37_254);
7163         assert(SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -38_715);
7164         assert(SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_413);
7165         assert(SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -73_778);
7166         assert(SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -109_937);
7167         assert(SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -110_302);
7168         assert(SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_097);
7169         assert(SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_462);
7170         assert(SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -146_827);
7171         assert(SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_621);
7172         assert(SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -182_986);
7173         assert(SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -183_351);
7174         assert(SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_607);
7175         assert(SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -365_972);
7176         assert(SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_387);
7177         assert(SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_388);
7178         assert(SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -584_753);
7179         assert(SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -585_118);
7180         assert(SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_325);
7181         assert(SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -694_690);
7182         assert(SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_484);
7183         assert(SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_485);
7184         assert(SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -730_850);
7185         assert(SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)).dayOfGregorianCal == -731_215);
7186 
7187         assert(SysTime(DateTime(-2010, 1, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_502);
7188         assert(SysTime(DateTime(-2010, 1, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_472);
7189         assert(SysTime(DateTime(-2010, 2, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_471);
7190         assert(SysTime(DateTime(-2010, 2, 28, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_444);
7191         assert(SysTime(DateTime(-2010, 3, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_443);
7192         assert(SysTime(DateTime(-2010, 3, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_413);
7193         assert(SysTime(DateTime(-2010, 4, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_412);
7194         assert(SysTime(DateTime(-2010, 4, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_383);
7195         assert(SysTime(DateTime(-2010, 5, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_382);
7196         assert(SysTime(DateTime(-2010, 5, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_352);
7197         assert(SysTime(DateTime(-2010, 6, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_351);
7198         assert(SysTime(DateTime(-2010, 6, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_322);
7199         assert(SysTime(DateTime(-2010, 7, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_321);
7200         assert(SysTime(DateTime(-2010, 7, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_291);
7201         assert(SysTime(DateTime(-2010, 8, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_290);
7202         assert(SysTime(DateTime(-2010, 8, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_260);
7203         assert(SysTime(DateTime(-2010, 9, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_259);
7204         assert(SysTime(DateTime(-2010, 9, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_230);
7205         assert(SysTime(DateTime(-2010, 10, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_229);
7206         assert(SysTime(DateTime(-2010, 10, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_199);
7207         assert(SysTime(DateTime(-2010, 11, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_198);
7208         assert(SysTime(DateTime(-2010, 11, 30, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_169);
7209         assert(SysTime(DateTime(-2010, 12, 1, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_168);
7210         assert(SysTime(DateTime(-2010, 12, 31, 23, 59, 59), msecs(999)).dayOfGregorianCal == -734_138);
7211 
7212         assert(SysTime(DateTime(-2012, 2, 1, 0, 0, 0)).dayOfGregorianCal == -735_202);
7213         assert(SysTime(DateTime(-2012, 2, 28, 0, 0, 0)).dayOfGregorianCal == -735_175);
7214         assert(SysTime(DateTime(-2012, 2, 29, 0, 0, 0)).dayOfGregorianCal == -735_174);
7215         assert(SysTime(DateTime(-2012, 3, 1, 0, 0, 0)).dayOfGregorianCal == -735_173);
7216 
7217         // Start of Hebrew Calendar
7218         assert(SysTime(DateTime(-3760, 9, 7, 0, 0, 0)).dayOfGregorianCal == -1_373_427);
7219 
7220         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7221         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7222         assert(cst.dayOfGregorianCal == 729_941);
7223         assert(ist.dayOfGregorianCal == 729_941);
7224 
7225         static void testScope(scope ref SysTime st) @safe
7226         {
7227             auto result = st.dayOfGregorianCal;
7228         }
7229     }
7230 
7231 
7232     // Test that the logic for the day of the Gregorian Calendar is consistent
7233     // between Date and SysTime.
7234     @safe unittest
7235     {
7236         import core.time;
7237         void test(Date date, SysTime st, size_t line = __LINE__)
7238         {
7239             if (date.dayOfGregorianCal != st.dayOfGregorianCal)
7240             {
7241                 throw new AssertError(format("Date [%s] SysTime [%s]", date.dayOfGregorianCal, st.dayOfGregorianCal),
7242                                       __FILE__, line);
7243             }
7244         }
7245 
7246         // Test A.D.
7247         test(Date(1, 1, 1), SysTime(DateTime(1, 1, 1, 0, 0, 0)));
7248         test(Date(1, 1, 2), SysTime(DateTime(1, 1, 2, 0, 0, 0), hnsecs(500)));
7249         test(Date(1, 2, 1), SysTime(DateTime(1, 2, 1, 0, 0, 0), hnsecs(50_000)));
7250         test(Date(2, 1, 1), SysTime(DateTime(2, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7251         test(Date(3, 1, 1), SysTime(DateTime(3, 1, 1, 12, 13, 14)));
7252         test(Date(4, 1, 1), SysTime(DateTime(4, 1, 1, 12, 13, 14), hnsecs(500)));
7253         test(Date(5, 1, 1), SysTime(DateTime(5, 1, 1, 12, 13, 14), hnsecs(50_000)));
7254         test(Date(50, 1, 1), SysTime(DateTime(50, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7255         test(Date(97, 1, 1), SysTime(DateTime(97, 1, 1, 23, 59, 59)));
7256         test(Date(100, 1, 1), SysTime(DateTime(100, 1, 1, 23, 59, 59), hnsecs(500)));
7257         test(Date(101, 1, 1), SysTime(DateTime(101, 1, 1, 23, 59, 59), hnsecs(50_000)));
7258         test(Date(105, 1, 1), SysTime(DateTime(105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7259         test(Date(200, 1, 1), SysTime(DateTime(200, 1, 1, 0, 0, 0)));
7260         test(Date(201, 1, 1), SysTime(DateTime(201, 1, 1, 0, 0, 0), hnsecs(500)));
7261         test(Date(300, 1, 1), SysTime(DateTime(300, 1, 1, 0, 0, 0), hnsecs(50_000)));
7262         test(Date(301, 1, 1), SysTime(DateTime(301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7263         test(Date(400, 1, 1), SysTime(DateTime(400, 1, 1, 12, 13, 14)));
7264         test(Date(401, 1, 1), SysTime(DateTime(401, 1, 1, 12, 13, 14), hnsecs(500)));
7265         test(Date(500, 1, 1), SysTime(DateTime(500, 1, 1, 12, 13, 14), hnsecs(50_000)));
7266         test(Date(501, 1, 1), SysTime(DateTime(501, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7267         test(Date(1000, 1, 1), SysTime(DateTime(1000, 1, 1, 23, 59, 59)));
7268         test(Date(1001, 1, 1), SysTime(DateTime(1001, 1, 1, 23, 59, 59), hnsecs(500)));
7269         test(Date(1600, 1, 1), SysTime(DateTime(1600, 1, 1, 23, 59, 59), hnsecs(50_000)));
7270         test(Date(1601, 1, 1), SysTime(DateTime(1601, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7271         test(Date(1900, 1, 1), SysTime(DateTime(1900, 1, 1, 0, 0, 0)));
7272         test(Date(1901, 1, 1), SysTime(DateTime(1901, 1, 1, 0, 0, 0), hnsecs(500)));
7273         test(Date(1945, 11, 12), SysTime(DateTime(1945, 11, 12, 0, 0, 0), hnsecs(50_000)));
7274         test(Date(1999, 1, 1), SysTime(DateTime(1999, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7275         test(Date(1999, 7, 6), SysTime(DateTime(1999, 7, 6, 12, 13, 14)));
7276         test(Date(2000, 1, 1), SysTime(DateTime(2000, 1, 1, 12, 13, 14), hnsecs(500)));
7277         test(Date(2001, 1, 1), SysTime(DateTime(2001, 1, 1, 12, 13, 14), hnsecs(50_000)));
7278 
7279         test(Date(2010, 1, 1), SysTime(DateTime(2010, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7280         test(Date(2010, 1, 31), SysTime(DateTime(2010, 1, 31, 23, 0, 0)));
7281         test(Date(2010, 2, 1), SysTime(DateTime(2010, 2, 1, 23, 59, 59), hnsecs(500)));
7282         test(Date(2010, 2, 28), SysTime(DateTime(2010, 2, 28, 23, 59, 59), hnsecs(50_000)));
7283         test(Date(2010, 3, 1), SysTime(DateTime(2010, 3, 1, 23, 59, 59), hnsecs(9_999_999)));
7284         test(Date(2010, 3, 31), SysTime(DateTime(2010, 3, 31, 0, 0, 0)));
7285         test(Date(2010, 4, 1), SysTime(DateTime(2010, 4, 1, 0, 0, 0), hnsecs(500)));
7286         test(Date(2010, 4, 30), SysTime(DateTime(2010, 4, 30, 0, 0, 0), hnsecs(50_000)));
7287         test(Date(2010, 5, 1), SysTime(DateTime(2010, 5, 1, 0, 0, 0), hnsecs(9_999_999)));
7288         test(Date(2010, 5, 31), SysTime(DateTime(2010, 5, 31, 12, 13, 14)));
7289         test(Date(2010, 6, 1), SysTime(DateTime(2010, 6, 1, 12, 13, 14), hnsecs(500)));
7290         test(Date(2010, 6, 30), SysTime(DateTime(2010, 6, 30, 12, 13, 14), hnsecs(50_000)));
7291         test(Date(2010, 7, 1), SysTime(DateTime(2010, 7, 1, 12, 13, 14), hnsecs(9_999_999)));
7292         test(Date(2010, 7, 31), SysTime(DateTime(2010, 7, 31, 23, 59, 59)));
7293         test(Date(2010, 8, 1), SysTime(DateTime(2010, 8, 1, 23, 59, 59), hnsecs(500)));
7294         test(Date(2010, 8, 31), SysTime(DateTime(2010, 8, 31, 23, 59, 59), hnsecs(50_000)));
7295         test(Date(2010, 9, 1), SysTime(DateTime(2010, 9, 1, 23, 59, 59), hnsecs(9_999_999)));
7296         test(Date(2010, 9, 30), SysTime(DateTime(2010, 9, 30, 12, 0, 0)));
7297         test(Date(2010, 10, 1), SysTime(DateTime(2010, 10, 1, 0, 12, 0), hnsecs(500)));
7298         test(Date(2010, 10, 31), SysTime(DateTime(2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
7299         test(Date(2010, 11, 1), SysTime(DateTime(2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
7300         test(Date(2010, 11, 30), SysTime(DateTime(2010, 11, 30, 0, 59, 0)));
7301         test(Date(2010, 12, 1), SysTime(DateTime(2010, 12, 1, 0, 0, 59), hnsecs(500)));
7302         test(Date(2010, 12, 31), SysTime(DateTime(2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
7303 
7304         test(Date(2012, 2, 1), SysTime(DateTime(2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
7305         test(Date(2012, 2, 28), SysTime(DateTime(2012, 2, 28, 23, 59, 0)));
7306         test(Date(2012, 2, 29), SysTime(DateTime(2012, 2, 29, 7, 7, 7), hnsecs(7)));
7307         test(Date(2012, 3, 1), SysTime(DateTime(2012, 3, 1, 7, 7, 7), hnsecs(7)));
7308 
7309         // Test B.C.
7310         test(Date(0, 12, 31), SysTime(DateTime(0, 12, 31, 0, 0, 0)));
7311         test(Date(0, 12, 30), SysTime(DateTime(0, 12, 30, 0, 0, 0), hnsecs(500)));
7312         test(Date(0, 12, 1), SysTime(DateTime(0, 12, 1, 0, 0, 0), hnsecs(50_000)));
7313         test(Date(0, 11, 30), SysTime(DateTime(0, 11, 30, 0, 0, 0), hnsecs(9_999_999)));
7314 
7315         test(Date(-1, 12, 31), SysTime(DateTime(-1, 12, 31, 12, 13, 14)));
7316         test(Date(-1, 12, 30), SysTime(DateTime(-1, 12, 30, 12, 13, 14), hnsecs(500)));
7317         test(Date(-1, 1, 1), SysTime(DateTime(-1, 1, 1, 12, 13, 14), hnsecs(50_000)));
7318         test(Date(-2, 12, 31), SysTime(DateTime(-2, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
7319         test(Date(-2, 1, 1), SysTime(DateTime(-2, 1, 1, 23, 59, 59)));
7320         test(Date(-3, 12, 31), SysTime(DateTime(-3, 12, 31, 23, 59, 59), hnsecs(500)));
7321         test(Date(-3, 1, 1), SysTime(DateTime(-3, 1, 1, 23, 59, 59), hnsecs(50_000)));
7322         test(Date(-4, 12, 31), SysTime(DateTime(-4, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7323         test(Date(-4, 1, 1), SysTime(DateTime(-4, 1, 1, 0, 0, 0)));
7324         test(Date(-5, 12, 31), SysTime(DateTime(-5, 12, 31, 0, 0, 0), hnsecs(500)));
7325         test(Date(-5, 1, 1), SysTime(DateTime(-5, 1, 1, 0, 0, 0), hnsecs(50_000)));
7326         test(Date(-9, 1, 1), SysTime(DateTime(-9, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7327 
7328         test(Date(-49, 1, 1), SysTime(DateTime(-49, 1, 1, 12, 13, 14)));
7329         test(Date(-50, 1, 1), SysTime(DateTime(-50, 1, 1, 12, 13, 14), hnsecs(500)));
7330         test(Date(-97, 1, 1), SysTime(DateTime(-97, 1, 1, 12, 13, 14), hnsecs(50_000)));
7331         test(Date(-99, 12, 31), SysTime(DateTime(-99, 12, 31, 12, 13, 14), hnsecs(9_999_999)));
7332         test(Date(-99, 1, 1), SysTime(DateTime(-99, 1, 1, 23, 59, 59)));
7333         test(Date(-100, 1, 1), SysTime(DateTime(-100, 1, 1, 23, 59, 59), hnsecs(500)));
7334         test(Date(-101, 1, 1), SysTime(DateTime(-101, 1, 1, 23, 59, 59), hnsecs(50_000)));
7335         test(Date(-105, 1, 1), SysTime(DateTime(-105, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7336         test(Date(-200, 1, 1), SysTime(DateTime(-200, 1, 1, 0, 0, 0)));
7337         test(Date(-201, 1, 1), SysTime(DateTime(-201, 1, 1, 0, 0, 0), hnsecs(500)));
7338         test(Date(-300, 1, 1), SysTime(DateTime(-300, 1, 1, 0, 0, 0), hnsecs(50_000)));
7339         test(Date(-301, 1, 1), SysTime(DateTime(-301, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7340         test(Date(-400, 12, 31), SysTime(DateTime(-400, 12, 31, 12, 13, 14)));
7341         test(Date(-400, 1, 1), SysTime(DateTime(-400, 1, 1, 12, 13, 14), hnsecs(500)));
7342         test(Date(-401, 1, 1), SysTime(DateTime(-401, 1, 1, 12, 13, 14), hnsecs(50_000)));
7343         test(Date(-499, 1, 1), SysTime(DateTime(-499, 1, 1, 12, 13, 14), hnsecs(9_999_999)));
7344         test(Date(-500, 1, 1), SysTime(DateTime(-500, 1, 1, 23, 59, 59)));
7345         test(Date(-501, 1, 1), SysTime(DateTime(-501, 1, 1, 23, 59, 59), hnsecs(500)));
7346         test(Date(-1000, 1, 1), SysTime(DateTime(-1000, 1, 1, 23, 59, 59), hnsecs(50_000)));
7347         test(Date(-1001, 1, 1), SysTime(DateTime(-1001, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7348         test(Date(-1599, 1, 1), SysTime(DateTime(-1599, 1, 1, 0, 0, 0)));
7349         test(Date(-1600, 12, 31), SysTime(DateTime(-1600, 12, 31, 0, 0, 0), hnsecs(500)));
7350         test(Date(-1600, 1, 1), SysTime(DateTime(-1600, 1, 1, 0, 0, 0), hnsecs(50_000)));
7351         test(Date(-1601, 1, 1), SysTime(DateTime(-1601, 1, 1, 0, 0, 0), hnsecs(9_999_999)));
7352         test(Date(-1900, 1, 1), SysTime(DateTime(-1900, 1, 1, 12, 13, 14)));
7353         test(Date(-1901, 1, 1), SysTime(DateTime(-1901, 1, 1, 12, 13, 14), hnsecs(500)));
7354         test(Date(-1999, 1, 1), SysTime(DateTime(-1999, 1, 1, 12, 13, 14), hnsecs(50_000)));
7355         test(Date(-1999, 7, 6), SysTime(DateTime(-1999, 7, 6, 12, 13, 14), hnsecs(9_999_999)));
7356         test(Date(-2000, 12, 31), SysTime(DateTime(-2000, 12, 31, 23, 59, 59)));
7357         test(Date(-2000, 1, 1), SysTime(DateTime(-2000, 1, 1, 23, 59, 59), hnsecs(500)));
7358         test(Date(-2001, 1, 1), SysTime(DateTime(-2001, 1, 1, 23, 59, 59), hnsecs(50_000)));
7359 
7360         test(Date(-2010, 1, 1), SysTime(DateTime(-2010, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7361         test(Date(-2010, 1, 31), SysTime(DateTime(-2010, 1, 31, 0, 0, 0)));
7362         test(Date(-2010, 2, 1), SysTime(DateTime(-2010, 2, 1, 0, 0, 0), hnsecs(500)));
7363         test(Date(-2010, 2, 28), SysTime(DateTime(-2010, 2, 28, 0, 0, 0), hnsecs(50_000)));
7364         test(Date(-2010, 3, 1), SysTime(DateTime(-2010, 3, 1, 0, 0, 0), hnsecs(9_999_999)));
7365         test(Date(-2010, 3, 31), SysTime(DateTime(-2010, 3, 31, 12, 13, 14)));
7366         test(Date(-2010, 4, 1), SysTime(DateTime(-2010, 4, 1, 12, 13, 14), hnsecs(500)));
7367         test(Date(-2010, 4, 30), SysTime(DateTime(-2010, 4, 30, 12, 13, 14), hnsecs(50_000)));
7368         test(Date(-2010, 5, 1), SysTime(DateTime(-2010, 5, 1, 12, 13, 14), hnsecs(9_999_999)));
7369         test(Date(-2010, 5, 31), SysTime(DateTime(-2010, 5, 31, 23, 59, 59)));
7370         test(Date(-2010, 6, 1), SysTime(DateTime(-2010, 6, 1, 23, 59, 59), hnsecs(500)));
7371         test(Date(-2010, 6, 30), SysTime(DateTime(-2010, 6, 30, 23, 59, 59), hnsecs(50_000)));
7372         test(Date(-2010, 7, 1), SysTime(DateTime(-2010, 7, 1, 23, 59, 59), hnsecs(9_999_999)));
7373         test(Date(-2010, 7, 31), SysTime(DateTime(-2010, 7, 31, 0, 0, 0)));
7374         test(Date(-2010, 8, 1), SysTime(DateTime(-2010, 8, 1, 0, 0, 0), hnsecs(500)));
7375         test(Date(-2010, 8, 31), SysTime(DateTime(-2010, 8, 31, 0, 0, 0), hnsecs(50_000)));
7376         test(Date(-2010, 9, 1), SysTime(DateTime(-2010, 9, 1, 0, 0, 0), hnsecs(9_999_999)));
7377         test(Date(-2010, 9, 30), SysTime(DateTime(-2010, 9, 30, 12, 0, 0)));
7378         test(Date(-2010, 10, 1), SysTime(DateTime(-2010, 10, 1, 0, 12, 0), hnsecs(500)));
7379         test(Date(-2010, 10, 31), SysTime(DateTime(-2010, 10, 31, 0, 0, 12), hnsecs(50_000)));
7380         test(Date(-2010, 11, 1), SysTime(DateTime(-2010, 11, 1, 23, 0, 0), hnsecs(9_999_999)));
7381         test(Date(-2010, 11, 30), SysTime(DateTime(-2010, 11, 30, 0, 59, 0)));
7382         test(Date(-2010, 12, 1), SysTime(DateTime(-2010, 12, 1, 0, 0, 59), hnsecs(500)));
7383         test(Date(-2010, 12, 31), SysTime(DateTime(-2010, 12, 31, 0, 59, 59), hnsecs(50_000)));
7384 
7385         test(Date(-2012, 2, 1), SysTime(DateTime(-2012, 2, 1, 23, 0, 59), hnsecs(9_999_999)));
7386         test(Date(-2012, 2, 28), SysTime(DateTime(-2012, 2, 28, 23, 59, 0)));
7387         test(Date(-2012, 2, 29), SysTime(DateTime(-2012, 2, 29, 7, 7, 7), hnsecs(7)));
7388         test(Date(-2012, 3, 1), SysTime(DateTime(-2012, 3, 1, 7, 7, 7), hnsecs(7)));
7389 
7390         test(Date(-3760, 9, 7), SysTime(DateTime(-3760, 9, 7, 0, 0, 0)));
7391     }
7392 
7393 
7394     /++
7395         The Xth day of the Gregorian Calendar that this $(LREF SysTime) is on.
7396         Setting this property does not affect the time portion of $(LREF SysTime).
7397 
7398         Params:
7399             days = The day of the Gregorian Calendar to set this $(LREF SysTime)
7400                    to.
7401      +/
7402     @property void dayOfGregorianCal(int days) @safe nothrow scope
7403     {
7404         auto hnsecs = adjTime;
7405         hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
7406 
7407         if (hnsecs < 0)
7408             hnsecs += convert!("hours", "hnsecs")(24);
7409 
7410         if (--days < 0)
7411         {
7412             hnsecs -= convert!("hours", "hnsecs")(24);
7413             ++days;
7414         }
7415 
7416         immutable newDaysHNSecs = convert!("days", "hnsecs")(days);
7417 
7418         adjTime = newDaysHNSecs + hnsecs;
7419     }
7420 
7421     ///
7422     @safe unittest
7423     {
7424         import core.time;
7425         import std.datetime.date : DateTime;
7426 
7427         auto st = SysTime(DateTime(0, 1, 1, 12, 0, 0));
7428         st.dayOfGregorianCal = 1;
7429         assert(st == SysTime(DateTime(1, 1, 1, 12, 0, 0)));
7430 
7431         st.dayOfGregorianCal = 365;
7432         assert(st == SysTime(DateTime(1, 12, 31, 12, 0, 0)));
7433 
7434         st.dayOfGregorianCal = 366;
7435         assert(st == SysTime(DateTime(2, 1, 1, 12, 0, 0)));
7436 
7437         st.dayOfGregorianCal = 0;
7438         assert(st == SysTime(DateTime(0, 12, 31, 12, 0, 0)));
7439 
7440         st.dayOfGregorianCal = -365;
7441         assert(st == SysTime(DateTime(-0, 1, 1, 12, 0, 0)));
7442 
7443         st.dayOfGregorianCal = -366;
7444         assert(st == SysTime(DateTime(-1, 12, 31, 12, 0, 0)));
7445 
7446         st.dayOfGregorianCal = 730_120;
7447         assert(st == SysTime(DateTime(2000, 1, 1, 12, 0, 0)));
7448 
7449         st.dayOfGregorianCal = 734_137;
7450         assert(st == SysTime(DateTime(2010, 12, 31, 12, 0, 0)));
7451     }
7452 
7453     @safe unittest
7454     {
7455         import core.time;
7456         void testST(SysTime orig, int day, SysTime expected, size_t line = __LINE__) @safe
7457         {
7458             orig.dayOfGregorianCal = day;
7459             if (orig != expected)
7460                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", orig, expected), __FILE__, line);
7461         }
7462 
7463         // Test A.D.
7464         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
7465         testST(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
7466         testST(SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 1,
7467                SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7468 
7469         // Test B.C.
7470         testST(SysTime(DateTime(0, 1, 1, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
7471         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(9_999_999)), 0,
7472                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7473         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59), hnsecs(1)), 0,
7474                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
7475         testST(SysTime(DateTime(0, 1, 1, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
7476 
7477         // Test Both.
7478         testST(SysTime(DateTime(-512, 7, 20, 0, 0, 0)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0)));
7479         testST(SysTime(DateTime(-513, 6, 6, 0, 0, 0), hnsecs(1)), 1, SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1)));
7480         testST(SysTime(DateTime(-511, 5, 7, 23, 59, 59), hnsecs(9_999_999)), 1,
7481                SysTime(DateTime(1, 1, 1, 23, 59, 59), hnsecs(9_999_999)));
7482 
7483         testST(SysTime(DateTime(1607, 4, 8, 0, 0, 0)), 0, SysTime(DateTime(0, 12, 31, 0, 0, 0)));
7484         testST(SysTime(DateTime(1500, 3, 9, 23, 59, 59), hnsecs(9_999_999)), 0,
7485                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7486         testST(SysTime(DateTime(999, 2, 10, 23, 59, 59), hnsecs(1)), 0,
7487                SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1)));
7488         testST(SysTime(DateTime(2007, 12, 11, 23, 59, 59)), 0, SysTime(DateTime(0, 12, 31, 23, 59, 59)));
7489 
7490 
7491         auto st = SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212));
7492 
7493         void testST2(int day, SysTime expected, size_t line = __LINE__) @safe
7494         {
7495             st.dayOfGregorianCal = day;
7496             if (st != expected)
7497                 throw new AssertError(format("Failed. actual [%s] != expected [%s]", st, expected), __FILE__, line);
7498         }
7499 
7500         // Test A.D.
7501         testST2(1, SysTime(DateTime(1, 1, 1, 12, 2, 9), msecs(212)));
7502         testST2(2, SysTime(DateTime(1, 1, 2, 12, 2, 9), msecs(212)));
7503         testST2(32, SysTime(DateTime(1, 2, 1, 12, 2, 9), msecs(212)));
7504         testST2(366, SysTime(DateTime(2, 1, 1, 12, 2, 9), msecs(212)));
7505         testST2(731, SysTime(DateTime(3, 1, 1, 12, 2, 9), msecs(212)));
7506         testST2(1096, SysTime(DateTime(4, 1, 1, 12, 2, 9), msecs(212)));
7507         testST2(1462, SysTime(DateTime(5, 1, 1, 12, 2, 9), msecs(212)));
7508         testST2(17_898, SysTime(DateTime(50, 1, 1, 12, 2, 9), msecs(212)));
7509         testST2(35_065, SysTime(DateTime(97, 1, 1, 12, 2, 9), msecs(212)));
7510         testST2(36_160, SysTime(DateTime(100, 1, 1, 12, 2, 9), msecs(212)));
7511         testST2(36_525, SysTime(DateTime(101, 1, 1, 12, 2, 9), msecs(212)));
7512         testST2(37_986, SysTime(DateTime(105, 1, 1, 12, 2, 9), msecs(212)));
7513         testST2(72_684, SysTime(DateTime(200, 1, 1, 12, 2, 9), msecs(212)));
7514         testST2(73_049, SysTime(DateTime(201, 1, 1, 12, 2, 9), msecs(212)));
7515         testST2(109_208, SysTime(DateTime(300, 1, 1, 12, 2, 9), msecs(212)));
7516         testST2(109_573, SysTime(DateTime(301, 1, 1, 12, 2, 9), msecs(212)));
7517         testST2(145_732, SysTime(DateTime(400, 1, 1, 12, 2, 9), msecs(212)));
7518         testST2(146_098, SysTime(DateTime(401, 1, 1, 12, 2, 9), msecs(212)));
7519         testST2(182_257, SysTime(DateTime(500, 1, 1, 12, 2, 9), msecs(212)));
7520         testST2(182_622, SysTime(DateTime(501, 1, 1, 12, 2, 9), msecs(212)));
7521         testST2(364_878, SysTime(DateTime(1000, 1, 1, 12, 2, 9), msecs(212)));
7522         testST2(365_243, SysTime(DateTime(1001, 1, 1, 12, 2, 9), msecs(212)));
7523         testST2(584_023, SysTime(DateTime(1600, 1, 1, 12, 2, 9), msecs(212)));
7524         testST2(584_389, SysTime(DateTime(1601, 1, 1, 12, 2, 9), msecs(212)));
7525         testST2(693_596, SysTime(DateTime(1900, 1, 1, 12, 2, 9), msecs(212)));
7526         testST2(693_961, SysTime(DateTime(1901, 1, 1, 12, 2, 9), msecs(212)));
7527         testST2(729_755, SysTime(DateTime(1999, 1, 1, 12, 2, 9), msecs(212)));
7528         testST2(730_120, SysTime(DateTime(2000, 1, 1, 12, 2, 9), msecs(212)));
7529         testST2(730_486, SysTime(DateTime(2001, 1, 1, 12, 2, 9), msecs(212)));
7530 
7531         testST2(733_773, SysTime(DateTime(2010, 1, 1, 12, 2, 9), msecs(212)));
7532         testST2(733_803, SysTime(DateTime(2010, 1, 31, 12, 2, 9), msecs(212)));
7533         testST2(733_804, SysTime(DateTime(2010, 2, 1, 12, 2, 9), msecs(212)));
7534         testST2(733_831, SysTime(DateTime(2010, 2, 28, 12, 2, 9), msecs(212)));
7535         testST2(733_832, SysTime(DateTime(2010, 3, 1, 12, 2, 9), msecs(212)));
7536         testST2(733_862, SysTime(DateTime(2010, 3, 31, 12, 2, 9), msecs(212)));
7537         testST2(733_863, SysTime(DateTime(2010, 4, 1, 12, 2, 9), msecs(212)));
7538         testST2(733_892, SysTime(DateTime(2010, 4, 30, 12, 2, 9), msecs(212)));
7539         testST2(733_893, SysTime(DateTime(2010, 5, 1, 12, 2, 9), msecs(212)));
7540         testST2(733_923, SysTime(DateTime(2010, 5, 31, 12, 2, 9), msecs(212)));
7541         testST2(733_924, SysTime(DateTime(2010, 6, 1, 12, 2, 9), msecs(212)));
7542         testST2(733_953, SysTime(DateTime(2010, 6, 30, 12, 2, 9), msecs(212)));
7543         testST2(733_954, SysTime(DateTime(2010, 7, 1, 12, 2, 9), msecs(212)));
7544         testST2(733_984, SysTime(DateTime(2010, 7, 31, 12, 2, 9), msecs(212)));
7545         testST2(733_985, SysTime(DateTime(2010, 8, 1, 12, 2, 9), msecs(212)));
7546         testST2(734_015, SysTime(DateTime(2010, 8, 31, 12, 2, 9), msecs(212)));
7547         testST2(734_016, SysTime(DateTime(2010, 9, 1, 12, 2, 9), msecs(212)));
7548         testST2(734_045, SysTime(DateTime(2010, 9, 30, 12, 2, 9), msecs(212)));
7549         testST2(734_046, SysTime(DateTime(2010, 10, 1, 12, 2, 9), msecs(212)));
7550         testST2(734_076, SysTime(DateTime(2010, 10, 31, 12, 2, 9), msecs(212)));
7551         testST2(734_077, SysTime(DateTime(2010, 11, 1, 12, 2, 9), msecs(212)));
7552         testST2(734_106, SysTime(DateTime(2010, 11, 30, 12, 2, 9), msecs(212)));
7553         testST2(734_107, SysTime(DateTime(2010, 12, 1, 12, 2, 9), msecs(212)));
7554         testST2(734_137, SysTime(DateTime(2010, 12, 31, 12, 2, 9), msecs(212)));
7555 
7556         testST2(734_534, SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
7557         testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
7558         testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
7559         testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
7560 
7561         testST2(734_534,  SysTime(DateTime(2012, 2, 1, 12, 2, 9), msecs(212)));
7562 
7563         testST2(734_561, SysTime(DateTime(2012, 2, 28, 12, 2, 9), msecs(212)));
7564         testST2(734_562, SysTime(DateTime(2012, 2, 29, 12, 2, 9), msecs(212)));
7565         testST2(734_563, SysTime(DateTime(2012, 3, 1, 12, 2, 9), msecs(212)));
7566 
7567         // Test B.C.
7568         testST2(0, SysTime(DateTime(0, 12, 31, 12, 2, 9), msecs(212)));
7569         testST2(-1, SysTime(DateTime(0, 12, 30, 12, 2, 9), msecs(212)));
7570         testST2(-30, SysTime(DateTime(0, 12, 1, 12, 2, 9), msecs(212)));
7571         testST2(-31, SysTime(DateTime(0, 11, 30, 12, 2, 9), msecs(212)));
7572 
7573         testST2(-366, SysTime(DateTime(-1, 12, 31, 12, 2, 9), msecs(212)));
7574         testST2(-367, SysTime(DateTime(-1, 12, 30, 12, 2, 9), msecs(212)));
7575         testST2(-730, SysTime(DateTime(-1, 1, 1, 12, 2, 9), msecs(212)));
7576         testST2(-731, SysTime(DateTime(-2, 12, 31, 12, 2, 9), msecs(212)));
7577         testST2(-1095, SysTime(DateTime(-2, 1, 1, 12, 2, 9), msecs(212)));
7578         testST2(-1096, SysTime(DateTime(-3, 12, 31, 12, 2, 9), msecs(212)));
7579         testST2(-1460, SysTime(DateTime(-3, 1, 1, 12, 2, 9), msecs(212)));
7580         testST2(-1461, SysTime(DateTime(-4, 12, 31, 12, 2, 9), msecs(212)));
7581         testST2(-1826, SysTime(DateTime(-4, 1, 1, 12, 2, 9), msecs(212)));
7582         testST2(-1827, SysTime(DateTime(-5, 12, 31, 12, 2, 9), msecs(212)));
7583         testST2(-2191, SysTime(DateTime(-5, 1, 1, 12, 2, 9), msecs(212)));
7584         testST2(-3652, SysTime(DateTime(-9, 1, 1, 12, 2, 9), msecs(212)));
7585 
7586         testST2(-18_262, SysTime(DateTime(-49, 1, 1, 12, 2, 9), msecs(212)));
7587         testST2(-18_627, SysTime(DateTime(-50, 1, 1, 12, 2, 9), msecs(212)));
7588         testST2(-35_794, SysTime(DateTime(-97, 1, 1, 12, 2, 9), msecs(212)));
7589         testST2(-36_160, SysTime(DateTime(-99, 12, 31, 12, 2, 9), msecs(212)));
7590         testST2(-36_524, SysTime(DateTime(-99, 1, 1, 12, 2, 9), msecs(212)));
7591         testST2(-36_889, SysTime(DateTime(-100, 1, 1, 12, 2, 9), msecs(212)));
7592         testST2(-37_254, SysTime(DateTime(-101, 1, 1, 12, 2, 9), msecs(212)));
7593         testST2(-38_715, SysTime(DateTime(-105, 1, 1, 12, 2, 9), msecs(212)));
7594         testST2(-73_413, SysTime(DateTime(-200, 1, 1, 12, 2, 9), msecs(212)));
7595         testST2(-73_778, SysTime(DateTime(-201, 1, 1, 12, 2, 9), msecs(212)));
7596         testST2(-109_937, SysTime(DateTime(-300, 1, 1, 12, 2, 9), msecs(212)));
7597         testST2(-110_302, SysTime(DateTime(-301, 1, 1, 12, 2, 9), msecs(212)));
7598         testST2(-146_097, SysTime(DateTime(-400, 12, 31, 12, 2, 9), msecs(212)));
7599         testST2(-146_462, SysTime(DateTime(-400, 1, 1, 12, 2, 9), msecs(212)));
7600         testST2(-146_827, SysTime(DateTime(-401, 1, 1, 12, 2, 9), msecs(212)));
7601         testST2(-182_621, SysTime(DateTime(-499, 1, 1, 12, 2, 9), msecs(212)));
7602         testST2(-182_986, SysTime(DateTime(-500, 1, 1, 12, 2, 9), msecs(212)));
7603         testST2(-183_351, SysTime(DateTime(-501, 1, 1, 12, 2, 9), msecs(212)));
7604         testST2(-365_607, SysTime(DateTime(-1000, 1, 1, 12, 2, 9), msecs(212)));
7605         testST2(-365_972, SysTime(DateTime(-1001, 1, 1, 12, 2, 9), msecs(212)));
7606         testST2(-584_387, SysTime(DateTime(-1599, 1, 1, 12, 2, 9), msecs(212)));
7607         testST2(-584_388, SysTime(DateTime(-1600, 12, 31, 12, 2, 9), msecs(212)));
7608         testST2(-584_753, SysTime(DateTime(-1600, 1, 1, 12, 2, 9), msecs(212)));
7609         testST2(-585_118, SysTime(DateTime(-1601, 1, 1, 12, 2, 9), msecs(212)));
7610         testST2(-694_325, SysTime(DateTime(-1900, 1, 1, 12, 2, 9), msecs(212)));
7611         testST2(-694_690, SysTime(DateTime(-1901, 1, 1, 12, 2, 9), msecs(212)));
7612         testST2(-730_484, SysTime(DateTime(-1999, 1, 1, 12, 2, 9), msecs(212)));
7613         testST2(-730_485, SysTime(DateTime(-2000, 12, 31, 12, 2, 9), msecs(212)));
7614         testST2(-730_850, SysTime(DateTime(-2000, 1, 1, 12, 2, 9), msecs(212)));
7615         testST2(-731_215, SysTime(DateTime(-2001, 1, 1, 12, 2, 9), msecs(212)));
7616 
7617         testST2(-734_502, SysTime(DateTime(-2010, 1, 1, 12, 2, 9), msecs(212)));
7618         testST2(-734_472, SysTime(DateTime(-2010, 1, 31, 12, 2, 9), msecs(212)));
7619         testST2(-734_471, SysTime(DateTime(-2010, 2, 1, 12, 2, 9), msecs(212)));
7620         testST2(-734_444, SysTime(DateTime(-2010, 2, 28, 12, 2, 9), msecs(212)));
7621         testST2(-734_443, SysTime(DateTime(-2010, 3, 1, 12, 2, 9), msecs(212)));
7622         testST2(-734_413, SysTime(DateTime(-2010, 3, 31, 12, 2, 9), msecs(212)));
7623         testST2(-734_412, SysTime(DateTime(-2010, 4, 1, 12, 2, 9), msecs(212)));
7624         testST2(-734_383, SysTime(DateTime(-2010, 4, 30, 12, 2, 9), msecs(212)));
7625         testST2(-734_382, SysTime(DateTime(-2010, 5, 1, 12, 2, 9), msecs(212)));
7626         testST2(-734_352, SysTime(DateTime(-2010, 5, 31, 12, 2, 9), msecs(212)));
7627         testST2(-734_351, SysTime(DateTime(-2010, 6, 1, 12, 2, 9), msecs(212)));
7628         testST2(-734_322, SysTime(DateTime(-2010, 6, 30, 12, 2, 9), msecs(212)));
7629         testST2(-734_321, SysTime(DateTime(-2010, 7, 1, 12, 2, 9), msecs(212)));
7630         testST2(-734_291, SysTime(DateTime(-2010, 7, 31, 12, 2, 9), msecs(212)));
7631         testST2(-734_290, SysTime(DateTime(-2010, 8, 1, 12, 2, 9), msecs(212)));
7632         testST2(-734_260, SysTime(DateTime(-2010, 8, 31, 12, 2, 9), msecs(212)));
7633         testST2(-734_259, SysTime(DateTime(-2010, 9, 1, 12, 2, 9), msecs(212)));
7634         testST2(-734_230, SysTime(DateTime(-2010, 9, 30, 12, 2, 9), msecs(212)));
7635         testST2(-734_229, SysTime(DateTime(-2010, 10, 1, 12, 2, 9), msecs(212)));
7636         testST2(-734_199, SysTime(DateTime(-2010, 10, 31, 12, 2, 9), msecs(212)));
7637         testST2(-734_198, SysTime(DateTime(-2010, 11, 1, 12, 2, 9), msecs(212)));
7638         testST2(-734_169, SysTime(DateTime(-2010, 11, 30, 12, 2, 9), msecs(212)));
7639         testST2(-734_168, SysTime(DateTime(-2010, 12, 1, 12, 2, 9), msecs(212)));
7640         testST2(-734_138, SysTime(DateTime(-2010, 12, 31, 12, 2, 9), msecs(212)));
7641 
7642         testST2(-735_202, SysTime(DateTime(-2012, 2, 1, 12, 2, 9), msecs(212)));
7643         testST2(-735_175, SysTime(DateTime(-2012, 2, 28, 12, 2, 9), msecs(212)));
7644         testST2(-735_174, SysTime(DateTime(-2012, 2, 29, 12, 2, 9), msecs(212)));
7645         testST2(-735_173, SysTime(DateTime(-2012, 3, 1, 12, 2, 9), msecs(212)));
7646 
7647         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7648         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7649         static assert(!__traits(compiles, cst.dayOfGregorianCal = 7));
7650         static assert(!__traits(compiles, ist.dayOfGregorianCal = 7));
7651 
7652         static void testScope(scope ref SysTime st) @safe
7653         {
7654             st.dayOfGregorianCal = 42;
7655         }
7656     }
7657 
7658 
7659     /++
7660         The ISO 8601 week of the year that this $(LREF SysTime) is in.
7661 
7662         See_Also:
7663             $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date).
7664       +/
7665     @property ubyte isoWeek() @safe const nothrow scope
7666     {
7667         return (cast(Date) this).isoWeek;
7668     }
7669 
7670     ///
7671     @safe unittest
7672     {
7673         import core.time;
7674         import std.datetime.date : Date;
7675 
7676         auto st = SysTime(Date(1999, 7, 6));
7677         const cst = SysTime(Date(2010, 5, 1));
7678         immutable ist = SysTime(Date(2015, 10, 10));
7679 
7680         assert(st.isoWeek == 27);
7681         assert(cst.isoWeek == 17);
7682         assert(ist.isoWeek == 41);
7683     }
7684 
7685     @safe unittest
7686     {
7687         static void testScope(scope ref SysTime st) @safe
7688         {
7689             auto result = st.isoWeek;
7690         }
7691     }
7692 
7693 
7694     /++
7695         $(LREF SysTime) for the last day in the month that this Date is in.
7696         The time portion of endOfMonth is always 23:59:59.9999999.
7697       +/
7698     @property SysTime endOfMonth() @safe const nothrow return scope
7699     {
7700         immutable hnsecs = adjTime;
7701         immutable days = getUnitsFromHNSecs!"days"(hnsecs);
7702 
7703         auto date = Date(cast(int) days + 1).endOfMonth;
7704         auto newDays = date.dayOfGregorianCal - 1;
7705         long theTimeHNSecs;
7706 
7707         if (newDays < 0)
7708         {
7709             theTimeHNSecs = -1;
7710             ++newDays;
7711         }
7712         else
7713             theTimeHNSecs = convert!("days", "hnsecs")(1) - 1;
7714 
7715         immutable newDaysHNSecs = convert!("days", "hnsecs")(newDays);
7716 
7717         auto retval = SysTime(this._stdTime, this._timezone);
7718         retval.adjTime = newDaysHNSecs + theTimeHNSecs;
7719 
7720         return retval;
7721     }
7722 
7723     ///
7724     @safe unittest
7725     {
7726         import core.time : msecs, usecs, hnsecs;
7727         import std.datetime.date : DateTime;
7728 
7729         assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonth ==
7730                SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7731 
7732         assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0), msecs(24)).endOfMonth ==
7733                SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7734 
7735         assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27), usecs(5203)).endOfMonth ==
7736                SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7737 
7738         assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9), hnsecs(12345)).endOfMonth ==
7739                SysTime(DateTime(2000, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7740     }
7741 
7742     @safe unittest
7743     {
7744         import core.time;
7745         // Test A.D.
7746         assert(SysTime(Date(1999, 1, 1)).endOfMonth == SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7747         assert(SysTime(Date(1999, 2, 1)).endOfMonth == SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7748         assert(SysTime(Date(2000, 2, 1)).endOfMonth == SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7749         assert(SysTime(Date(1999, 3, 1)).endOfMonth == SysTime(DateTime(1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
7750         assert(SysTime(Date(1999, 4, 1)).endOfMonth == SysTime(DateTime(1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
7751         assert(SysTime(Date(1999, 5, 1)).endOfMonth == SysTime(DateTime(1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
7752         assert(SysTime(Date(1999, 6, 1)).endOfMonth == SysTime(DateTime(1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7753         assert(SysTime(Date(1999, 7, 1)).endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7754         assert(SysTime(Date(1999, 8, 1)).endOfMonth == SysTime(DateTime(1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
7755         assert(SysTime(Date(1999, 9, 1)).endOfMonth == SysTime(DateTime(1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
7756         assert(SysTime(Date(1999, 10, 1)).endOfMonth == SysTime(DateTime(1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
7757         assert(SysTime(Date(1999, 11, 1)).endOfMonth == SysTime(DateTime(1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
7758         assert(SysTime(Date(1999, 12, 1)).endOfMonth == SysTime(DateTime(1999, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7759 
7760         // Test B.C.
7761         assert(SysTime(Date(-1999, 1, 1)).endOfMonth == SysTime(DateTime(-1999, 1, 31, 23, 59, 59), hnsecs(9_999_999)));
7762         assert(SysTime(Date(-1999, 2, 1)).endOfMonth == SysTime(DateTime(-1999, 2, 28, 23, 59, 59), hnsecs(9_999_999)));
7763         assert(SysTime(Date(-2000, 2, 1)).endOfMonth == SysTime(DateTime(-2000, 2, 29, 23, 59, 59), hnsecs(9_999_999)));
7764         assert(SysTime(Date(-1999, 3, 1)).endOfMonth == SysTime(DateTime(-1999, 3, 31, 23, 59, 59), hnsecs(9_999_999)));
7765         assert(SysTime(Date(-1999, 4, 1)).endOfMonth == SysTime(DateTime(-1999, 4, 30, 23, 59, 59), hnsecs(9_999_999)));
7766         assert(SysTime(Date(-1999, 5, 1)).endOfMonth == SysTime(DateTime(-1999, 5, 31, 23, 59, 59), hnsecs(9_999_999)));
7767         assert(SysTime(Date(-1999, 6, 1)).endOfMonth == SysTime(DateTime(-1999, 6, 30, 23, 59, 59), hnsecs(9_999_999)));
7768         assert(SysTime(Date(-1999, 7, 1)).endOfMonth == SysTime(DateTime(-1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7769         assert(SysTime(Date(-1999, 8, 1)).endOfMonth == SysTime(DateTime(-1999, 8, 31, 23, 59, 59), hnsecs(9_999_999)));
7770         assert(SysTime(Date(-1999, 9, 1)).endOfMonth == SysTime(DateTime(-1999, 9, 30, 23, 59, 59), hnsecs(9_999_999)));
7771         assert(SysTime(Date(-1999, 10, 1)).endOfMonth ==
7772                SysTime(DateTime(-1999, 10, 31, 23, 59, 59), hnsecs(9_999_999)));
7773         assert(SysTime(Date(-1999, 11, 1)).endOfMonth ==
7774                SysTime(DateTime(-1999, 11, 30, 23, 59, 59), hnsecs(9_999_999)));
7775         assert(SysTime(Date(-1999, 12, 1)).endOfMonth ==
7776                SysTime(DateTime(-1999, 12, 31, 23, 59, 59), hnsecs(9_999_999)));
7777 
7778         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7779         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7780         assert(cst.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7781         assert(ist.endOfMonth == SysTime(DateTime(1999, 7, 31, 23, 59, 59), hnsecs(9_999_999)));
7782 
7783         static void testScope(scope ref SysTime st) @safe
7784         {
7785             auto result = st.endOfMonth;
7786         }
7787     }
7788 
7789 
7790     /++
7791         The last day in the month that this $(LREF SysTime) is in.
7792       +/
7793     @property ubyte daysInMonth() @safe const nothrow scope
7794     {
7795         return Date(dayOfGregorianCal).daysInMonth;
7796     }
7797 
7798     ///
7799     @safe unittest
7800     {
7801         import core.time;
7802         import std.datetime.date : DateTime;
7803 
7804         assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).daysInMonth == 31);
7805         assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0)).daysInMonth == 28);
7806         assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27)).daysInMonth == 29);
7807         assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9)).daysInMonth == 30);
7808     }
7809 
7810     @safe unittest
7811     {
7812         import core.time;
7813         // Test A.D.
7814         assert(SysTime(DateTime(1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
7815         assert(SysTime(DateTime(1999, 2, 1, 17, 13, 12)).daysInMonth == 28);
7816         assert(SysTime(DateTime(2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
7817         assert(SysTime(DateTime(1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
7818         assert(SysTime(DateTime(1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
7819         assert(SysTime(DateTime(1999, 5, 1, 15, 13, 12)).daysInMonth == 31);
7820         assert(SysTime(DateTime(1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
7821         assert(SysTime(DateTime(1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
7822         assert(SysTime(DateTime(1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
7823         assert(SysTime(DateTime(1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
7824         assert(SysTime(DateTime(1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
7825         assert(SysTime(DateTime(1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
7826         assert(SysTime(DateTime(1999, 12, 1, 12, 52, 13)).daysInMonth == 31);
7827 
7828         // Test B.C.
7829         assert(SysTime(DateTime(-1999, 1, 1, 12, 1, 13)).daysInMonth == 31);
7830         assert(SysTime(DateTime(-1999, 2, 1, 7, 13, 12)).daysInMonth == 28);
7831         assert(SysTime(DateTime(-2000, 2, 1, 13, 2, 12)).daysInMonth == 29);
7832         assert(SysTime(DateTime(-1999, 3, 1, 12, 13, 12)).daysInMonth == 31);
7833         assert(SysTime(DateTime(-1999, 4, 1, 12, 6, 13)).daysInMonth == 30);
7834         assert(SysTime(DateTime(-1999, 5, 1, 5, 13, 12)).daysInMonth == 31);
7835         assert(SysTime(DateTime(-1999, 6, 1, 13, 7, 12)).daysInMonth == 30);
7836         assert(SysTime(DateTime(-1999, 7, 1, 12, 13, 17)).daysInMonth == 31);
7837         assert(SysTime(DateTime(-1999, 8, 1, 12, 3, 13)).daysInMonth == 31);
7838         assert(SysTime(DateTime(-1999, 9, 1, 12, 13, 12)).daysInMonth == 30);
7839         assert(SysTime(DateTime(-1999, 10, 1, 13, 19, 12)).daysInMonth == 31);
7840         assert(SysTime(DateTime(-1999, 11, 1, 12, 13, 17)).daysInMonth == 30);
7841         assert(SysTime(DateTime(-1999, 12, 1, 12, 52, 13)).daysInMonth == 31);
7842 
7843         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7844         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7845         assert(cst.daysInMonth == 31);
7846         assert(ist.daysInMonth == 31);
7847 
7848         static void testScope(scope ref SysTime st) @safe
7849         {
7850             auto result = st.daysInMonth;
7851         }
7852     }
7853 
7854 
7855     /++
7856         Whether the current year is a date in A.D.
7857       +/
7858     @property bool isAD() @safe const nothrow scope
7859     {
7860         return adjTime >= 0;
7861     }
7862 
7863     ///
7864     @safe unittest
7865     {
7866         import core.time;
7867         import std.datetime.date : DateTime;
7868 
7869         assert(SysTime(DateTime(1, 1, 1, 12, 7, 0)).isAD);
7870         assert(SysTime(DateTime(2010, 12, 31, 0, 0, 0)).isAD);
7871         assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
7872         assert(!SysTime(DateTime(-2010, 1, 1, 2, 2, 2)).isAD);
7873     }
7874 
7875     @safe unittest
7876     {
7877         import core.time;
7878         assert(SysTime(DateTime(2010, 7, 4, 12, 0, 9)).isAD);
7879         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).isAD);
7880         assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD);
7881         assert(!SysTime(DateTime(0, 1, 1, 23, 59, 59)).isAD);
7882         assert(!SysTime(DateTime(-1, 1, 1, 23 ,59 ,59)).isAD);
7883         assert(!SysTime(DateTime(-2010, 7, 4, 12, 2, 2)).isAD);
7884 
7885         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7886         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7887         assert(cst.isAD);
7888         assert(ist.isAD);
7889 
7890         static void testScope(scope ref SysTime st) @safe
7891         {
7892             auto result = st.isAD;
7893         }
7894     }
7895 
7896 
7897     /++
7898         The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day)
7899         for this $(LREF SysTime) at the given time. For example,
7900         prior to noon, 1996-03-31 would be the Julian day number 2_450_173, so
7901         this function returns 2_450_173, while from noon onward, the Julian
7902         day number would be 2_450_174, so this function returns 2_450_174.
7903       +/
7904     @property long julianDay() @safe const nothrow scope
7905     {
7906         immutable jd = dayOfGregorianCal + 1_721_425;
7907         return hour < 12 ? jd - 1 : jd;
7908     }
7909 
7910     @safe unittest
7911     {
7912         import core.time;
7913         assert(SysTime(DateTime(-4713, 11, 24, 0, 0, 0)).julianDay == -1);
7914         assert(SysTime(DateTime(-4713, 11, 24, 12, 0, 0)).julianDay == 0);
7915 
7916         assert(SysTime(DateTime(0, 12, 31, 0, 0, 0)).julianDay == 1_721_424);
7917         assert(SysTime(DateTime(0, 12, 31, 12, 0, 0)).julianDay == 1_721_425);
7918 
7919         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).julianDay == 1_721_425);
7920         assert(SysTime(DateTime(1, 1, 1, 12, 0, 0)).julianDay == 1_721_426);
7921 
7922         assert(SysTime(DateTime(1582, 10, 15, 0, 0, 0)).julianDay == 2_299_160);
7923         assert(SysTime(DateTime(1582, 10, 15, 12, 0, 0)).julianDay == 2_299_161);
7924 
7925         assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).julianDay == 2_400_000);
7926         assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).julianDay == 2_400_001);
7927 
7928         assert(SysTime(DateTime(1982, 1, 4, 0, 0, 0)).julianDay == 2_444_973);
7929         assert(SysTime(DateTime(1982, 1, 4, 12, 0, 0)).julianDay == 2_444_974);
7930 
7931         assert(SysTime(DateTime(1996, 3, 31, 0, 0, 0)).julianDay == 2_450_173);
7932         assert(SysTime(DateTime(1996, 3, 31, 12, 0, 0)).julianDay == 2_450_174);
7933 
7934         assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).julianDay == 2_455_432);
7935         assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).julianDay == 2_455_433);
7936 
7937         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7938         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7939         assert(cst.julianDay == 2_451_366);
7940         assert(ist.julianDay == 2_451_366);
7941 
7942         static void testScope(scope ref SysTime st) @safe
7943         {
7944             auto result = st.julianDay;
7945         }
7946     }
7947 
7948 
7949     /++
7950         The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for
7951         any time on this date (since, the modified Julian day changes at
7952         midnight).
7953       +/
7954     @property long modJulianDay() @safe const nothrow scope
7955     {
7956         return dayOfGregorianCal + 1_721_425 - 2_400_001;
7957     }
7958 
7959     @safe unittest
7960     {
7961         import core.time;
7962         assert(SysTime(DateTime(1858, 11, 17, 0, 0, 0)).modJulianDay == 0);
7963         assert(SysTime(DateTime(1858, 11, 17, 12, 0, 0)).modJulianDay == 0);
7964 
7965         assert(SysTime(DateTime(2010, 8, 24, 0, 0, 0)).modJulianDay == 55_432);
7966         assert(SysTime(DateTime(2010, 8, 24, 12, 0, 0)).modJulianDay == 55_432);
7967 
7968         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7969         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
7970         assert(cst.modJulianDay == 51_365);
7971         assert(ist.modJulianDay == 51_365);
7972 
7973         static void testScope(scope ref SysTime st) @safe
7974         {
7975             auto result = st.modJulianDay;
7976         }
7977     }
7978 
7979 
7980     /++
7981         Returns a $(REF Date,std,datetime,date) equivalent to this $(LREF SysTime).
7982       +/
7983     Date opCast(T)() @safe const nothrow scope
7984         if (is(immutable T == immutable Date))
7985     {
7986         return Date(dayOfGregorianCal);
7987     }
7988 
7989     @safe unittest
7990     {
7991         import core.time;
7992         assert(cast(Date) SysTime(Date(1999, 7, 6)) == Date(1999, 7, 6));
7993         assert(cast(Date) SysTime(Date(2000, 12, 31)) == Date(2000, 12, 31));
7994         assert(cast(Date) SysTime(Date(2001, 1, 1)) == Date(2001, 1, 1));
7995 
7996         assert(cast(Date) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == Date(1999, 7, 6));
7997         assert(cast(Date) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == Date(2000, 12, 31));
7998         assert(cast(Date) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == Date(2001, 1, 1));
7999 
8000         assert(cast(Date) SysTime(Date(-1999, 7, 6)) == Date(-1999, 7, 6));
8001         assert(cast(Date) SysTime(Date(-2000, 12, 31)) == Date(-2000, 12, 31));
8002         assert(cast(Date) SysTime(Date(-2001, 1, 1)) == Date(-2001, 1, 1));
8003 
8004         assert(cast(Date) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == Date(-1999, 7, 6));
8005         assert(cast(Date) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == Date(-2000, 12, 31));
8006         assert(cast(Date) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == Date(-2001, 1, 1));
8007 
8008         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8009         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8010         assert(cast(Date) cst != Date.init);
8011         assert(cast(Date) ist != Date.init);
8012 
8013         static void testScope(scope ref SysTime st) @safe
8014         {
8015             auto result = cast(Date) st;
8016         }
8017     }
8018 
8019 
8020     /++
8021         Returns a $(REF DateTime,std,datetime,date) equivalent to this
8022         $(LREF SysTime).
8023       +/
8024     DateTime opCast(T)() @safe const nothrow scope
8025         if (is(immutable T == immutable DateTime))
8026     {
8027         try
8028         {
8029             auto hnsecs = adjTime;
8030             auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8031 
8032             if (hnsecs < 0)
8033             {
8034                 hnsecs += convert!("hours", "hnsecs")(24);
8035                 --days;
8036             }
8037 
8038             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8039             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8040             immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
8041 
8042             return DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour, cast(int) minute, cast(int) second));
8043         }
8044         catch (Exception e)
8045             assert(0, "Either DateTime's constructor or TimeOfDay's constructor threw.");
8046     }
8047 
8048     @safe unittest
8049     {
8050         import core.time;
8051         assert(cast(DateTime) SysTime(DateTime(1, 1, 6, 7, 12, 22)) == DateTime(1, 1, 6, 7, 12, 22));
8052         assert(cast(DateTime) SysTime(DateTime(1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(1, 1, 6, 7, 12, 22));
8053         assert(cast(DateTime) SysTime(Date(1999, 7, 6)) == DateTime(1999, 7, 6, 0, 0, 0));
8054         assert(cast(DateTime) SysTime(Date(2000, 12, 31)) == DateTime(2000, 12, 31, 0, 0, 0));
8055         assert(cast(DateTime) SysTime(Date(2001, 1, 1)) == DateTime(2001, 1, 1, 0, 0, 0));
8056 
8057         assert(cast(DateTime) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == DateTime(1999, 7, 6, 12, 10, 9));
8058         assert(cast(DateTime) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == DateTime(2000, 12, 31, 13, 11, 10));
8059         assert(cast(DateTime) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == DateTime(2001, 1, 1, 14, 12, 11));
8060 
8061         assert(cast(DateTime) SysTime(DateTime(-1, 1, 6, 7, 12, 22)) == DateTime(-1, 1, 6, 7, 12, 22));
8062         assert(cast(DateTime) SysTime(DateTime(-1, 1, 6, 7, 12, 22), msecs(22)) == DateTime(-1, 1, 6, 7, 12, 22));
8063         assert(cast(DateTime) SysTime(Date(-1999, 7, 6)) == DateTime(-1999, 7, 6, 0, 0, 0));
8064         assert(cast(DateTime) SysTime(Date(-2000, 12, 31)) == DateTime(-2000, 12, 31, 0, 0, 0));
8065         assert(cast(DateTime) SysTime(Date(-2001, 1, 1)) == DateTime(-2001, 1, 1, 0, 0, 0));
8066 
8067         assert(cast(DateTime) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == DateTime(-1999, 7, 6, 12, 10, 9));
8068         assert(cast(DateTime) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == DateTime(-2000, 12, 31, 13, 11, 10));
8069         assert(cast(DateTime) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == DateTime(-2001, 1, 1, 14, 12, 11));
8070 
8071         assert(cast(DateTime) SysTime(DateTime(2011, 1, 13, 8, 17, 2), msecs(296), LocalTime()) ==
8072                DateTime(2011, 1, 13, 8, 17, 2));
8073 
8074         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8075         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8076         assert(cast(DateTime) cst != DateTime.init);
8077         assert(cast(DateTime) ist != DateTime.init);
8078 
8079         static void testScope(scope ref SysTime st) @safe
8080         {
8081             auto result = cast(DateTime) st;
8082         }
8083     }
8084 
8085 
8086     /++
8087         Returns a $(REF TimeOfDay,std,datetime,date) equivalent to this
8088         $(LREF SysTime).
8089       +/
8090     TimeOfDay opCast(T)() @safe const nothrow scope
8091         if (is(immutable T == immutable TimeOfDay))
8092     {
8093         try
8094         {
8095             auto hnsecs = adjTime;
8096             hnsecs = removeUnitsFromHNSecs!"days"(hnsecs);
8097 
8098             if (hnsecs < 0)
8099                 hnsecs += convert!("hours", "hnsecs")(24);
8100 
8101             immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8102             immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8103             immutable second = getUnitsFromHNSecs!"seconds"(hnsecs);
8104 
8105             return TimeOfDay(cast(int) hour, cast(int) minute, cast(int) second);
8106         }
8107         catch (Exception e)
8108             assert(0, "TimeOfDay's constructor threw.");
8109     }
8110 
8111     @safe unittest
8112     {
8113         import core.time;
8114         assert(cast(TimeOfDay) SysTime(Date(1999, 7, 6)) == TimeOfDay(0, 0, 0));
8115         assert(cast(TimeOfDay) SysTime(Date(2000, 12, 31)) == TimeOfDay(0, 0, 0));
8116         assert(cast(TimeOfDay) SysTime(Date(2001, 1, 1)) == TimeOfDay(0, 0, 0));
8117 
8118         assert(cast(TimeOfDay) SysTime(DateTime(1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
8119         assert(cast(TimeOfDay) SysTime(DateTime(2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
8120         assert(cast(TimeOfDay) SysTime(DateTime(2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11));
8121 
8122         assert(cast(TimeOfDay) SysTime(Date(-1999, 7, 6)) == TimeOfDay(0, 0, 0));
8123         assert(cast(TimeOfDay) SysTime(Date(-2000, 12, 31)) == TimeOfDay(0, 0, 0));
8124         assert(cast(TimeOfDay) SysTime(Date(-2001, 1, 1)) == TimeOfDay(0, 0, 0));
8125 
8126         assert(cast(TimeOfDay) SysTime(DateTime(-1999, 7, 6, 12, 10, 9)) == TimeOfDay(12, 10, 9));
8127         assert(cast(TimeOfDay) SysTime(DateTime(-2000, 12, 31, 13, 11, 10)) == TimeOfDay(13, 11, 10));
8128         assert(cast(TimeOfDay) SysTime(DateTime(-2001, 1, 1, 14, 12, 11)) == TimeOfDay(14, 12, 11));
8129 
8130         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8131         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8132         assert(cast(TimeOfDay) cst != TimeOfDay.init);
8133         assert(cast(TimeOfDay) ist != TimeOfDay.init);
8134 
8135         static void testScope(scope ref SysTime st) @safe
8136         {
8137             auto result = cast(TimeOfDay) st;
8138         }
8139     }
8140 
8141 
8142     // Temporary hack until bug https://issues.dlang.org/show_bug.cgi?id=4867 is fixed.
8143     // This allows assignment from const(SysTime) to SysTime.
8144     // It may be a good idea to keep it though, since casting from a type to itself
8145     // should be allowed, and it doesn't work without this opCast() since opCast()
8146     // has already been defined for other types.
8147     SysTime opCast(T)() @safe const pure nothrow scope
8148         if (is(immutable T == immutable SysTime))
8149     {
8150         return SysTime(_stdTime, _timezone);
8151     }
8152 
8153     @safe unittest
8154     {
8155         static void testScope(scope ref SysTime st) @safe
8156         {
8157             auto result = cast(SysTime) st;
8158         }
8159     }
8160 
8161 
8162     /++
8163         Converts this $(LREF SysTime) to a string with the format
8164         YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds and TZ is time
8165         zone).
8166 
8167         Note that the number of digits in the fractional seconds varies with the
8168         number of fractional seconds. It's a maximum of 7 (which would be
8169         hnsecs), but only has as many as are necessary to hold the correct value
8170         (so no trailing zeroes), and if there are no fractional seconds, then
8171         there is no decimal point.
8172 
8173         If this $(LREF SysTime)'s time zone is
8174         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
8175         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
8176         (e.g. +0100 or -0700). Note that the offset from UTC is $(I not) enough
8177         to uniquely identify the time zone.
8178 
8179         Time zone offsets will be in the form +HHMM or -HHMM.
8180 
8181         $(RED Warning:
8182             Previously, toISOString did the same as $(LREF toISOExtString) and
8183             generated +HH:MM or -HH:MM for the time zone when it was not
8184             $(REF LocalTime,std,datetime,timezone) or
8185             $(REF UTC,std,datetime,timezone), which is not in conformance with
8186             ISO 8601 for the non-extended string format. This has now been
8187             fixed. However, for now, fromISOString will continue to accept the
8188             extended format for the time zone so that any code which has been
8189             writing out the result of toISOString to read in later will continue
8190             to work. The current behavior will be kept until July 2019 at which
8191             point, fromISOString will be fixed to be standards compliant.)
8192 
8193         Params:
8194             writer = A `char` accepting
8195             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8196         Returns:
8197             A `string` when not using an output range; `void` otherwise.
8198       +/
8199     string toISOString() @safe const nothrow scope
8200     {
8201         import std.array : appender;
8202         auto app = appender!string();
8203         app.reserve(30);
8204         try
8205             toISOString(app);
8206         catch (Exception e)
8207             assert(0, "toISOString() threw.");
8208         return app.data;
8209     }
8210 
8211     /// ditto
8212     void toISOString(W)(ref W writer) const scope
8213     if (isOutputRange!(W, char))
8214     {
8215         immutable adjustedTime = adjTime;
8216         long hnsecs = adjustedTime;
8217 
8218         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8219 
8220         if (hnsecs < 0)
8221         {
8222             hnsecs += convert!("hours", "hnsecs")(24);
8223             --days;
8224         }
8225 
8226         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8227         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8228         immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
8229 
8230         auto dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
8231                                       cast(int) minute, cast(int) second));
8232 
8233         if (_timezone is LocalTime())
8234         {
8235             dateTime.toISOString(writer);
8236             fracSecsToISOString(writer, cast(int) hnsecs);
8237             return;
8238         }
8239 
8240         if (_timezone is UTC())
8241         {
8242             dateTime.toISOString(writer);
8243             fracSecsToISOString(writer, cast(int) hnsecs);
8244             put(writer, 'Z');
8245             return;
8246         }
8247 
8248         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
8249 
8250         dateTime.toISOString(writer);
8251         fracSecsToISOString(writer, cast(int) hnsecs);
8252         SimpleTimeZone.toISOExtString(writer, utcOffset);
8253     }
8254 
8255     ///
8256     @safe unittest
8257     {
8258         import core.time : msecs, hnsecs;
8259         import std.datetime.date : DateTime;
8260 
8261         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOString() ==
8262                "20100704T070612");
8263 
8264         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOString() ==
8265                "19981225T021500.024");
8266 
8267         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOString() ==
8268                "00000105T230959");
8269 
8270         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOString() ==
8271                "-00040105T000002.052092");
8272     }
8273 
8274     @safe unittest
8275     {
8276         import core.time;
8277         // Test A.D.
8278         assert(SysTime(DateTime.init, UTC()).toISOString() == "00010101T000000Z");
8279         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOString() == "00010101T000000.0000001Z");
8280 
8281         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOString() == "00091204T000000");
8282         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOString() == "00991204T050612");
8283         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOString() == "09991204T134459");
8284         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOString() == "99990704T235959");
8285         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOString() == "+100001020T010101");
8286 
8287         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "00091204T000000.042");
8288         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "00991204T050612.1");
8289         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "09991204T134459.04502");
8290         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "99990704T235959.0000012");
8291         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "+100001020T010101.050789");
8292 
8293         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8294                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOString() ==
8295                "20121221T121212-06:00");
8296 
8297         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8298                        new immutable SimpleTimeZone(dur!"minutes"(420))).toISOString() ==
8299                "20121221T121212+07:00");
8300 
8301         // Test B.C.
8302         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOString() ==
8303                "00001231T235959.9999999Z");
8304         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOString() == "00001231T235959.0000001Z");
8305         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOString() == "00001231T235959Z");
8306 
8307         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOString() == "00001204T001204");
8308         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOString() == "-00091204T000000");
8309         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOString() == "-00991204T050612");
8310         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOString() == "-09991204T134459");
8311         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOString() == "-99990704T235959");
8312         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOString() == "-100001020T010101");
8313 
8314         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOString() == "00001204T000000.007");
8315         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOString() == "-00091204T000000.042");
8316         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOString() == "-00991204T050612.1");
8317         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOString() == "-09991204T134459.04502");
8318         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOString() == "-99990704T235959.0000012");
8319         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOString() == "-100001020T010101.050789");
8320 
8321         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8322         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8323         assert(cst.toISOString() == "19990706T123033");
8324         assert(ist.toISOString() == "19990706T123033");
8325 
8326         static void testScope(scope ref SysTime st) @safe
8327         {
8328             auto result = st.toISOString();
8329         }
8330     }
8331 
8332 
8333 
8334     /++
8335         Converts this $(LREF SysTime) to a string with the format
8336         YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
8337         is the time zone).
8338 
8339         Default behaviour:
8340         Note that the number of digits in the fractional seconds varies with the
8341         number of fractional seconds. It's a maximum of 7 (which would be
8342         hnsecs), but only has as many as are necessary to hold the correct value
8343         (so no trailing zeroes), and if there are no fractional seconds, then
8344         there is no decimal point.
8345 
8346         The optional parameter "prec" allows to change the default behavior by
8347         specifying the precision of the fractional seconds. The accepted values
8348         are in the range [-1, 7], where -1 represents the default behavior.
8349 
8350         If this $(LREF SysTime)'s time zone is
8351         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
8352         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
8353         (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not)
8354         enough to uniquely identify the time zone.
8355 
8356         Time zone offsets will be in the form +HH:MM or -HH:MM.
8357 
8358         Params:
8359             writer = A `char` accepting
8360             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8361             prec = An `int` representing the desired precision. Acceptable values range from -1 to 7, where -1 represents the default behavior.
8362         Returns:
8363             A `string` when not using an output range; `void` otherwise.
8364       +/
8365     string toISOExtString(int prec = -1) @safe const nothrow scope
8366     {
8367         assert(prec >= -1 && prec <= 7, "Precision must be in the range [-1, 7]");
8368 
8369         import std.array : appender;
8370         auto app = appender!string();
8371         app.reserve(35);
8372         try
8373             toISOExtString(app, prec);
8374         catch (Exception e)
8375             assert(0, "toISOExtString() threw.");
8376         return app.data;
8377     }
8378 
8379     /// ditto
8380     void toISOExtString(W)(ref W writer, int prec = -1) const scope
8381     if (isOutputRange!(W, char))
8382     {
8383         assert(prec >= -1 && prec <= 7, "Precision must be in the range [-1, 7]");
8384 
8385         immutable adjustedTime = adjTime;
8386         long hnsecs = adjustedTime;
8387 
8388         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8389 
8390         if (hnsecs < 0)
8391         {
8392             hnsecs += convert!("hours", "hnsecs")(24);
8393             --days;
8394         }
8395 
8396         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8397         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8398         immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
8399 
8400         immutable dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
8401                                       cast(int) minute, cast(int) second));
8402 
8403         if (_timezone is LocalTime())
8404         {
8405             dateTime.toISOExtString(writer);
8406             fracSecsToISOString(writer, cast(int) hnsecs, prec);
8407             return;
8408         }
8409 
8410         if (_timezone is UTC())
8411         {
8412             dateTime.toISOExtString(writer);
8413             fracSecsToISOString(writer, cast(int) hnsecs, prec);
8414             put(writer, 'Z');
8415             return;
8416         }
8417 
8418         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
8419 
8420         dateTime.toISOExtString(writer);
8421         fracSecsToISOString(writer, cast(int) hnsecs, prec);
8422         SimpleTimeZone.toISOExtString(writer, utcOffset);
8423     }
8424 
8425     ///
8426     @safe unittest
8427     {
8428         import core.time : msecs, hnsecs;
8429         import std.datetime.date : DateTime;
8430 
8431         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOExtString() ==
8432                "2010-07-04T07:06:12");
8433 
8434         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOExtString() ==
8435                "1998-12-25T02:15:00.024");
8436 
8437         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOExtString() ==
8438                "0000-01-05T23:09:59");
8439 
8440         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString() ==
8441                "-0004-01-05T00:00:02.052092");
8442 
8443         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(4) ==
8444                "-0004-01-05T00:00:02.0520");
8445 
8446         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(2) ==
8447                "-0004-01-05T00:00:02.05");
8448 
8449         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(7) ==
8450                "-0004-01-05T00:00:02.0520920");
8451     }
8452 
8453     @safe unittest
8454     {
8455         import core.time;
8456         // Test A.D.
8457         assert(SysTime(DateTime.init, UTC()).toISOExtString() == "0001-01-01T00:00:00Z");
8458         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toISOExtString() ==
8459                "0001-01-01T00:00:00.0000001Z");
8460 
8461         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00");
8462         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12");
8463         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59");
8464         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59");
8465         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01");
8466 
8467         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "0009-12-04T00:00:00.042");
8468         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "0099-12-04T05:06:12.1");
8469         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() == "0999-12-04T13:44:59.04502");
8470         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() == "9999-07-04T23:59:59.0000012");
8471         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
8472                "+10000-10-20T01:01:01.050789");
8473 
8474         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8475                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toISOExtString() ==
8476                "2012-12-21T12:12:12-06:00");
8477 
8478         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8479                        new immutable SimpleTimeZone(dur!"minutes"(420))).toISOExtString() ==
8480                "2012-12-21T12:12:12+07:00");
8481 
8482         // Test B.C.
8483         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toISOExtString() ==
8484                "0000-12-31T23:59:59.9999999Z");
8485         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toISOExtString() ==
8486                "0000-12-31T23:59:59.0000001Z");
8487         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toISOExtString() == "0000-12-31T23:59:59Z");
8488 
8489         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04");
8490         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00");
8491         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12");
8492         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59");
8493         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59");
8494         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01");
8495 
8496         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toISOExtString() == "0000-12-04T00:00:00.007");
8497         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toISOExtString() == "-0009-12-04T00:00:00.042");
8498         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toISOExtString() == "-0099-12-04T05:06:12.1");
8499         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toISOExtString() ==
8500                "-0999-12-04T13:44:59.04502");
8501         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toISOExtString() ==
8502                "-9999-07-04T23:59:59.0000012");
8503         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toISOExtString() ==
8504                "-10000-10-20T01:01:01.050789");
8505 
8506         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8507         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8508         assert(cst.toISOExtString() == "1999-07-06T12:30:33");
8509         assert(ist.toISOExtString() == "1999-07-06T12:30:33");
8510 
8511         static void testScope(scope ref SysTime st) @safe
8512         {
8513             auto result = st.toISOExtString();
8514         }
8515     }
8516 
8517     /++
8518         Converts this $(LREF SysTime) to a string with the format
8519         YYYY-Mon-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
8520         is the time zone).
8521 
8522         Note that the number of digits in the fractional seconds varies with the
8523         number of fractional seconds. It's a maximum of 7 (which would be
8524         hnsecs), but only has as many as are necessary to hold the correct value
8525         (so no trailing zeroes), and if there are no fractional seconds, then
8526         there is no decimal point.
8527 
8528         If this $(LREF SysTime)'s time zone is
8529         $(REF LocalTime,std,datetime,timezone), then TZ is empty. If its time
8530         zone is `UTC`, then it is "Z". Otherwise, it is the offset from UTC
8531         (e.g. +01:00 or -07:00). Note that the offset from UTC is $(I not)
8532         enough to uniquely identify the time zone.
8533 
8534         Time zone offsets will be in the form +HH:MM or -HH:MM.
8535 
8536         Params:
8537             writer = A `char` accepting
8538             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8539         Returns:
8540             A `string` when not using an output range; `void` otherwise.
8541       +/
8542     string toSimpleString() @safe const nothrow scope
8543     {
8544         import std.array : appender;
8545         auto app = appender!string();
8546         app.reserve(35);
8547         try
8548             toSimpleString(app);
8549         catch (Exception e)
8550             assert(0, "toSimpleString() threw.");
8551         return app.data;
8552     }
8553 
8554     /// ditto
8555     void toSimpleString(W)(ref W writer) const scope
8556     if (isOutputRange!(W, char))
8557     {
8558         immutable adjustedTime = adjTime;
8559         long hnsecs = adjustedTime;
8560 
8561         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
8562 
8563         if (hnsecs < 0)
8564         {
8565             hnsecs += convert!("hours", "hnsecs")(24);
8566             --days;
8567         }
8568 
8569         immutable hour = splitUnitsFromHNSecs!"hours"(hnsecs);
8570         immutable minute = splitUnitsFromHNSecs!"minutes"(hnsecs);
8571         immutable second = splitUnitsFromHNSecs!"seconds"(hnsecs);
8572 
8573         immutable dateTime = DateTime(Date(cast(int) days), TimeOfDay(cast(int) hour,
8574                                       cast(int) minute, cast(int) second));
8575 
8576         if (_timezone is LocalTime())
8577         {
8578             dateTime.toSimpleString(writer);
8579             fracSecsToISOString(writer, cast(int) hnsecs);
8580             return;
8581         }
8582 
8583         if (_timezone is UTC())
8584         {
8585             dateTime.toSimpleString(writer);
8586             fracSecsToISOString(writer, cast(int) hnsecs);
8587             put(writer, 'Z');
8588             return;
8589         }
8590 
8591         immutable utcOffset = dur!"hnsecs"(adjustedTime - stdTime);
8592 
8593         dateTime.toSimpleString(writer);
8594         fracSecsToISOString(writer, cast(int) hnsecs);
8595         SimpleTimeZone.toISOExtString(writer, utcOffset);
8596     }
8597 
8598     ///
8599     @safe unittest
8600     {
8601         import core.time : msecs, hnsecs;
8602         import std.datetime.date : DateTime;
8603 
8604         assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toSimpleString() ==
8605                "2010-Jul-04 07:06:12");
8606 
8607         assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toSimpleString() ==
8608                "1998-Dec-25 02:15:00.024");
8609 
8610         assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toSimpleString() ==
8611                "0000-Jan-05 23:09:59");
8612 
8613         assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toSimpleString() ==
8614                 "-0004-Jan-05 00:00:02.052092");
8615     }
8616 
8617     @safe unittest
8618     {
8619         import core.time;
8620         // Test A.D.
8621         assert(SysTime(DateTime.init, UTC()).toString() == "0001-Jan-01 00:00:00Z");
8622         assert(SysTime(DateTime(1, 1, 1, 0, 0, 0), hnsecs(1), UTC()).toString() == "0001-Jan-01 00:00:00.0000001Z");
8623 
8624         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00");
8625         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12");
8626         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59");
8627         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59");
8628         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01");
8629 
8630         assert(SysTime(DateTime(9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "0009-Dec-04 00:00:00.042");
8631         assert(SysTime(DateTime(99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "0099-Dec-04 05:06:12.1");
8632         assert(SysTime(DateTime(999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
8633                "0999-Dec-04 13:44:59.04502");
8634         assert(SysTime(DateTime(9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
8635                "9999-Jul-04 23:59:59.0000012");
8636         assert(SysTime(DateTime(10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() ==
8637                "+10000-Oct-20 01:01:01.050789");
8638 
8639         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8640                        new immutable SimpleTimeZone(dur!"minutes"(-360))).toSimpleString() ==
8641                "2012-Dec-21 12:12:12-06:00");
8642 
8643         assert(SysTime(DateTime(2012, 12, 21, 12, 12, 12),
8644                        new immutable SimpleTimeZone(dur!"minutes"(420))).toSimpleString() ==
8645                "2012-Dec-21 12:12:12+07:00");
8646 
8647         // Test B.C.
8648         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(9_999_999), UTC()).toSimpleString() ==
8649                "0000-Dec-31 23:59:59.9999999Z");
8650         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), hnsecs(1), UTC()).toSimpleString() ==
8651                "0000-Dec-31 23:59:59.0000001Z");
8652         assert(SysTime(DateTime(0, 12, 31, 23, 59, 59), UTC()).toSimpleString() == "0000-Dec-31 23:59:59Z");
8653 
8654         assert(SysTime(DateTime(0, 12, 4, 0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04");
8655         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00");
8656         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12");
8657         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59");
8658         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59");
8659         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01");
8660 
8661         assert(SysTime(DateTime(0, 12, 4, 0, 0, 0), msecs(7)).toSimpleString() == "0000-Dec-04 00:00:00.007");
8662         assert(SysTime(DateTime(-9, 12, 4, 0, 0, 0), msecs(42)).toSimpleString() == "-0009-Dec-04 00:00:00.042");
8663         assert(SysTime(DateTime(-99, 12, 4, 5, 6, 12), msecs(100)).toSimpleString() == "-0099-Dec-04 05:06:12.1");
8664         assert(SysTime(DateTime(-999, 12, 4, 13, 44, 59), usecs(45020)).toSimpleString() ==
8665                "-0999-Dec-04 13:44:59.04502");
8666         assert(SysTime(DateTime(-9999, 7, 4, 23, 59, 59), hnsecs(12)).toSimpleString() ==
8667                "-9999-Jul-04 23:59:59.0000012");
8668         assert(SysTime(DateTime(-10000, 10, 20, 1, 1, 1), hnsecs(507890)).toSimpleString() ==
8669                "-10000-Oct-20 01:01:01.050789");
8670 
8671         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8672         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8673         assert(cst.toSimpleString() == "1999-Jul-06 12:30:33");
8674         assert(ist.toSimpleString() == "1999-Jul-06 12:30:33");
8675 
8676         static void testScope(scope ref SysTime st) @safe
8677         {
8678             auto result = st.toSimpleString();
8679         }
8680     }
8681 
8682 
8683     /++
8684         Converts this $(LREF SysTime) to a string.
8685 
8686         This function exists to make it easy to convert a $(LREF SysTime) to a
8687         string for code that does not care what the exact format is - just that
8688         it presents the information in a clear manner. It also makes it easy to
8689         simply convert a $(LREF SysTime) to a string when using functions such
8690         as `to!string`, `format`, or `writeln` which use toString to convert
8691         user-defined types. So, it is unlikely that much code will call
8692         toString directly.
8693 
8694         The format of the string is purposefully unspecified, and code that
8695         cares about the format of the string should use `toISOString`,
8696         `toISOExtString`, `toSimpleString`, or some other custom formatting
8697         function that explicitly generates the format that the code needs. The
8698         reason is that the code is then clear about what format it's using,
8699         making it less error-prone to maintain the code and interact with other
8700         software that consumes the generated strings. It's for this same reason
8701         that $(LREF SysTime) has no `fromString` function, whereas it does have
8702         `fromISOString`, `fromISOExtString`, and `fromSimpleString`.
8703 
8704         The format returned by toString may or may not change in the future.
8705 
8706         Params:
8707             writer = A `char` accepting
8708             $(REF_ALTTEXT output range, isOutputRange, std, range, primitives)
8709         Returns:
8710             A `string` when not using an output range; `void` otherwise.
8711       +/
8712     string toString() @safe const nothrow scope
8713     {
8714         return toSimpleString();
8715     }
8716 
8717     /// ditto
8718     void toString(W)(ref W writer) const scope
8719     if (isOutputRange!(W, char))
8720     {
8721         toSimpleString(writer);
8722     }
8723 
8724     @safe unittest
8725     {
8726         import core.time;
8727         auto st = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8728         const cst = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8729         immutable ist = SysTime(DateTime(1999, 7, 6, 12, 30, 33));
8730         static assert(__traits(compiles, st.toString()));
8731         static assert(__traits(compiles, cst.toString()));
8732         static assert(__traits(compiles, ist.toString()));
8733 
8734         static void testScope(scope ref SysTime st) @safe
8735         {
8736             auto result = st.toString();
8737         }
8738     }
8739 
8740 
8741     /++
8742         Creates a $(LREF SysTime) from a string with the format
8743         YYYYMMDDTHHMMSS.FFFFFFFTZ (where F is fractional seconds and TZ
8744         is the time zone). Whitespace is stripped from the given string.
8745 
8746         The exact format is exactly as described in $(LREF toISOString) except
8747         that trailing zeroes are permitted - including having fractional seconds
8748         with all zeroes. The time zone and fractional seconds are optional,
8749         however, a decimal point with nothing following it is invalid.
8750         Also, while $(LREF toISOString) will never generate a string
8751         with more than 7 digits in the fractional seconds (because that's the
8752         limit with hecto-nanosecond precision), it will allow more than 7 digits
8753         in order to read strings from other sources that have higher precision
8754         (however, any digits beyond 7 will be truncated).
8755 
8756         If there is no time zone in the string, then
8757         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
8758         then `UTC` is used. Otherwise, a
8759         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
8760         given offset from UTC is used. To get the returned $(LREF SysTime) to be
8761         a particular time zone, pass in that time zone and the $(LREF SysTime)
8762         to be returned will be converted to that time zone (though it will still
8763         be read in as whatever time zone is in its string).
8764 
8765         The accepted formats for time zone offsets are +HH, -HH, +HHMM, and
8766         -HHMM.
8767 
8768         $(RED Warning:
8769             Previously, $(LREF toISOString) did the same as
8770             $(LREF toISOExtString) and generated +HH:MM or -HH:MM for the time
8771             zone when it was not $(REF LocalTime,std,datetime,timezone) or
8772             $(REF UTC,std,datetime,timezone), which is not in conformance with
8773             ISO 8601 for the non-extended string format. This has now been
8774             fixed. However, for now, fromISOString will continue to accept the
8775             extended format for the time zone so that any code which has been
8776             writing out the result of toISOString to read in later will continue
8777             to work. The current behavior will be kept until July 2019 at which
8778             point, fromISOString will be fixed to be standards compliant.)
8779 
8780         Params:
8781             isoString = A string formatted in the ISO format for dates and times.
8782             tz        = The time zone to convert the given time to (no
8783                         conversion occurs if null).
8784 
8785         Throws:
8786             $(REF DateTimeException,std,datetime,date) if the given string is
8787             not in the ISO format or if the resulting $(LREF SysTime) would not
8788             be valid.
8789       +/
8790     static SysTime fromISOString(S)(scope const S isoString, immutable TimeZone tz = null) @safe
8791         if (isSomeString!S)
8792     {
8793         import std.algorithm.searching : startsWith, find;
8794         import std.conv : to;
8795         import std.string : strip;
8796         import std.utf : byCodeUnit;
8797 
8798         auto str = strip(isoString);
8799         immutable skipFirst = str.startsWith('+', '-');
8800 
8801         auto found = (skipFirst ? str[1..$] : str).byCodeUnit.find('.', 'Z', '+', '-');
8802         auto dateTimeStr = str[0 .. $ - found[0].length];
8803 
8804         typeof(str.byCodeUnit) foundTZ; // needs to have longer lifetime than zoneStr
8805         typeof(str) fracSecStr;
8806         typeof(str) zoneStr;
8807 
8808         if (found[1] != 0)
8809         {
8810             if (found[1] == 1)
8811             {
8812                 foundTZ = found[0].find('Z', '+', '-')[0];
8813 
8814                 if (foundTZ.length != 0)
8815                 {
8816                     static if (isNarrowString!S)
8817                     {
8818                         fracSecStr = found[0][0 .. $ - foundTZ.length].source;
8819                         zoneStr = foundTZ.source;
8820                     }
8821                     else
8822                     {
8823                         fracSecStr = found[0][0 .. $ - foundTZ.length];
8824                         zoneStr = foundTZ;
8825                     }
8826                 }
8827                 else
8828                 {
8829                     static if (isNarrowString!S)
8830                         fracSecStr = found[0].source;
8831                     else
8832                         fracSecStr = found[0];
8833                 }
8834             }
8835             else
8836             {
8837                 static if (isNarrowString!S)
8838                     zoneStr = found[0].source;
8839                 else
8840                     zoneStr = found[0];
8841             }
8842         }
8843 
8844         try
8845         {
8846             auto dateTime = DateTime.fromISOString(dateTimeStr);
8847             auto fracSec = fracSecsFromISOString(fracSecStr);
8848 
8849             Rebindable!(immutable TimeZone) parsedZone;
8850 
8851             if (zoneStr.empty)
8852                 parsedZone = LocalTime();
8853             else if (zoneStr == "Z")
8854                 parsedZone = UTC();
8855             else
8856             {
8857                 try
8858                     parsedZone = SimpleTimeZone.fromISOString(zoneStr);
8859                 catch (DateTimeException dte)
8860                     parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
8861             }
8862 
8863             auto retval = SysTime(dateTime, fracSec, parsedZone);
8864 
8865             if (tz !is null)
8866                 retval.timezone = tz;
8867 
8868             return retval;
8869         }
8870         catch (DateTimeException dte)
8871             throw new DateTimeException(format("Invalid ISO String: %s", isoString));
8872     }
8873 
8874     ///
8875     @safe unittest
8876     {
8877         import core.time : hours, msecs, usecs, hnsecs;
8878         import std.datetime.date : DateTime;
8879         import std.datetime.timezone : SimpleTimeZone, UTC;
8880 
8881         assert(SysTime.fromISOString("20100704T070612") ==
8882                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8883 
8884         assert(SysTime.fromISOString("19981225T021500.007") ==
8885                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
8886 
8887         assert(SysTime.fromISOString("00000105T230959.00002") ==
8888                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
8889 
8890         assert(SysTime.fromISOString("20130207T043937.000050392") ==
8891                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
8892 
8893         assert(SysTime.fromISOString("-00040105T000002") ==
8894                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
8895 
8896         assert(SysTime.fromISOString(" 20100704T070612 ") ==
8897                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
8898 
8899         assert(SysTime.fromISOString("20100704T070612Z") ==
8900                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
8901 
8902         assert(SysTime.fromISOString("20100704T070612-0800") ==
8903                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8904                        new immutable SimpleTimeZone(hours(-8))));
8905 
8906         assert(SysTime.fromISOString("20100704T070612+0800") ==
8907                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
8908                        new immutable SimpleTimeZone(hours(8))));
8909     }
8910 
8911     @safe unittest
8912     {
8913         import core.time;
8914         foreach (str; ["", "20100704000000", "20100704 000000", "20100704t000000",
8915                        "20100704T000000.", "20100704T000000.A", "20100704T000000.Z",
8916                        "20100704T000000.0000000A", "20100704T000000.00000000A",
8917                        "20100704T000000+", "20100704T000000-", "20100704T000000:",
8918                        "20100704T000000-:", "20100704T000000+:", "20100704T000000-1:",
8919                        "20100704T000000+1:", "20100704T000000+1:0",
8920                        "20100704T000000-12.00", "20100704T000000+12.00",
8921                        "20100704T000000-8", "20100704T000000+8",
8922                        "20100704T000000-800", "20100704T000000+800",
8923                        "20100704T000000-080", "20100704T000000+080",
8924                        "20100704T000000-2400", "20100704T000000+2400",
8925                        "20100704T000000-1260", "20100704T000000+1260",
8926                        "20100704T000000.0-8", "20100704T000000.0+8",
8927                        "20100704T000000.0-800", "20100704T000000.0+800",
8928                        "20100704T000000.0-080", "20100704T000000.0+080",
8929                        "20100704T000000.0-2400", "20100704T000000.0+2400",
8930                        "20100704T000000.0-1260", "20100704T000000.0+1260",
8931                        "20100704T000000-8:00", "20100704T000000+8:00",
8932                        "20100704T000000-08:0", "20100704T000000+08:0",
8933                        "20100704T000000-24:00", "20100704T000000+24:00",
8934                        "20100704T000000-12:60", "20100704T000000+12:60",
8935                        "20100704T000000.0-8:00", "20100704T000000.0+8:00",
8936                        "20100704T000000.0-08:0", "20100704T000000.0+08:0",
8937                        "20100704T000000.0-24:00", "20100704T000000.0+24:00",
8938                        "20100704T000000.0-12:60", "20100704T000000.0+12:60",
8939                        "2010-07-0400:00:00", "2010-07-04 00:00:00",
8940                        "2010-07-04t00:00:00", "2010-07-04T00:00:00.",
8941                        "2010-Jul-0400:00:00", "2010-Jul-04 00:00:00", "2010-Jul-04t00:00:00",
8942                        "2010-Jul-04T00:00:00", "2010-Jul-04 00:00:00.",
8943                        "2010-12-22T172201", "2010-Dec-22 17:22:01"])
8944         {
8945             assertThrown!DateTimeException(SysTime.fromISOString(str), format("[%s]", str));
8946         }
8947 
8948         static void test(string str, SysTime st, size_t line = __LINE__)
8949         {
8950             if (SysTime.fromISOString(str) != st)
8951                 throw new AssertError("unittest failure", __FILE__, line);
8952         }
8953 
8954         test("20101222T172201", SysTime(DateTime(2010, 12, 22, 17, 22, 1)));
8955         test("19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8956         test("-19990706T123033", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
8957         test("+019990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8958         test("19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8959         test(" 19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8960         test(" 19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
8961 
8962         test("19070707T121212.0", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
8963         test("19070707T121212.0000000", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
8964         test("19070707T121212.0000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), hnsecs(1)));
8965         test("20100704T000000.00000000", SysTime(Date(2010, 7, 4)));
8966         test("20100704T000000.00000009", SysTime(Date(2010, 7, 4)));
8967         test("20100704T000000.00000019", SysTime(DateTime(2010, 7, 4), hnsecs(1)));
8968         test("19070707T121212.000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
8969         test("19070707T121212.0000010", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
8970         test("19070707T121212.001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
8971         test("19070707T121212.0010000", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
8972 
8973         auto west60 = new immutable SimpleTimeZone(hours(-1));
8974         auto west90 = new immutable SimpleTimeZone(minutes(-90));
8975         auto west480 = new immutable SimpleTimeZone(hours(-8));
8976         auto east60 = new immutable SimpleTimeZone(hours(1));
8977         auto east90 = new immutable SimpleTimeZone(minutes(90));
8978         auto east480 = new immutable SimpleTimeZone(hours(8));
8979 
8980         test("20101222T172201Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), UTC()));
8981         test("20101222T172201-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
8982         test("20101222T172201-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
8983         test("20101222T172201-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
8984         test("20101222T172201-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
8985         test("20101222T172201+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
8986         test("20101222T172201+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
8987         test("20101222T172201+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
8988         test("20101222T172201+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
8989 
8990         test("20101103T065106.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
8991         test("20101222T172201.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_341_200), UTC()));
8992         test("20101222T172201.23112-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
8993         test("20101222T172201.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), west60));
8994         test("20101222T172201.1-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
8995         test("20101222T172201.55-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
8996         test("20101222T172201.1234567+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
8997         test("20101222T172201.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
8998         test("20101222T172201.0000000+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
8999         test("20101222T172201.45+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
9000 
9001         // for dstring coverage
9002         assert(SysTime.fromISOString("20101222T172201.23112-0100"d) == SysTime(
9003             DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9004         assert(SysTime.fromISOString("19070707T121212.0010000"d) == SysTime(
9005             DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9006 
9007         // @@@DEPRECATED_2019-07@@@
9008         // This isn't deprecated per se, but that text will make it so that it
9009         // pops up when deprecations are moved along around July 2019. At that
9010         // time, we will update fromISOString so that it is conformant with ISO
9011         // 8601, and it will no longer accept ISO extended time zones (it does
9012         // currently because of https://issues.dlang.org/show_bug.cgi?id=15654
9013         // toISOString used to incorrectly use the ISO extended time zone format).
9014         // These tests will then start failing will need to be updated accordingly.
9015         // Also, the notes about this issue in toISOString and fromISOString's
9016         // documentation will need to be removed.
9017         test("20101222T172201-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9018         test("20101222T172201-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
9019         test("20101222T172201-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
9020         test("20101222T172201+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9021         test("20101222T172201+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9022         test("20101222T172201+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
9023 
9024         test("20101222T172201.23112-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9025         test("20101222T172201.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
9026         test("20101222T172201.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
9027         test("20101222T172201.1234567+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
9028         test("20101222T172201.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9029         test("20101222T172201.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
9030 
9031         static void testScope(scope ref string str) @safe
9032         {
9033             auto result = SysTime.fromISOString(str);
9034         }
9035     }
9036 
9037     // https://issues.dlang.org/show_bug.cgi?id=17801
9038     @safe unittest
9039     {
9040         import std.conv : to;
9041         import std.meta : AliasSeq;
9042         static foreach (C; AliasSeq!(char, wchar, dchar))
9043         {
9044             static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
9045             {
9046                 assert(SysTime.fromISOString(to!S("20121221T141516Z")) ==
9047                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
9048             }
9049         }
9050     }
9051 
9052 
9053     /++
9054         Creates a $(LREF SysTime) from a string with the format
9055         YYYY-MM-DDTHH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
9056         is the time zone). Whitespace is stripped from the given string.
9057 
9058         The exact format is exactly as described in $(LREF toISOExtString)
9059         except that trailing zeroes are permitted - including having fractional
9060         seconds with all zeroes. The time zone and fractional seconds are
9061         optional, however, a decimal point with nothing following it is invalid.
9062         Also, while $(LREF toISOExtString) will never generate a
9063         string with more than 7 digits in the fractional seconds (because that's
9064         the limit with hecto-nanosecond precision), it will allow more than 7
9065         digits in order to read strings from other sources that have higher
9066         precision (however, any digits beyond 7 will be truncated).
9067 
9068         If there is no time zone in the string, then
9069         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
9070         then `UTC` is used. Otherwise, a
9071         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
9072         given offset from UTC is used. To get the returned $(LREF SysTime) to be
9073         a particular time zone, pass in that time zone and the $(LREF SysTime)
9074         to be returned will be converted to that time zone (though it will still
9075         be read in as whatever time zone is in its string).
9076 
9077         The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and
9078         -HH:MM.
9079 
9080         Params:
9081             isoExtString = A string formatted in the ISO Extended format for
9082                            dates and times.
9083             tz           = The time zone to convert the given time to (no
9084                            conversion occurs if null).
9085 
9086         Throws:
9087             $(REF DateTimeException,std,datetime,date) if the given string is
9088             not in the ISO format or if the resulting $(LREF SysTime) would not
9089             be valid.
9090       +/
9091     static SysTime fromISOExtString(S)(scope const S isoExtString, immutable TimeZone tz = null) @safe
9092         if (isSomeString!(S))
9093     {
9094         import std.algorithm.searching : countUntil, find;
9095         import std.conv : to;
9096         import std.string : strip, indexOf;
9097 
9098         auto str = strip(isoExtString);
9099 
9100         auto tIndex = str.indexOf('T');
9101         enforce(tIndex != -1, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
9102 
9103         auto found = str[tIndex + 1 .. $].find('.', 'Z', '+', '-');
9104         auto dateTimeStr = str[0 .. $ - found[0].length];
9105 
9106         typeof(str) foundTZ;  // needs to have longer lifetime than zoneStr
9107         typeof(str) fracSecStr;
9108         typeof(str) zoneStr;
9109 
9110         if (found[1] != 0)
9111         {
9112             if (found[1] == 1)
9113             {
9114                 foundTZ = found[0].find('Z', '+', '-')[0];
9115 
9116                 if (foundTZ.length != 0)
9117                 {
9118                     fracSecStr = found[0][0 .. $ - foundTZ.length];
9119                     zoneStr = foundTZ;
9120                 }
9121                 else
9122                     fracSecStr = found[0];
9123             }
9124             else
9125                 zoneStr = found[0];
9126         }
9127 
9128         try
9129         {
9130             auto dateTime = DateTime.fromISOExtString(dateTimeStr);
9131             auto fracSec = fracSecsFromISOString(fracSecStr);
9132             Rebindable!(immutable TimeZone) parsedZone;
9133 
9134             if (zoneStr.empty)
9135                 parsedZone = LocalTime();
9136             else if (zoneStr == "Z")
9137                 parsedZone = UTC();
9138             else
9139                 parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
9140 
9141             auto retval = SysTime(dateTime, fracSec, parsedZone);
9142 
9143             if (tz !is null)
9144                 retval.timezone = tz;
9145 
9146             return retval;
9147         }
9148         catch (DateTimeException dte)
9149             throw new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString));
9150     }
9151 
9152     ///
9153     @safe unittest
9154     {
9155         import core.time : hours, msecs, usecs, hnsecs;
9156         import std.datetime.date : DateTime;
9157         import std.datetime.timezone : SimpleTimeZone, UTC;
9158 
9159         assert(SysTime.fromISOExtString("2010-07-04T07:06:12") ==
9160                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9161 
9162         assert(SysTime.fromISOExtString("1998-12-25T02:15:00.007") ==
9163                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
9164 
9165         assert(SysTime.fromISOExtString("0000-01-05T23:09:59.00002") ==
9166                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
9167 
9168         assert(SysTime.fromISOExtString("2013-02-07T04:39:37.000050392") ==
9169                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
9170 
9171         assert(SysTime.fromISOExtString("-0004-01-05T00:00:02") ==
9172                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
9173 
9174         assert(SysTime.fromISOExtString(" 2010-07-04T07:06:12 ") ==
9175                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9176 
9177         assert(SysTime.fromISOExtString("2010-07-04T07:06:12Z") ==
9178                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
9179 
9180         assert(SysTime.fromISOExtString("2010-07-04T07:06:12-08:00") ==
9181                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9182                        new immutable SimpleTimeZone(hours(-8))));
9183         assert(SysTime.fromISOExtString("2010-07-04T07:06:12+08:00") ==
9184                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9185                        new immutable SimpleTimeZone(hours(8))));
9186     }
9187 
9188     @safe unittest
9189     {
9190         import core.time;
9191         foreach (str; ["", "20100704000000", "20100704 000000",
9192                        "20100704t000000", "20100704T000000.", "20100704T000000.0",
9193                        "2010-07:0400:00:00", "2010-07-04 00:00:00",
9194                        "2010-07-04 00:00:00", "2010-07-04t00:00:00",
9195                        "2010-07-04T00:00:00.", "2010-07-04T00:00:00.A", "2010-07-04T00:00:00.Z",
9196                        "2010-07-04T00:00:00.0000000A", "2010-07-04T00:00:00.00000000A",
9197                        "2010-07-04T00:00:00+", "2010-07-04T00:00:00-",
9198                        "2010-07-04T00:00:00:", "2010-07-04T00:00:00-:", "2010-07-04T00:00:00+:",
9199                        "2010-07-04T00:00:00-1:", "2010-07-04T00:00:00+1:", "2010-07-04T00:00:00+1:0",
9200                        "2010-07-04T00:00:00-12.00", "2010-07-04T00:00:00+12.00",
9201                        "2010-07-04T00:00:00-8", "2010-07-04T00:00:00+8",
9202                        "20100704T000000-800", "20100704T000000+800",
9203                        "20100704T000000-080", "20100704T000000+080",
9204                        "20100704T000000-2400", "20100704T000000+2400",
9205                        "20100704T000000-1260", "20100704T000000+1260",
9206                        "20100704T000000.0-800", "20100704T000000.0+800",
9207                        "20100704T000000.0-8", "20100704T000000.0+8",
9208                        "20100704T000000.0-080", "20100704T000000.0+080",
9209                        "20100704T000000.0-2400", "20100704T000000.0+2400",
9210                        "20100704T000000.0-1260", "20100704T000000.0+1260",
9211                        "2010-07-04T00:00:00-8:00", "2010-07-04T00:00:00+8:00",
9212                        "2010-07-04T00:00:00-24:00", "2010-07-04T00:00:00+24:00",
9213                        "2010-07-04T00:00:00-12:60", "2010-07-04T00:00:00+12:60",
9214                        "2010-07-04T00:00:00.0-8:00", "2010-07-04T00:00:00.0+8:00",
9215                        "2010-07-04T00:00:00.0-8", "2010-07-04T00:00:00.0+8",
9216                        "2010-07-04T00:00:00.0-24:00", "2010-07-04T00:00:00.0+24:00",
9217                        "2010-07-04T00:00:00.0-12:60", "2010-07-04T00:00:00.0+12:60",
9218                        "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00",
9219                        "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.0",
9220                        "20101222T172201", "2010-Dec-22 17:22:01"])
9221         {
9222             assertThrown!DateTimeException(SysTime.fromISOExtString(str), format("[%s]", str));
9223         }
9224 
9225         static void test(string str, SysTime st, size_t line = __LINE__)
9226         {
9227             if (SysTime.fromISOExtString(str) != st)
9228                 throw new AssertError("unittest failure", __FILE__, line);
9229         }
9230 
9231         test("2010-12-22T17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 1)));
9232         test("1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9233         test("-1999-07-06T12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
9234         test("+01999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9235         test("1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9236         test(" 1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9237         test(" 1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9238 
9239         test("1907-07-07T12:12:12.0", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9240         test("1907-07-07T12:12:12.0000000", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9241         test("1907-07-07T12:12:12.0000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), hnsecs(1)));
9242         test("2010-07-04T00:00:00.00000000", SysTime(Date(2010, 7, 4)));
9243         test("2010-07-04T00:00:00.00000009", SysTime(Date(2010, 7, 4)));
9244         test("2010-07-04T00:00:00.00000019", SysTime(DateTime(2010, 7, 4), hnsecs(1)));
9245         test("1907-07-07T12:12:12.000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9246         test("1907-07-07T12:12:12.0000010", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9247         test("1907-07-07T12:12:12.001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9248         test("1907-07-07T12:12:12.0010000", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9249 
9250         auto west60 = new immutable SimpleTimeZone(hours(-1));
9251         auto west90 = new immutable SimpleTimeZone(minutes(-90));
9252         auto west480 = new immutable SimpleTimeZone(hours(-8));
9253         auto east60 = new immutable SimpleTimeZone(hours(1));
9254         auto east90 = new immutable SimpleTimeZone(minutes(90));
9255         auto east480 = new immutable SimpleTimeZone(hours(8));
9256 
9257         test("2010-12-22T17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), UTC()));
9258         test("2010-12-22T17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9259         test("2010-12-22T17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9260         test("2010-12-22T17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
9261         test("2010-12-22T17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
9262         test("2010-12-22T17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9263         test("2010-12-22T17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9264         test("2010-12-22T17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9265         test("2010-12-22T17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
9266 
9267         test("2010-11-03T06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
9268         test("2010-12-22T17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_341_200), UTC()));
9269         test("2010-12-22T17:22:01.23112-01:00",
9270              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9271         test("2010-12-22T17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), west60));
9272         test("2010-12-22T17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
9273         test("2010-12-22T17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
9274         test("2010-12-22T17:22:01.1234567+01:00",
9275              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
9276         test("2010-12-22T17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9277         test("2010-12-22T17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9278         test("2010-12-22T17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
9279 
9280         static void testScope(scope ref string str) @safe
9281         {
9282             auto result = SysTime.fromISOExtString(str);
9283         }
9284     }
9285 
9286     // https://issues.dlang.org/show_bug.cgi?id=17801
9287     @safe unittest
9288     {
9289         import core.time;
9290         import std.conv : to;
9291         import std.meta : AliasSeq;
9292         static foreach (C; AliasSeq!(char, wchar, dchar))
9293         {
9294             static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
9295             {
9296                 assert(SysTime.fromISOExtString(to!S("2012-12-21T14:15:16Z")) ==
9297                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
9298             }
9299         }
9300     }
9301 
9302 
9303     /++
9304         Creates a $(LREF SysTime) from a string with the format
9305         YYYY-Mon-DD HH:MM:SS.FFFFFFFTZ (where F is fractional seconds and TZ
9306         is the time zone). Whitespace is stripped from the given string.
9307 
9308         The exact format is exactly as described in $(LREF toSimpleString) except
9309         that trailing zeroes are permitted - including having fractional seconds
9310         with all zeroes. The time zone and fractional seconds are optional,
9311         however, a decimal point with nothing following it is invalid.
9312         Also, while $(LREF toSimpleString) will never generate a
9313         string with more than 7 digits in the fractional seconds (because that's
9314         the limit with hecto-nanosecond precision), it will allow more than 7
9315         digits in order to read strings from other sources that have higher
9316         precision (however, any digits beyond 7 will be truncated).
9317 
9318         If there is no time zone in the string, then
9319         $(REF LocalTime,std,datetime,timezone) is used. If the time zone is "Z",
9320         then `UTC` is used. Otherwise, a
9321         $(REF SimpleTimeZone,std,datetime,timezone) which corresponds to the
9322         given offset from UTC is used. To get the returned $(LREF SysTime) to be
9323         a particular time zone, pass in that time zone and the $(LREF SysTime)
9324         to be returned will be converted to that time zone (though it will still
9325         be read in as whatever time zone is in its string).
9326 
9327         The accepted formats for time zone offsets are +HH, -HH, +HH:MM, and
9328         -HH:MM.
9329 
9330         Params:
9331             simpleString = A string formatted in the way that
9332                            `toSimpleString` formats dates and times.
9333             tz           = The time zone to convert the given time to (no
9334                            conversion occurs if null).
9335 
9336         Throws:
9337             $(REF DateTimeException,std,datetime,date) if the given string is
9338             not in the ISO format or if the resulting $(LREF SysTime) would not
9339             be valid.
9340       +/
9341     static SysTime fromSimpleString(S)(scope const S simpleString, immutable TimeZone tz = null) @safe
9342         if (isSomeString!(S))
9343     {
9344         import std.algorithm.searching : find;
9345         import std.conv : to;
9346         import std.string : strip, indexOf;
9347 
9348         auto str = strip(simpleString);
9349 
9350         auto spaceIndex = str.indexOf(' ');
9351         enforce(spaceIndex != -1, new DateTimeException(format("Invalid Simple String: %s", simpleString)));
9352 
9353         auto found = str[spaceIndex + 1 .. $].find('.', 'Z', '+', '-');
9354         auto dateTimeStr = str[0 .. $ - found[0].length];
9355 
9356         typeof(str) foundTZ;  // needs to have longer lifetime than zoneStr
9357         typeof(str) fracSecStr;
9358         typeof(str) zoneStr;
9359 
9360         if (found[1] != 0)
9361         {
9362             if (found[1] == 1)
9363             {
9364                 foundTZ = found[0].find('Z', '+', '-')[0];
9365 
9366                 if (foundTZ.length != 0)
9367                 {
9368                     fracSecStr = found[0][0 .. $ - foundTZ.length];
9369                     zoneStr = foundTZ;
9370                 }
9371                 else
9372                     fracSecStr = found[0];
9373             }
9374             else
9375                 zoneStr = found[0];
9376         }
9377 
9378         try
9379         {
9380             auto dateTime = DateTime.fromSimpleString(dateTimeStr);
9381             auto fracSec = fracSecsFromISOString(fracSecStr);
9382             Rebindable!(immutable TimeZone) parsedZone;
9383 
9384             if (zoneStr.empty)
9385                 parsedZone = LocalTime();
9386             else if (zoneStr == "Z")
9387                 parsedZone = UTC();
9388             else
9389                 parsedZone = SimpleTimeZone.fromISOExtString(zoneStr);
9390 
9391             auto retval = SysTime(dateTime, fracSec, parsedZone);
9392 
9393             if (tz !is null)
9394                 retval.timezone = tz;
9395 
9396             return retval;
9397         }
9398         catch (DateTimeException dte)
9399             throw new DateTimeException(format("Invalid Simple String: %s", simpleString));
9400     }
9401 
9402     ///
9403     @safe unittest
9404     {
9405         import core.time : hours, msecs, usecs, hnsecs;
9406         import std.datetime.date : DateTime;
9407         import std.datetime.timezone : SimpleTimeZone, UTC;
9408 
9409         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12") ==
9410                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9411 
9412         assert(SysTime.fromSimpleString("1998-Dec-25 02:15:00.007") ==
9413                SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7)));
9414 
9415         assert(SysTime.fromSimpleString("0000-Jan-05 23:09:59.00002") ==
9416                SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20)));
9417 
9418         assert(SysTime.fromSimpleString("2013-Feb-07 04:39:37.000050392") ==
9419                SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503)));
9420 
9421         assert(SysTime.fromSimpleString("-0004-Jan-05 00:00:02") ==
9422                SysTime(DateTime(-4, 1, 5, 0, 0, 2)));
9423 
9424         assert(SysTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") ==
9425                SysTime(DateTime(2010, 7, 4, 7, 6, 12)));
9426 
9427         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12Z") ==
9428                SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC()));
9429 
9430         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12-08:00") ==
9431                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9432                        new immutable SimpleTimeZone(hours(-8))));
9433 
9434         assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12+08:00") ==
9435                SysTime(DateTime(2010, 7, 4, 7, 6, 12),
9436                        new immutable SimpleTimeZone(hours(8))));
9437     }
9438 
9439     @safe unittest
9440     {
9441         import core.time;
9442         foreach (str; ["", "20100704000000", "20100704 000000",
9443                        "20100704t000000", "20100704T000000.", "20100704T000000.0",
9444                        "2010-07-0400:00:00", "2010-07-04 00:00:00", "2010-07-04t00:00:00",
9445                        "2010-07-04T00:00:00.", "2010-07-04T00:00:00.0",
9446                        "2010-Jul-0400:00:00", "2010-Jul-04t00:00:00", "2010-Jul-04T00:00:00",
9447                        "2010-Jul-04 00:00:00.", "2010-Jul-04 00:00:00.A", "2010-Jul-04 00:00:00.Z",
9448                        "2010-Jul-04 00:00:00.0000000A", "2010-Jul-04 00:00:00.00000000A",
9449                        "2010-Jul-04 00:00:00+", "2010-Jul-04 00:00:00-",
9450                        "2010-Jul-04 00:00:00:", "2010-Jul-04 00:00:00-:",
9451                        "2010-Jul-04 00:00:00+:", "2010-Jul-04 00:00:00-1:",
9452                        "2010-Jul-04 00:00:00+1:", "2010-Jul-04 00:00:00+1:0",
9453                        "2010-Jul-04 00:00:00-12.00", "2010-Jul-04 00:00:00+12.00",
9454                        "2010-Jul-04 00:00:00-8", "2010-Jul-04 00:00:00+8",
9455                        "20100704T000000-800", "20100704T000000+800",
9456                        "20100704T000000-080", "20100704T000000+080",
9457                        "20100704T000000-2400", "20100704T000000+2400",
9458                        "20100704T000000-1260", "20100704T000000+1260",
9459                        "20100704T000000.0-800", "20100704T000000.0+800",
9460                        "20100704T000000.0-8", "20100704T000000.0+8",
9461                        "20100704T000000.0-080", "20100704T000000.0+080",
9462                        "20100704T000000.0-2400", "20100704T000000.0+2400",
9463                        "20100704T000000.0-1260", "20100704T000000.0+1260",
9464                        "2010-Jul-04 00:00:00-8:00", "2010-Jul-04 00:00:00+8:00",
9465                        "2010-Jul-04 00:00:00-08:0", "2010-Jul-04 00:00:00+08:0",
9466                        "2010-Jul-04 00:00:00-24:00", "2010-Jul-04 00:00:00+24:00",
9467                        "2010-Jul-04 00:00:00-12:60", "2010-Jul-04 00:00:00+24:60",
9468                        "2010-Jul-04 00:00:00.0-8:00", "2010-Jul-04 00:00:00+8:00",
9469                        "2010-Jul-04 00:00:00.0-8", "2010-Jul-04 00:00:00.0+8",
9470                        "2010-Jul-04 00:00:00.0-08:0", "2010-Jul-04 00:00:00.0+08:0",
9471                        "2010-Jul-04 00:00:00.0-24:00", "2010-Jul-04 00:00:00.0+24:00",
9472                        "2010-Jul-04 00:00:00.0-12:60", "2010-Jul-04 00:00:00.0+24:60",
9473                        "20101222T172201", "2010-12-22T172201"])
9474         {
9475             assertThrown!DateTimeException(SysTime.fromSimpleString(str), format("[%s]", str));
9476         }
9477 
9478         static void test(string str, SysTime st, size_t line = __LINE__)
9479         {
9480             if (SysTime.fromSimpleString(str) != st)
9481                 throw new AssertError("unittest failure", __FILE__, line);
9482         }
9483 
9484         test("2010-Dec-22 17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 1)));
9485         test("1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9486         test("-1999-Jul-06 12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
9487         test("+01999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9488         test("1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9489         test(" 1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9490         test(" 1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
9491 
9492         test("1907-Jul-07 12:12:12.0", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9493         test("1907-Jul-07 12:12:12.0000000", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
9494         test("2010-Jul-04 00:00:00.00000000", SysTime(Date(2010, 7, 4)));
9495         test("2010-Jul-04 00:00:00.00000009", SysTime(Date(2010, 7, 4)));
9496         test("2010-Jul-04 00:00:00.00000019", SysTime(DateTime(2010, 7, 4), hnsecs(1)));
9497         test("1907-Jul-07 12:12:12.0000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), hnsecs(1)));
9498         test("1907-Jul-07 12:12:12.000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9499         test("1907-Jul-07 12:12:12.0000010", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
9500         test("1907-Jul-07 12:12:12.001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9501         test("1907-Jul-07 12:12:12.0010000", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
9502 
9503         auto west60 = new immutable SimpleTimeZone(hours(-1));
9504         auto west90 = new immutable SimpleTimeZone(minutes(-90));
9505         auto west480 = new immutable SimpleTimeZone(hours(-8));
9506         auto east60 = new immutable SimpleTimeZone(hours(1));
9507         auto east90 = new immutable SimpleTimeZone(minutes(90));
9508         auto east480 = new immutable SimpleTimeZone(hours(8));
9509 
9510         test("2010-Dec-22 17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), UTC()));
9511         test("2010-Dec-22 17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9512         test("2010-Dec-22 17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
9513         test("2010-Dec-22 17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
9514         test("2010-Dec-22 17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
9515         test("2010-Dec-22 17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9516         test("2010-Dec-22 17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9517         test("2010-Dec-22 17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9518         test("2010-Dec-22 17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
9519 
9520         test("2010-Nov-03 06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
9521         test("2010-Dec-22 17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_341_200), UTC()));
9522         test("2010-Dec-22 17:22:01.23112-01:00",
9523              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
9524         test("2010-Dec-22 17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), west60));
9525         test("2010-Dec-22 17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
9526         test("2010-Dec-22 17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
9527         test("2010-Dec-22 17:22:01.1234567+01:00",
9528              SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
9529         test("2010-Dec-22 17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
9530         test("2010-Dec-22 17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
9531         test("2010-Dec-22 17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
9532 
9533         static void testScope(scope ref string str) @safe
9534         {
9535             auto result = SysTime.fromSimpleString(str);
9536         }
9537     }
9538 
9539     // https://issues.dlang.org/show_bug.cgi?id=17801
9540     @safe unittest
9541     {
9542         import core.time;
9543         import std.conv : to;
9544         import std.meta : AliasSeq;
9545         static foreach (C; AliasSeq!(char, wchar, dchar))
9546         {
9547             static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
9548             {
9549                 assert(SysTime.fromSimpleString(to!S("2012-Dec-21 14:15:16Z")) ==
9550                        SysTime(DateTime(2012, 12, 21, 14, 15, 16), UTC()));
9551             }
9552         }
9553     }
9554 
9555 
9556     /++
9557         Returns the $(LREF SysTime) farthest in the past which is representable
9558         by $(LREF SysTime).
9559 
9560         The $(LREF SysTime) which is returned is in UTC.
9561       +/
9562     @property static SysTime min() @safe pure nothrow
9563     {
9564         return SysTime(long.min, UTC());
9565     }
9566 
9567     @safe unittest
9568     {
9569         assert(SysTime.min.year < 0);
9570         assert(SysTime.min < SysTime.max);
9571     }
9572 
9573 
9574     /++
9575         Returns the $(LREF SysTime) farthest in the future which is representable
9576         by $(LREF SysTime).
9577 
9578         The $(LREF SysTime) which is returned is in UTC.
9579       +/
9580     @property static SysTime max() @safe pure nothrow
9581     {
9582         return SysTime(long.max, UTC());
9583     }
9584 
9585     @safe unittest
9586     {
9587         assert(SysTime.max.year > 0);
9588         assert(SysTime.max > SysTime.min);
9589     }
9590 
9591 
9592 private:
9593 
9594     /+
9595         Returns `stdTime` converted to $(LREF SysTime)'s time zone.
9596       +/
9597     @property long adjTime() @safe const nothrow scope
9598     {
9599         return _timezone.utcToTZ(_stdTime);
9600     }
9601 
9602 
9603     /+
9604         Converts the given hnsecs from $(LREF SysTime)'s time zone to std time.
9605       +/
9606     @property void adjTime(long adjTime) @safe nothrow scope
9607     {
9608         _stdTime = _timezone.tzToUTC(adjTime);
9609     }
9610 
9611 
9612     final class InitTimeZone : TimeZone
9613     {
9614     public:
9615 
9616         static immutable(InitTimeZone) opCall() @safe pure nothrow @nogc { return _initTimeZone; }
9617 
9618         @property override bool hasDST() @safe const nothrow @nogc { return false; }
9619 
9620         override bool dstInEffect(long stdTime) @safe const scope nothrow @nogc { return false; }
9621 
9622         override long utcToTZ(long stdTime) @safe const scope nothrow @nogc { return 0; }
9623 
9624         override long tzToUTC(long adjTime) @safe const scope nothrow @nogc { return 0; }
9625 
9626         override Duration utcOffsetAt(long stdTime) @safe const scope nothrow @nogc { return Duration.zero; }
9627 
9628     private:
9629 
9630         this() @safe immutable pure
9631         {
9632             super("SysTime.init's timezone", "SysTime.init's timezone", "SysTime.init's timezone");
9633         }
9634 
9635         static immutable InitTimeZone _initTimeZone = new immutable(InitTimeZone);
9636     }
9637 
9638     // https://issues.dlang.org/show_bug.cgi?id=17732
9639     @safe unittest
9640     {
9641         assert(SysTime.init.timezone is InitTimeZone());
9642         assert(SysTime.init.toISOString() == "00010101T000000+00:00");
9643         assert(SysTime.init.toISOExtString() == "0001-01-01T00:00:00+00:00");
9644         assert(SysTime.init.toSimpleString() == "0001-Jan-01 00:00:00+00:00");
9645         assert(SysTime.init.toString() == "0001-Jan-01 00:00:00+00:00");
9646     }
9647 
9648     // Assigning a value to _timezone in SysTime.init currently doesn't work due
9649     // to https://issues.dlang.org/show_bug.cgi?id=17740. So, to hack around
9650     // that problem, these accessors have been added so that we can insert a
9651     // runtime check for null and then use InitTimeZone for SysTime.init (which
9652     // which is the only case where _timezone would be null). This thus fixes
9653     // the problem with segfaulting when using SysTime.init but at the cost of
9654     // what should be an unnecessary null check. Once 17740 has finally been
9655     // fixed, _timezoneStorage should be removed, these accessors should be
9656     // removed, and the _timezone variable declaration should be restored.
9657     pragma(inline, true) @property _timezone() @safe const pure nothrow @nogc
9658     {
9659         return _timezoneStorage is null ? InitTimeZone() : _timezoneStorage;
9660     }
9661 
9662     pragma(inline, true) @property void _timezone(return scope immutable TimeZone tz) @safe pure nothrow @nogc scope
9663     {
9664         _timezoneStorage = tz;
9665     }
9666 
9667 
9668     long  _stdTime;
9669     Rebindable!(immutable TimeZone) _timezoneStorage;
9670     //Rebindable!(immutable TimeZone) _timezone = InitTimeZone();
9671 }
9672 
9673 ///
9674 @safe unittest
9675 {
9676     import core.time : days, hours, seconds;
9677     import std.datetime.date : DateTime;
9678     import std.datetime.timezone : SimpleTimeZone, UTC;
9679 
9680     // make a specific point in time in the UTC timezone
9681     auto st = SysTime(DateTime(2018, 1, 1, 10, 30, 0), UTC());
9682     // make a specific point in time in the New York timezone
9683     auto ny = SysTime(
9684         DateTime(2018, 1, 1, 10, 30, 0),
9685         new immutable SimpleTimeZone(-5.hours, "America/New_York")
9686     );
9687 
9688     // ISO standard time strings
9689     assert(st.toISOString() == "20180101T103000Z");
9690     assert(st.toISOExtString() == "2018-01-01T10:30:00Z");
9691 
9692     // add two days and 30 seconds
9693     st += 2.days + 30.seconds;
9694     assert(st.toISOExtString() == "2018-01-03T10:30:30Z");
9695 }
9696 
9697 
9698 /++
9699     Converts from unix time (which uses midnight, January 1st, 1970 UTC as its
9700     epoch and seconds as its units) to "std time" (which uses midnight,
9701     January 1st, 1 A.D. UTC and hnsecs as its units).
9702 
9703     The C standard does not specify the representation of time_t, so it is
9704     implementation defined. On POSIX systems, unix time is equivalent to
9705     time_t, but that's not necessarily true on other systems (e.g. it is
9706     not true for the Digital Mars C runtime). So, be careful when using unix
9707     time with C functions on non-POSIX systems.
9708 
9709     "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO
9710     8601 and is what $(LREF SysTime) uses internally. However, holding the time
9711     as an integer in hnsecs since that epoch technically isn't actually part of
9712     the standard, much as it's based on it, so the name "std time" isn't
9713     particularly good, but there isn't an official name for it. C# uses "ticks"
9714     for the same thing, but they aren't actually clock ticks, and the term
9715     "ticks" $(I is) used for actual clock ticks for $(REF MonoTime, core,time),
9716     so it didn't make sense to use the term ticks here. So, for better or worse,
9717     std.datetime uses the term "std time" for this.
9718 
9719     Params:
9720         unixTime = The unix time to convert.
9721 
9722     See_Also:
9723         SysTime.fromUnixTime
9724   +/
9725 long unixTimeToStdTime(long unixTime) @safe pure nothrow @nogc
9726 {
9727     return 621_355_968_000_000_000L + convert!("seconds", "hnsecs")(unixTime);
9728 }
9729 
9730 ///
9731 @safe unittest
9732 {
9733     import std.datetime.date : DateTime;
9734     import std.datetime.timezone : UTC;
9735 
9736     // Midnight, January 1st, 1970
9737     assert(unixTimeToStdTime(0) == 621_355_968_000_000_000L);
9738     assert(SysTime(unixTimeToStdTime(0)) ==
9739            SysTime(DateTime(1970, 1, 1), UTC()));
9740 
9741     assert(unixTimeToStdTime(int.max) == 642_830_804_470_000_000L);
9742     assert(SysTime(unixTimeToStdTime(int.max)) ==
9743            SysTime(DateTime(2038, 1, 19, 3, 14, 7), UTC()));
9744 
9745     assert(unixTimeToStdTime(-127_127) == 621_354_696_730_000_000L);
9746     assert(SysTime(unixTimeToStdTime(-127_127)) ==
9747            SysTime(DateTime(1969, 12, 30, 12, 41, 13), UTC()));
9748 }
9749 
9750 @safe unittest
9751 {
9752     // Midnight, January 2nd, 1970
9753     assert(unixTimeToStdTime(86_400) == 621_355_968_000_000_000L + 864_000_000_000L);
9754     // Midnight, December 31st, 1969
9755     assert(unixTimeToStdTime(-86_400) == 621_355_968_000_000_000L - 864_000_000_000L);
9756 
9757     assert(unixTimeToStdTime(0) == (Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs");
9758     assert(unixTimeToStdTime(0) == (DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs");
9759 
9760     foreach (dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)])
9761         assert(unixTimeToStdTime((dt - DateTime(1970, 1, 1)).total!"seconds") == (dt - DateTime.init).total!"hnsecs");
9762 }
9763 
9764 
9765 /++
9766     Converts std time (which uses midnight, January 1st, 1 A.D. UTC as its epoch
9767     and hnsecs as its units) to unix time (which uses midnight, January 1st,
9768     1970 UTC as its epoch and seconds as its units).
9769 
9770     The C standard does not specify the representation of time_t, so it is
9771     implementation defined. On POSIX systems, unix time is equivalent to
9772     time_t, but that's not necessarily true on other systems (e.g. it is
9773     not true for the Digital Mars C runtime). So, be careful when using unix
9774     time with C functions on non-POSIX systems.
9775 
9776     "std time"'s epoch is based on the Proleptic Gregorian Calendar per ISO
9777     8601 and is what $(LREF SysTime) uses internally. However, holding the time
9778     as an integer in hnescs since that epoch technically isn't actually part of
9779     the standard, much as it's based on it, so the name "std time" isn't
9780     particularly good, but there isn't an official name for it. C# uses "ticks"
9781     for the same thing, but they aren't actually clock ticks, and the term
9782     "ticks" $(I is) used for actual clock ticks for $(REF MonoTime, core,time),
9783     so it didn't make sense to use the term ticks here. So, for better or worse,
9784     std.datetime uses the term "std time" for this.
9785 
9786     By default, the return type is time_t (which is normally an alias for
9787     int on 32-bit systems and long on 64-bit systems), but if a different
9788     size is required than either int or long can be passed as a template
9789     argument to get the desired size.
9790 
9791     If the return type is int, and the result can't fit in an int, then the
9792     closest value that can be held in 32 bits will be used (so `int.max`
9793     if it goes over and `int.min` if it goes under). However, no attempt
9794     is made to deal with integer overflow if the return type is long.
9795 
9796     Params:
9797         T = The return type (int or long). It defaults to time_t, which is
9798             normally 32 bits on a 32-bit system and 64 bits on a 64-bit
9799             system.
9800         stdTime = The std time to convert.
9801 
9802     Returns:
9803         A signed integer representing the unix time which is equivalent to
9804         the given std time.
9805 
9806     See_Also:
9807         SysTime.toUnixTime
9808   +/
9809 T stdTimeToUnixTime(T = time_t)(long stdTime) @safe pure nothrow
9810 if (is(T == int) || is(T == long))
9811 {
9812     immutable unixTime = convert!("hnsecs", "seconds")(stdTime - 621_355_968_000_000_000L);
9813 
9814     static assert(is(time_t == int) || is(time_t == long),
9815                   "Currently, std.datetime only supports systems where time_t is int or long");
9816 
9817     static if (is(T == long))
9818         return unixTime;
9819     else static if (is(T == int))
9820     {
9821         if (unixTime > int.max)
9822             return int.max;
9823         return unixTime < int.min ? int.min : cast(int) unixTime;
9824     }
9825     else
9826         static assert(0, "Bug in template constraint. Only int and long allowed.");
9827 }
9828 
9829 ///
9830 @safe unittest
9831 {
9832     // Midnight, January 1st, 1970 UTC
9833     assert(stdTimeToUnixTime(621_355_968_000_000_000L) == 0);
9834 
9835     // 2038-01-19 03:14:07 UTC
9836     assert(stdTimeToUnixTime(642_830_804_470_000_000L) == int.max);
9837 }
9838 
9839 @safe unittest
9840 {
9841     enum unixEpochAsStdTime = (Date(1970, 1, 1) - Date.init).total!"hnsecs";
9842 
9843     assert(stdTimeToUnixTime(unixEpochAsStdTime) == 0);  // Midnight, January 1st, 1970
9844     assert(stdTimeToUnixTime(unixEpochAsStdTime + 864_000_000_000L) == 86_400);  // Midnight, January 2nd, 1970
9845     assert(stdTimeToUnixTime(unixEpochAsStdTime - 864_000_000_000L) == -86_400);  // Midnight, December 31st, 1969
9846 
9847     assert(stdTimeToUnixTime((Date(1970, 1, 1) - Date(1, 1, 1)).total!"hnsecs") == 0);
9848     assert(stdTimeToUnixTime((DateTime(1970, 1, 1) - DateTime(1, 1, 1)).total!"hnsecs") == 0);
9849 
9850     foreach (dt; [DateTime(2010, 11, 1, 19, 5, 22), DateTime(1952, 7, 6, 2, 17, 9)])
9851         assert(stdTimeToUnixTime((dt - DateTime.init).total!"hnsecs") == (dt - DateTime(1970, 1, 1)).total!"seconds");
9852 
9853     enum max = convert!("seconds", "hnsecs")(int.max);
9854     enum min = convert!("seconds", "hnsecs")(int.min);
9855     enum one = convert!("seconds", "hnsecs")(1);
9856 
9857     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max) == int.max);
9858     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max) == int.max);
9859 
9860     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + one) == int.max + 1L);
9861     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + one) == int.max);
9862     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + max + 9_999_999) == int.max);
9863     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + max + 9_999_999) == int.max);
9864 
9865     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min) == int.min);
9866     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min) == int.min);
9867 
9868     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - one) == int.min - 1L);
9869     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - one) == int.min);
9870     assert(stdTimeToUnixTime!long(unixEpochAsStdTime + min - 9_999_999) == int.min);
9871     assert(stdTimeToUnixTime!int(unixEpochAsStdTime + min - 9_999_999) == int.min);
9872 }
9873 
9874 
9875 version (StdDdoc)
9876 {
9877     version (Windows)
9878     {}
9879     else
9880     {
9881         alias SYSTEMTIME = void*;
9882         alias FILETIME = void*;
9883     }
9884 
9885     /++
9886         $(BLUE This function is Windows-Only.)
9887 
9888         Converts a `SYSTEMTIME` struct to a $(LREF SysTime).
9889 
9890         Params:
9891             st = The `SYSTEMTIME` struct to convert.
9892             tz = The time zone that the time in the `SYSTEMTIME` struct is
9893                  assumed to be (if the `SYSTEMTIME` was supplied by a Windows
9894                  system call, the `SYSTEMTIME` will either be in local time
9895                  or UTC, depending on the call).
9896 
9897         Throws:
9898             $(REF DateTimeException,std,datetime,date) if the given
9899             `SYSTEMTIME` will not fit in a $(LREF SysTime), which is highly
9900             unlikely to happen given that `SysTime.max` is in 29,228 A.D. and
9901             the maximum `SYSTEMTIME` is in 30,827 A.D.
9902       +/
9903     SysTime SYSTEMTIMEToSysTime(const scope SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe;
9904 
9905 
9906     /++
9907         $(BLUE This function is Windows-Only.)
9908 
9909         Converts a $(LREF SysTime) to a `SYSTEMTIME` struct.
9910 
9911         The `SYSTEMTIME` which is returned will be set using the given
9912         $(LREF SysTime)'s time zone, so to get the `SYSTEMTIME` in
9913         UTC, set the $(LREF SysTime)'s time zone to UTC.
9914 
9915         Params:
9916             sysTime = The $(LREF SysTime) to convert.
9917 
9918         Throws:
9919             $(REF DateTimeException,std,datetime,date) if the given
9920             $(LREF SysTime) will not fit in a `SYSTEMTIME`. This will only
9921             happen if the $(LREF SysTime)'s date is prior to 1601 A.D.
9922       +/
9923     SYSTEMTIME SysTimeToSYSTEMTIME(scope SysTime sysTime) @safe;
9924 
9925 
9926     /++
9927         $(BLUE This function is Windows-Only.)
9928 
9929         Converts a `FILETIME` struct to the number of hnsecs since midnight,
9930         January 1st, 1 A.D.
9931 
9932         Params:
9933             ft = The `FILETIME` struct to convert.
9934 
9935         Throws:
9936             $(REF DateTimeException,std,datetime,date) if the given
9937             `FILETIME` cannot be represented as the return value.
9938       +/
9939     long FILETIMEToStdTime(scope const FILETIME* ft) @safe;
9940 
9941 
9942     /++
9943         $(BLUE This function is Windows-Only.)
9944 
9945         Converts a `FILETIME` struct to a $(LREF SysTime).
9946 
9947         Params:
9948             ft = The `FILETIME` struct to convert.
9949             tz = The time zone that the $(LREF SysTime) will be in
9950                  (`FILETIME`s are in UTC).
9951 
9952         Throws:
9953             $(REF DateTimeException,std,datetime,date) if the given
9954             `FILETIME` will not fit in a $(LREF SysTime).
9955       +/
9956     SysTime FILETIMEToSysTime(scope const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe;
9957 
9958 
9959     /++
9960         $(BLUE This function is Windows-Only.)
9961 
9962         Converts a number of hnsecs since midnight, January 1st, 1 A.D. to a
9963         `FILETIME` struct.
9964 
9965         Params:
9966             stdTime = The number of hnsecs since midnight, January 1st, 1 A.D.
9967                       UTC.
9968 
9969         Throws:
9970             $(REF DateTimeException,std,datetime,date) if the given value will
9971             not fit in a `FILETIME`.
9972       +/
9973     FILETIME stdTimeToFILETIME(long stdTime) @safe;
9974 
9975 
9976     /++
9977         $(BLUE This function is Windows-Only.)
9978 
9979         Converts a $(LREF SysTime) to a `FILETIME` struct.
9980 
9981         `FILETIME`s are always in UTC.
9982 
9983         Params:
9984             sysTime = The $(LREF SysTime) to convert.
9985 
9986         Throws:
9987             $(REF DateTimeException,std,datetime,date) if the given
9988             $(LREF SysTime) will not fit in a `FILETIME`.
9989       +/
9990     FILETIME SysTimeToFILETIME(scope SysTime sysTime) @safe;
9991 }
9992 else version (Windows)
9993 {
9994     SysTime SYSTEMTIMEToSysTime(const scope SYSTEMTIME* st, immutable TimeZone tz = LocalTime()) @safe
9995     {
9996         const max = SysTime.max;
9997 
9998         static void throwLaterThanMax()
9999         {
10000             throw new DateTimeException("The given SYSTEMTIME is for a date greater than SysTime.max.");
10001         }
10002 
10003         if (st.wYear > max.year)
10004             throwLaterThanMax();
10005         else if (st.wYear == max.year)
10006         {
10007             if (st.wMonth > max.month)
10008                 throwLaterThanMax();
10009             else if (st.wMonth == max.month)
10010             {
10011                 if (st.wDay > max.day)
10012                     throwLaterThanMax();
10013                 else if (st.wDay == max.day)
10014                 {
10015                     if (st.wHour > max.hour)
10016                         throwLaterThanMax();
10017                     else if (st.wHour == max.hour)
10018                     {
10019                         if (st.wMinute > max.minute)
10020                             throwLaterThanMax();
10021                         else if (st.wMinute == max.minute)
10022                         {
10023                             if (st.wSecond > max.second)
10024                                 throwLaterThanMax();
10025                             else if (st.wSecond == max.second)
10026                             {
10027                                 if (st.wMilliseconds > max.fracSecs.total!"msecs")
10028                                     throwLaterThanMax();
10029                             }
10030                         }
10031                     }
10032                 }
10033             }
10034         }
10035 
10036         auto dt = DateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
10037 
10038         import core.time : msecs;
10039         return SysTime(dt, msecs(st.wMilliseconds), tz);
10040     }
10041 
10042     @system unittest
10043     {
10044         auto sysTime = Clock.currTime(UTC());
10045         SYSTEMTIME st = void;
10046         GetSystemTime(&st);
10047         auto converted = SYSTEMTIMEToSysTime(&st, UTC());
10048         import core.time : abs;
10049         assert(abs((converted - sysTime)) <= dur!"seconds"(2));
10050 
10051         static void testScope(scope SYSTEMTIME* st) @safe
10052         {
10053             auto result = SYSTEMTIMEToSysTime(st);
10054         }
10055     }
10056 
10057 
10058     SYSTEMTIME SysTimeToSYSTEMTIME(scope SysTime sysTime) @safe
10059     {
10060         immutable dt = cast(DateTime) sysTime;
10061 
10062         if (dt.year < 1601)
10063             throw new DateTimeException("SYSTEMTIME cannot hold dates prior to the year 1601.");
10064 
10065         SYSTEMTIME st;
10066 
10067         st.wYear = dt.year;
10068         st.wMonth = dt.month;
10069         st.wDayOfWeek = dt.dayOfWeek;
10070         st.wDay = dt.day;
10071         st.wHour = dt.hour;
10072         st.wMinute = dt.minute;
10073         st.wSecond = dt.second;
10074         st.wMilliseconds = cast(ushort) sysTime.fracSecs.total!"msecs";
10075 
10076         return st;
10077     }
10078 
10079     @system unittest
10080     {
10081         SYSTEMTIME st = void;
10082         GetSystemTime(&st);
10083         auto sysTime = SYSTEMTIMEToSysTime(&st, UTC());
10084 
10085         SYSTEMTIME result = SysTimeToSYSTEMTIME(sysTime);
10086 
10087         assert(st.wYear == result.wYear);
10088         assert(st.wMonth == result.wMonth);
10089         assert(st.wDayOfWeek == result.wDayOfWeek);
10090         assert(st.wDay == result.wDay);
10091         assert(st.wHour == result.wHour);
10092         assert(st.wMinute == result.wMinute);
10093         assert(st.wSecond == result.wSecond);
10094         assert(st.wMilliseconds == result.wMilliseconds);
10095 
10096         static void testScope(scope ref SysTime st) @safe
10097         {
10098             auto localResult = SysTimeToSYSTEMTIME(st);
10099         }
10100     }
10101 
10102     private enum hnsecsFrom1601 = 504_911_232_000_000_000L;
10103 
10104     long FILETIMEToStdTime(scope const FILETIME* ft) @safe
10105     {
10106         ULARGE_INTEGER ul;
10107         ul.HighPart = ft.dwHighDateTime;
10108         ul.LowPart = ft.dwLowDateTime;
10109         ulong tempHNSecs = ul.QuadPart;
10110 
10111         if (tempHNSecs > long.max - hnsecsFrom1601)
10112             throw new DateTimeException("The given FILETIME cannot be represented as a stdTime value.");
10113 
10114         return cast(long) tempHNSecs + hnsecsFrom1601;
10115     }
10116 
10117     SysTime FILETIMEToSysTime(scope const FILETIME* ft, immutable TimeZone tz = LocalTime()) @safe
10118     {
10119         auto sysTime = SysTime(FILETIMEToStdTime(ft), UTC());
10120         sysTime.timezone = tz;
10121         return sysTime;
10122     }
10123 
10124     @system unittest
10125     {
10126         auto sysTime = Clock.currTime(UTC());
10127         SYSTEMTIME st = void;
10128         GetSystemTime(&st);
10129 
10130         FILETIME ft = void;
10131         SystemTimeToFileTime(&st, &ft);
10132 
10133         auto converted = FILETIMEToSysTime(&ft);
10134 
10135         import core.time : abs;
10136         assert(abs((converted - sysTime)) <= dur!"seconds"(2));
10137 
10138         static void testScope(scope FILETIME* ft) @safe
10139         {
10140             auto result = FILETIMEToSysTime(ft);
10141         }
10142     }
10143 
10144 
10145     FILETIME stdTimeToFILETIME(long stdTime) @safe
10146     {
10147         if (stdTime < hnsecsFrom1601)
10148             throw new DateTimeException("The given stdTime value cannot be represented as a FILETIME.");
10149 
10150         ULARGE_INTEGER ul;
10151         ul.QuadPart = cast(ulong) stdTime - hnsecsFrom1601;
10152 
10153         FILETIME ft;
10154         ft.dwHighDateTime = ul.HighPart;
10155         ft.dwLowDateTime = ul.LowPart;
10156 
10157         return ft;
10158     }
10159 
10160     FILETIME SysTimeToFILETIME(scope SysTime sysTime) @safe
10161     {
10162         return stdTimeToFILETIME(sysTime.stdTime);
10163     }
10164 
10165     @system unittest
10166     {
10167         SYSTEMTIME st = void;
10168         GetSystemTime(&st);
10169 
10170         FILETIME ft = void;
10171         SystemTimeToFileTime(&st, &ft);
10172         auto sysTime = FILETIMEToSysTime(&ft, UTC());
10173 
10174         FILETIME result = SysTimeToFILETIME(sysTime);
10175 
10176         assert(ft.dwLowDateTime == result.dwLowDateTime);
10177         assert(ft.dwHighDateTime == result.dwHighDateTime);
10178 
10179         static void testScope(scope ref SysTime st) @safe
10180         {
10181             auto local_result = SysTimeToFILETIME(st);
10182         }
10183     }
10184 }
10185 
10186 
10187 /++
10188     Type representing the DOS file date/time format.
10189   +/
10190 alias DosFileTime = uint;
10191 
10192 /++
10193     Converts from DOS file date/time to $(LREF SysTime).
10194 
10195     Params:
10196         dft = The DOS file time to convert.
10197         tz  = The time zone which the DOS file time is assumed to be in.
10198 
10199     Throws:
10200         $(REF DateTimeException,std,datetime,date) if the `DosFileTime` is
10201         invalid.
10202   +/
10203 SysTime DosFileTimeToSysTime(DosFileTime dft, immutable TimeZone tz = LocalTime()) @safe
10204 {
10205     uint dt = cast(uint) dft;
10206 
10207     if (dt == 0)
10208         throw new DateTimeException("Invalid DosFileTime.");
10209 
10210     int year = ((dt >> 25) & 0x7F) + 1980;
10211     int month = ((dt >> 21) & 0x0F);       // 1 .. 12
10212     int dayOfMonth = ((dt >> 16) & 0x1F);  // 1 .. 31
10213     int hour = (dt >> 11) & 0x1F;          // 0 .. 23
10214     int minute = (dt >> 5) & 0x3F;         // 0 .. 59
10215     int second = (dt << 1) & 0x3E;         // 0 .. 58 (in 2 second increments)
10216 
10217     try
10218         return SysTime(DateTime(year, month, dayOfMonth, hour, minute, second), tz);
10219     catch (DateTimeException dte)
10220         throw new DateTimeException("Invalid DosFileTime", __FILE__, __LINE__, dte);
10221 }
10222 
10223 ///
10224 @safe unittest
10225 {
10226     import std.datetime.date : DateTime;
10227 
10228     assert(DosFileTimeToSysTime(0b00000000001000010000000000000000) == SysTime(DateTime(1980, 1, 1, 0, 0, 0)));
10229     assert(DosFileTimeToSysTime(0b11111111100111111011111101111101) == SysTime(DateTime(2107, 12, 31, 23, 59, 58)));
10230     assert(DosFileTimeToSysTime(0x3E3F8456) == SysTime(DateTime(2011, 1, 31, 16, 34, 44)));
10231 }
10232 
10233 @safe unittest
10234 {
10235     static void testScope(scope ref DosFileTime dft) @safe
10236     {
10237         auto result = DosFileTimeToSysTime(dft);
10238     }
10239 }
10240 
10241 
10242 /++
10243     Converts from $(LREF SysTime) to DOS file date/time.
10244 
10245     Params:
10246         sysTime = The $(LREF SysTime) to convert.
10247 
10248     Throws:
10249         $(REF DateTimeException,std,datetime,date) if the given
10250         $(LREF SysTime) cannot be converted to a `DosFileTime`.
10251   +/
10252 DosFileTime SysTimeToDosFileTime(scope SysTime sysTime) @safe
10253 {
10254     auto dateTime = cast(DateTime) sysTime;
10255 
10256     if (dateTime.year < 1980)
10257         throw new DateTimeException("DOS File Times cannot hold dates prior to 1980.");
10258 
10259     if (dateTime.year > 2107)
10260         throw new DateTimeException("DOS File Times cannot hold dates past 2107.");
10261 
10262     uint retval = 0;
10263     retval = (dateTime.year - 1980) << 25;
10264     retval |= (dateTime.month & 0x0F) << 21;
10265     retval |= (dateTime.day & 0x1F) << 16;
10266     retval |= (dateTime.hour & 0x1F) << 11;
10267     retval |= (dateTime.minute & 0x3F) << 5;
10268     retval |= (dateTime.second >> 1) & 0x1F;
10269 
10270     return cast(DosFileTime) retval;
10271 }
10272 
10273 ///
10274 @safe unittest
10275 {
10276     import std.datetime.date : DateTime;
10277 
10278     assert(SysTimeToDosFileTime(SysTime(DateTime(1980, 1, 1, 0, 0, 0))) == 0b00000000001000010000000000000000);
10279     assert(SysTimeToDosFileTime(SysTime(DateTime(2107, 12, 31, 23, 59, 58))) == 0b11111111100111111011111101111101);
10280     assert(SysTimeToDosFileTime(SysTime(DateTime(2011, 1, 31, 16, 34, 44))) == 0x3E3F8456);
10281 }
10282 
10283 @safe unittest
10284 {
10285     static void testScope(scope ref SysTime st) @safe
10286     {
10287         auto result = SysTimeToDosFileTime(st);
10288     }
10289 }
10290 
10291 
10292 /++
10293     The given array of `char` or random-access range of `char` or
10294     `ubyte` is expected to be in the format specified in
10295     $(HTTP tools.ietf.org/html/rfc5322, RFC 5322) section 3.3 with the
10296     grammar rule $(I date-time). It is the date-time format commonly used in
10297     internet messages such as e-mail and HTTP. The corresponding
10298     $(LREF SysTime) will be returned.
10299 
10300     RFC 822 was the original spec (hence the function's name), whereas RFC 5322
10301     is the current spec.
10302 
10303     The day of the week is ignored beyond verifying that it's a valid day of the
10304     week, as the day of the week can be inferred from the date. It is not
10305     checked whether the given day of the week matches the actual day of the week
10306     of the given date (though it is technically invalid per the spec if the
10307     day of the week doesn't match the actual day of the week of the given date).
10308 
10309     If the time zone is `"-0000"` (or considered to be equivalent to
10310     `"-0000"` by section 4.3 of the spec), a
10311     $(REF SimpleTimeZone,std,datetime,timezone) with a utc offset of `0` is
10312     used rather than $(REF UTC,std,datetime,timezone), whereas `"+0000"` uses
10313     $(REF UTC,std,datetime,timezone).
10314 
10315     Note that because $(LREF SysTime) does not currently support having a second
10316     value of 60 (as is sometimes done for leap seconds), if the date-time value
10317     does have a value of 60 for the seconds, it is treated as 59.
10318 
10319     The one area in which this function violates RFC 5322 is that it accepts
10320     `"\n"` in folding whitespace in the place of `"\r\n"`, because the
10321     HTTP spec requires it.
10322 
10323     Throws:
10324         $(REF DateTimeException,std,datetime,date) if the given string doesn't
10325         follow the grammar for a date-time field or if the resulting
10326         $(LREF SysTime) is invalid.
10327   +/
10328 SysTime parseRFC822DateTime()(scope const char[] value) @safe
10329 {
10330     import std.string : representation;
10331     return parseRFC822DateTime(value.representation);
10332 }
10333 
10334 /++ Ditto +/
10335 SysTime parseRFC822DateTime(R)(scope R value)
10336 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
10337     (is(immutable ElementType!R == immutable char) || is(immutable ElementType!R == immutable ubyte)))
10338 {
10339     import std.algorithm.searching : find, all;
10340     import std.ascii : isDigit, isAlpha, isPrintable;
10341     import std.conv : to;
10342     import std.functional : not;
10343     import std.string : capitalize, format;
10344     import std.traits : EnumMembers, isArray;
10345     import std.typecons : Rebindable;
10346 
10347     void stripAndCheckLen(R valueBefore, size_t minLen, size_t line = __LINE__)
10348     {
10349         value = _stripCFWS(valueBefore);
10350         if (value.length < minLen)
10351             throw new DateTimeException("date-time value too short", __FILE__, line);
10352     }
10353     stripAndCheckLen(value, "7Dec1200:00A".length);
10354 
10355     static if (isArray!R && (is(ElementEncodingType!R == char) || is(ElementEncodingType!R == ubyte)))
10356     {
10357         static string sliceAsString(R str) @trusted
10358         {
10359             return cast(string) str;
10360         }
10361     }
10362     else
10363     {
10364         char[4] temp;
10365         char[] sliceAsString(R str) @trusted
10366         {
10367             size_t i = 0;
10368             foreach (c; str)
10369                 temp[i++] = cast(char) c;
10370             return temp[0 .. str.length];
10371         }
10372     }
10373 
10374     // day-of-week
10375     if (isAlpha(value[0]))
10376     {
10377         auto dowStr = sliceAsString(value[0 .. 3]);
10378         switch (dowStr)
10379         {
10380             foreach (dow; EnumMembers!DayOfWeek)
10381             {
10382                 enum dowC = capitalize(to!string(dow));
10383                 case dowC:
10384                     goto afterDoW;
10385             }
10386             default: throw new DateTimeException(format("Invalid day-of-week: %s", dowStr));
10387         }
10388 afterDoW: stripAndCheckLen(value[3 .. value.length], ",7Dec1200:00A".length);
10389         if (value[0] != ',')
10390             throw new DateTimeException("day-of-week missing comma");
10391         stripAndCheckLen(value[1 .. value.length], "7Dec1200:00A".length);
10392     }
10393 
10394     // day
10395     immutable digits = isDigit(value[1]) ? 2 : 1;
10396     immutable day = _convDigits!short(value[0 .. digits]);
10397     if (day == -1)
10398         throw new DateTimeException("Invalid day");
10399     stripAndCheckLen(value[digits .. value.length], "Dec1200:00A".length);
10400 
10401     // month
10402     Month month;
10403     {
10404         auto monStr = sliceAsString(value[0 .. 3]);
10405         switch (monStr)
10406         {
10407             foreach (mon; EnumMembers!Month)
10408             {
10409                 enum monC = capitalize(to!string(mon));
10410                 case monC:
10411                 {
10412                     month = mon;
10413                     goto afterMon;
10414                 }
10415             }
10416             default: throw new DateTimeException(format("Invalid month: %s", monStr));
10417         }
10418 afterMon: stripAndCheckLen(value[3 .. value.length], "1200:00A".length);
10419     }
10420 
10421     // year
10422     auto found = value[2 .. value.length].find!(not!(isDigit))();
10423     size_t yearLen = value.length - found.length;
10424     if (found.length == 0)
10425         throw new DateTimeException("Invalid year");
10426     if (found[0] == ':')
10427         yearLen -= 2;
10428     auto year = _convDigits!short(value[0 .. yearLen]);
10429     if (year < 1900)
10430     {
10431         if (year == -1)
10432             throw new DateTimeException("Invalid year");
10433         if (yearLen < 4)
10434         {
10435             if (yearLen == 3)
10436                 year += 1900;
10437             else if (yearLen == 2)
10438                 year += year < 50 ? 2000 : 1900;
10439             else
10440                 throw new DateTimeException("Invalid year. Too few digits.");
10441         }
10442         else
10443             throw new DateTimeException("Invalid year. Cannot be earlier than 1900.");
10444     }
10445     stripAndCheckLen(value[yearLen .. value.length], "00:00A".length);
10446 
10447     // hour
10448     immutable hour = _convDigits!short(value[0 .. 2]);
10449     stripAndCheckLen(value[2 .. value.length], ":00A".length);
10450     if (value[0] != ':')
10451         throw new DateTimeException("Invalid hour");
10452     stripAndCheckLen(value[1 .. value.length], "00A".length);
10453 
10454     // minute
10455     immutable minute = _convDigits!short(value[0 .. 2]);
10456     stripAndCheckLen(value[2 .. value.length], "A".length);
10457 
10458     // second
10459     short second;
10460     if (value[0] == ':')
10461     {
10462         stripAndCheckLen(value[1 .. value.length], "00A".length);
10463         second = _convDigits!short(value[0 .. 2]);
10464         // this is just if/until SysTime is sorted out to fully support leap seconds
10465         if (second == 60)
10466             second = 59;
10467         stripAndCheckLen(value[2 .. value.length], "A".length);
10468     }
10469 
10470     immutable(TimeZone) parseTZ(int sign)
10471     {
10472         if (value.length < 5)
10473             throw new DateTimeException("Invalid timezone");
10474         immutable zoneHours = _convDigits!short(value[1 .. 3]);
10475         immutable zoneMinutes = _convDigits!short(value[3 .. 5]);
10476         if (zoneHours == -1 || zoneMinutes == -1 || zoneMinutes > 59)
10477             throw new DateTimeException("Invalid timezone");
10478         value = value[5 .. value.length];
10479         immutable utcOffset = (dur!"hours"(zoneHours) + dur!"minutes"(zoneMinutes)) * sign;
10480         if (utcOffset == Duration.zero)
10481         {
10482             return sign == 1 ? cast(immutable(TimeZone))UTC()
10483                              : cast(immutable(TimeZone))new immutable SimpleTimeZone(Duration.zero);
10484         }
10485         return new immutable(SimpleTimeZone)(utcOffset);
10486     }
10487 
10488     // zone
10489     Rebindable!(immutable TimeZone) tz;
10490     if (value[0] == '-')
10491         tz = parseTZ(-1);
10492     else if (value[0] == '+')
10493         tz = parseTZ(1);
10494     else
10495     {
10496         // obs-zone
10497         immutable tzLen = value.length - find(value, ' ', '\t', '(')[0].length;
10498         switch (sliceAsString(value[0 .. tzLen <= 4 ? tzLen : 4]))
10499         {
10500             case "UT": case "GMT": tz = UTC(); break;
10501             case "EST": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
10502             case "EDT": tz = new immutable SimpleTimeZone(dur!"hours"(-4)); break;
10503             case "CST": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
10504             case "CDT": tz = new immutable SimpleTimeZone(dur!"hours"(-5)); break;
10505             case "MST": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
10506             case "MDT": tz = new immutable SimpleTimeZone(dur!"hours"(-6)); break;
10507             case "PST": tz = new immutable SimpleTimeZone(dur!"hours"(-8)); break;
10508             case "PDT": tz = new immutable SimpleTimeZone(dur!"hours"(-7)); break;
10509             case "J": case "j": throw new DateTimeException("Invalid timezone");
10510             default:
10511             {
10512                 if (all!(isAlpha)(value[0 .. tzLen]))
10513                 {
10514                     tz = new immutable SimpleTimeZone(Duration.zero);
10515                     break;
10516                 }
10517                 throw new DateTimeException("Invalid timezone");
10518             }
10519         }
10520         value = value[tzLen .. value.length];
10521     }
10522 
10523     // This is kind of arbitrary. Technically, nothing but CFWS is legal past
10524     // the end of the timezone, but we don't want to be picky about that in a
10525     // function that's just parsing rather than validating. So, the idea here is
10526     // that if the next character is printable (and not part of CFWS), then it
10527     // might be part of the timezone and thus affect what the timezone was
10528     // supposed to be, so we'll throw, but otherwise, we'll just ignore it.
10529     if (!value.empty && isPrintable(value[0]) && value[0] != ' ' && value[0] != '(')
10530         throw new DateTimeException("Invalid timezone");
10531 
10532     try
10533         return SysTime(DateTime(year, month, day, hour, minute, second), tz);
10534     catch (DateTimeException dte)
10535         throw new DateTimeException("date-time format is correct, but the resulting SysTime is invalid.", dte);
10536 }
10537 
10538 ///
10539 @safe unittest
10540 {
10541     import core.time : hours;
10542     import std.datetime.date : DateTime, DateTimeException;
10543     import std.datetime.timezone : SimpleTimeZone, UTC;
10544     import std.exception : assertThrown;
10545 
10546     auto tz = new immutable SimpleTimeZone(hours(-8));
10547     assert(parseRFC822DateTime("Sat, 6 Jan 1990 12:14:19 -0800") ==
10548            SysTime(DateTime(1990, 1, 6, 12, 14, 19), tz));
10549 
10550     assert(parseRFC822DateTime("9 Jul 2002 13:11 +0000") ==
10551            SysTime(DateTime(2002, 7, 9, 13, 11, 0), UTC()));
10552 
10553     auto badStr = "29 Feb 2001 12:17:16 +0200";
10554     assertThrown!DateTimeException(parseRFC822DateTime(badStr));
10555 }
10556 
10557 version (StdUnittest) private void testParse822(alias cr)(string str, SysTime expected, size_t line = __LINE__)
10558 {
10559     import std.format : format;
10560     auto value = cr(str);
10561     auto result = parseRFC822DateTime(value);
10562     if (result != expected)
10563         throw new AssertError(format("wrong result. expected [%s], actual[%s]", expected, result), __FILE__, line);
10564 }
10565 
10566 version (StdUnittest) private void testBadParse822(alias cr)(string str, size_t line = __LINE__)
10567 {
10568     try
10569         parseRFC822DateTime(cr(str));
10570     catch (DateTimeException)
10571         return;
10572     throw new AssertError("No DateTimeException was thrown", __FILE__, line);
10573 }
10574 
10575 @system unittest
10576 {
10577     import core.time;
10578     import std.algorithm.iteration : filter, map;
10579     import std.algorithm.searching : canFind;
10580     import std.array : array;
10581     import std.ascii : letters;
10582     import std.format : format;
10583     import std.meta : AliasSeq;
10584     import std.range : chain, iota, take;
10585     import std.stdio : writefln, writeln;
10586     import std.string : representation;
10587 
10588     static struct Rand3Letters
10589     {
10590         enum empty = false;
10591         @property auto front() { return _mon; }
10592         void popFront()
10593         {
10594             import std.exception : assumeUnique;
10595             import std.random : rndGen;
10596             _mon = rndGen.map!(a => letters[a % letters.length])().take(3).array().assumeUnique();
10597         }
10598         string _mon;
10599         static auto start() { Rand3Letters retval; retval.popFront(); return retval; }
10600     }
10601 
10602     static foreach (cr; AliasSeq!(function(string a){return cast(char[]) a;},
10603                            function(string a){return cast(ubyte[]) a;},
10604                            function(string a){return a;},
10605                            function(string a){return map!(b => cast(char) b)(a.representation);}))
10606     {(){ // workaround slow optimizations for large functions
10607          // https://issues.dlang.org/show_bug.cgi?id=2396
10608         scope(failure) writeln(typeof(cr).stringof);
10609         alias test = testParse822!cr;
10610         alias testBad = testBadParse822!cr;
10611 
10612         immutable std1 = DateTime(2012, 12, 21, 13, 14, 15);
10613         immutable std2 = DateTime(2012, 12, 21, 13, 14, 0);
10614         immutable dst1 = DateTime(1976, 7, 4, 5, 4, 22);
10615         immutable dst2 = DateTime(1976, 7, 4, 5, 4, 0);
10616 
10617         test("21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
10618         test("21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
10619         test("Fri, 21 Dec 2012 13:14 +0000", SysTime(std2, UTC()));
10620         test("Fri, 21 Dec 2012 13:14:15 +0000", SysTime(std1, UTC()));
10621 
10622         test("04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10623         test("04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10624         test("Sun, 04 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10625         test("Sun, 04 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10626 
10627         test("4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10628         test("4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10629         test("Sun, 4 Jul 1976 05:04 +0000", SysTime(dst2, UTC()));
10630         test("Sun, 4 Jul 1976 05:04:22 +0000", SysTime(dst1, UTC()));
10631 
10632         auto badTZ = new immutable SimpleTimeZone(Duration.zero);
10633         test("21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
10634         test("21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
10635         test("Fri, 21 Dec 2012 13:14 -0000", SysTime(std2, badTZ));
10636         test("Fri, 21 Dec 2012 13:14:15 -0000", SysTime(std1, badTZ));
10637 
10638         test("04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10639         test("04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10640         test("Sun, 04 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10641         test("Sun, 04 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10642 
10643         test("4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10644         test("4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10645         test("Sun, 4 Jul 1976 05:04 -0000", SysTime(dst2, badTZ));
10646         test("Sun, 4 Jul 1976 05:04:22 -0000", SysTime(dst1, badTZ));
10647 
10648         auto pst = new immutable SimpleTimeZone(dur!"hours"(-8));
10649         auto pdt = new immutable SimpleTimeZone(dur!"hours"(-7));
10650         test("21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
10651         test("21 Dec 2012 13:14 -0800", SysTime(std2, pst));
10652         test("Fri, 21 Dec 2012 13:14 -0800", SysTime(std2, pst));
10653         test("Fri, 21 Dec 2012 13:14:15 -0800", SysTime(std1, pst));
10654 
10655         test("04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10656         test("04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10657         test("Sun, 04 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10658         test("Sun, 04 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10659 
10660         test("4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10661         test("4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10662         test("Sun, 4 Jul 1976 05:04 -0700", SysTime(dst2, pdt));
10663         test("Sun, 4 Jul 1976 05:04:22 -0700", SysTime(dst1, pdt));
10664 
10665         auto cet = new immutable SimpleTimeZone(dur!"hours"(1));
10666         auto cest = new immutable SimpleTimeZone(dur!"hours"(2));
10667         test("21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
10668         test("21 Dec 2012 13:14 +0100", SysTime(std2, cet));
10669         test("Fri, 21 Dec 2012 13:14 +0100", SysTime(std2, cet));
10670         test("Fri, 21 Dec 2012 13:14:15 +0100", SysTime(std1, cet));
10671 
10672         test("04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10673         test("04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10674         test("Sun, 04 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10675         test("Sun, 04 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10676 
10677         test("4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10678         test("4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10679         test("Sun, 4 Jul 1976 05:04 +0200", SysTime(dst2, cest));
10680         test("Sun, 4 Jul 1976 05:04:22 +0200", SysTime(dst1, cest));
10681 
10682         // dst and std times are switched in the Southern Hemisphere which is why the
10683         // time zone names and DateTime variables don't match.
10684         auto cstStd = new immutable SimpleTimeZone(dur!"hours"(9) + dur!"minutes"(30));
10685         auto cstDST = new immutable SimpleTimeZone(dur!"hours"(10) + dur!"minutes"(30));
10686         test("21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
10687         test("21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
10688         test("Fri, 21 Dec 2012 13:14 +1030", SysTime(std2, cstDST));
10689         test("Fri, 21 Dec 2012 13:14:15 +1030", SysTime(std1, cstDST));
10690 
10691         test("04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10692         test("04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10693         test("Sun, 04 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10694         test("Sun, 04 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10695 
10696         test("4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10697         test("4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10698         test("Sun, 4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10699         test("Sun, 4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10700 
10701         foreach (int i, mon; _monthNames)
10702         {
10703             test(format("17 %s 2012 00:05:02 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 2), UTC()));
10704             test(format("17 %s 2012 00:05 +0000", mon), SysTime(DateTime(2012, i + 1, 17, 0, 5, 0), UTC()));
10705         }
10706 
10707         import std.uni : toLower, toUpper;
10708         foreach (mon; chain(_monthNames[].map!(a => toLower(a))(),
10709                             _monthNames[].map!(a => toUpper(a))(),
10710                             ["Jam", "Jen", "Fec", "Fdb", "Mas", "Mbr", "Aps", "Aqr", "Mai", "Miy",
10711                              "Jum", "Jbn", "Jup", "Jal", "Aur", "Apg", "Sem", "Sap", "Ocm", "Odt",
10712                              "Nom", "Nav", "Dem", "Dac"],
10713                             Rand3Letters.start().filter!(a => !_monthNames[].canFind(a)).take(20)))
10714         {
10715             scope(failure) writefln("Month: %s", mon);
10716             testBad(format("17 %s 2012 00:05:02 +0000", mon));
10717             testBad(format("17 %s 2012 00:05 +0000", mon));
10718         }
10719 
10720         immutable string[7] daysOfWeekNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
10721 
10722         {
10723             auto start = SysTime(DateTime(2012, 11, 11, 9, 42, 0), UTC());
10724             int day = 11;
10725 
10726             foreach (int i, dow; daysOfWeekNames)
10727             {
10728                 auto curr = start + dur!"days"(i);
10729                 test(format("%s, %s Nov 2012 09:42:00 +0000", dow, day), curr);
10730                 test(format("%s, %s Nov 2012 09:42 +0000", dow, day++), curr);
10731 
10732                 // Whether the day of the week matches the date is ignored.
10733                 test(format("%s, 11 Nov 2012 09:42:00 +0000", dow), start);
10734                 test(format("%s, 11 Nov 2012 09:42 +0000", dow), start);
10735             }
10736         }
10737 
10738         foreach (dow; chain(daysOfWeekNames[].map!(a => toLower(a))(),
10739                             daysOfWeekNames[].map!(a => toUpper(a))(),
10740                             ["Sum", "Spn", "Mom", "Man", "Tuf", "Tae", "Wem", "Wdd", "The", "Tur",
10741                              "Fro", "Fai", "San", "Sut"],
10742                             Rand3Letters.start().filter!(a => !daysOfWeekNames[].canFind(a)).take(20)))
10743         {
10744             scope(failure) writefln("Day of Week: %s", dow);
10745             testBad(format("%s, 11 Nov 2012 09:42:00 +0000", dow));
10746             testBad(format("%s, 11 Nov 2012 09:42 +0000", dow));
10747         }
10748 
10749         testBad("31 Dec 1899 23:59:59 +0000");
10750         test("01 Jan 1900 00:00:00 +0000", SysTime(Date(1900, 1, 1), UTC()));
10751         test("01 Jan 1900 00:00:00 -0000", SysTime(Date(1900, 1, 1),
10752                                                    new immutable SimpleTimeZone(Duration.zero)));
10753         test("01 Jan 1900 00:00:00 -0700", SysTime(Date(1900, 1, 1),
10754                                                    new immutable SimpleTimeZone(dur!"hours"(-7))));
10755 
10756         {
10757             auto st1 = SysTime(Date(1900, 1, 1), UTC());
10758             auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
10759             foreach (i; 1900 .. 2102)
10760             {
10761                 test(format("1 Jan %05d 00:00 +0000", i), st1);
10762                 test(format("1 Jan %05d 00:00 -1100", i), st2);
10763                 st1.add!"years"(1);
10764                 st2.add!"years"(1);
10765             }
10766             st1.year = 9998;
10767             st2.year = 9998;
10768             foreach (i; 9998 .. 11_002)
10769             {
10770                 test(format("1 Jan %05d 00:00 +0000", i), st1);
10771                 test(format("1 Jan %05d 00:00 -1100", i), st2);
10772                 st1.add!"years"(1);
10773                 st2.add!"years"(1);
10774             }
10775         }
10776 
10777         testBad("12 Feb 1907 23:17:09 0000");
10778         testBad("12 Feb 1907 23:17:09 +000");
10779         testBad("12 Feb 1907 23:17:09 -000");
10780         testBad("12 Feb 1907 23:17:09 +00000");
10781         testBad("12 Feb 1907 23:17:09 -00000");
10782         testBad("12 Feb 1907 23:17:09 +A");
10783         testBad("12 Feb 1907 23:17:09 +PST");
10784         testBad("12 Feb 1907 23:17:09 -A");
10785         testBad("12 Feb 1907 23:17:09 -PST");
10786 
10787         // test trailing stuff that gets ignored
10788         {
10789             foreach (c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
10790             {
10791                 scope(failure) writefln("c: %d", c);
10792                 test(format("21 Dec 2012 13:14:15 +0000%c", cast(char) c), SysTime(std1, UTC()));
10793                 test(format("21 Dec 2012 13:14:15 +0000%c  ", cast(char) c), SysTime(std1, UTC()));
10794                 test(format("21 Dec 2012 13:14:15 +0000%chello", cast(char) c), SysTime(std1, UTC()));
10795             }
10796         }
10797 
10798         // test trailing stuff that doesn't get ignored
10799         {
10800             foreach (c; chain(iota(33, '('), iota('(' + 1, 127)))
10801             {
10802                 scope(failure) writefln("c: %d", c);
10803                 testBad(format("21 Dec 2012 13:14:15 +0000%c", cast(char) c));
10804                 testBad(format("21 Dec 2012 13:14:15 +0000%c   ", cast(char) c));
10805                 testBad(format("21 Dec 2012 13:14:15 +0000%chello", cast(char) c));
10806             }
10807         }
10808 
10809         testBad("32 Jan 2012 12:13:14 -0800");
10810         testBad("31 Jan 2012 24:13:14 -0800");
10811         testBad("31 Jan 2012 12:60:14 -0800");
10812         testBad("31 Jan 2012 12:13:61 -0800");
10813         testBad("31 Jan 2012 12:13:14 -0860");
10814         test("31 Jan 2012 12:13:14 -0859",
10815              SysTime(DateTime(2012, 1, 31, 12, 13, 14),
10816                      new immutable SimpleTimeZone(dur!"hours"(-8) + dur!"minutes"(-59))));
10817 
10818         // leap-seconds
10819         test("21 Dec 2012 15:59:60 -0800", SysTime(DateTime(2012, 12, 21, 15, 59, 59), pst));
10820 
10821         // FWS
10822         test("Sun,4 Jul 1976 05:04 +0930", SysTime(dst2, cstStd));
10823         test("Sun,4 Jul 1976 05:04:22 +0930", SysTime(dst1, cstStd));
10824         test("Sun,4 Jul 1976 05:04 +0930 (foo)", SysTime(dst2, cstStd));
10825         test("Sun,4 Jul 1976 05:04:22 +0930 (foo)", SysTime(dst1, cstStd));
10826         test("Sun,4  \r\n  Jul  \r\n  1976  \r\n  05:04  \r\n  +0930  \r\n  (foo)", SysTime(dst2, cstStd));
10827         test("Sun,4  \r\n  Jul  \r\n  1976  \r\n  05:04:22  \r\n  +0930  \r\n  (foo)", SysTime(dst1, cstStd));
10828 
10829         auto str = "01 Jan 2012 12:13:14 -0800 ";
10830         test(str, SysTime(DateTime(2012, 1, 1, 12, 13, 14), new immutable SimpleTimeZone(hours(-8))));
10831         foreach (i; 0 .. str.length)
10832         {
10833             auto currStr = str.dup;
10834             currStr[i] = 'x';
10835             scope(failure) writefln("failed: %s", currStr);
10836             testBad(cast(string) currStr);
10837         }
10838         foreach (i; 2 .. str.length)
10839         {
10840             auto currStr = str[0 .. $ - i];
10841             scope(failure) writefln("failed: %s", currStr);
10842             testBad(cast(string) currStr);
10843             testBad((cast(string) currStr) ~ "                                    ");
10844         }
10845     }();}
10846 
10847     static void testScope(scope ref string str) @safe
10848     {
10849         auto result = parseRFC822DateTime(str);
10850     }
10851 }
10852 
10853 // Obsolete Format per section 4.3 of RFC 5322.
10854 @system unittest
10855 {
10856     import std.algorithm.iteration : filter, map;
10857     import std.ascii : letters;
10858     import std.exception : collectExceptionMsg;
10859     import std.format : format;
10860     import std.meta : AliasSeq;
10861     import std.range : chain, iota;
10862     import std.stdio : writefln, writeln;
10863     import std.string : representation;
10864 
10865     auto std1 = SysTime(DateTime(2012, 12, 21, 13, 14, 15), UTC());
10866     auto std2 = SysTime(DateTime(2012, 12, 21, 13, 14, 0), UTC());
10867     auto std3 = SysTime(DateTime(1912, 12, 21, 13, 14, 15), UTC());
10868     auto std4 = SysTime(DateTime(1912, 12, 21, 13, 14, 0), UTC());
10869     auto dst1 = SysTime(DateTime(1976, 7, 4, 5, 4, 22), UTC());
10870     auto dst2 = SysTime(DateTime(1976, 7, 4, 5, 4, 0), UTC());
10871     auto tooLate1 = SysTime(Date(10_000, 1, 1), UTC());
10872     auto tooLate2 = SysTime(DateTime(12_007, 12, 31, 12, 22, 19), UTC());
10873 
10874     static foreach (cr; AliasSeq!(function(string a){return cast(char[]) a;},
10875                            function(string a){return cast(ubyte[]) a;},
10876                            function(string a){return a;},
10877                            function(string a){return map!(b => cast(char) b)(a.representation);}))
10878     {(){ // workaround slow optimizations for large functions
10879          // https://issues.dlang.org/show_bug.cgi?id=2396
10880         scope(failure) writeln(typeof(cr).stringof);
10881         alias test = testParse822!cr;
10882         {
10883             auto list = ["", " ", " \r\n\t", "\t\r\n (hello world( frien(dog)) silly \r\n )  \t\t \r\n ()",
10884                          " \n ", "\t\n\t", " \n\t (foo) \n (bar) \r\n (baz) \n "];
10885 
10886             foreach (i, cfws; list)
10887             {
10888                 scope(failure) writefln("i: %s", i);
10889 
10890                 test(format("%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10891                 test(format("%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
10892                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14%1$s+0000%1$s", cfws), std2);
10893                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s2012%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10894 
10895                 test(format("%1$s04%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10896                 test(format("%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10897                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10898                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s1976%1$s05:04:22 +0000%1$s", cfws), dst1);
10899 
10900                 test(format("%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10901                 test(format("%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10902                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04%1$s+0000%1$s", cfws), dst2);
10903                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s1976%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10904 
10905                 test(format("%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10906                 test(format("%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
10907                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14%1$s+0000%1$s", cfws), std2);
10908                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s12%1$s13:14:15%1$s+0000%1$s", cfws), std1);
10909 
10910                 test(format("%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10911                 test(format("%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10912                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10913                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10914 
10915                 test(format("%1$s4%1$sJul%1$s76 05:04:22%1$s+0000%1$s", cfws), dst1);
10916                 test(format("%1$s4%1$sJul%1$s76 05:04%1$s+0000%1$s", cfws), dst2);
10917                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04%1$s+0000%1$s", cfws), dst2);
10918                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s76%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10919 
10920                 test(format("%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
10921                 test(format("%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
10922                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14%1$s+0000%1$s", cfws), std4);
10923                 test(format("%1$sFri%1$s,%1$s21%1$sDec%1$s012%1$s13:14:15%1$s+0000%1$s", cfws), std3);
10924 
10925                 test(format("%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10926                 test(format("%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10927                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10928                 test(format("%1$sSun%1$s,%1$s04%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10929 
10930                 test(format("%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10931                 test(format("%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10932                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04%1$s+0000%1$s", cfws), dst2);
10933                 test(format("%1$sSun%1$s,%1$s4%1$sJul%1$s076%1$s05:04:22%1$s+0000%1$s", cfws), dst1);
10934 
10935                 test(format("%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
10936                 test(format("%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
10937                 test(format("%1$sSat%1$s,%1$s1%1$sJan%1$s10000%1$s00:00:00%1$s+0000%1$s", cfws), tooLate1);
10938                 test(format("%1$sSun%1$s,%1$s31%1$sDec%1$s12007%1$s12:22:19%1$s+0000%1$s", cfws), tooLate2);
10939             }
10940         }
10941 
10942         // test years of 1, 2, and 3 digits.
10943         {
10944             auto st1 = SysTime(Date(2000, 1, 1), UTC());
10945             auto st2 = SysTime(Date(2000, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
10946             foreach (i; 0 .. 50)
10947             {
10948                 test(format("1 Jan %02d 00:00 GMT", i), st1);
10949                 test(format("1 Jan %02d 00:00 -1200", i), st2);
10950                 st1.add!"years"(1);
10951                 st2.add!"years"(1);
10952             }
10953         }
10954 
10955         {
10956             auto st1 = SysTime(Date(1950, 1, 1), UTC());
10957             auto st2 = SysTime(Date(1950, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-12)));
10958             foreach (i; 50 .. 100)
10959             {
10960                 test(format("1 Jan %02d 00:00 GMT", i), st1);
10961                 test(format("1 Jan %02d 00:00 -1200", i), st2);
10962                 st1.add!"years"(1);
10963                 st2.add!"years"(1);
10964             }
10965         }
10966 
10967         {
10968             auto st1 = SysTime(Date(1900, 1, 1), UTC());
10969             auto st2 = SysTime(Date(1900, 1, 1), new immutable SimpleTimeZone(dur!"hours"(-11)));
10970             foreach (i; 0 .. 1000)
10971             {
10972                 test(format("1 Jan %03d 00:00 GMT", i), st1);
10973                 test(format("1 Jan %03d 00:00 -1100", i), st2);
10974                 st1.add!"years"(1);
10975                 st2.add!"years"(1);
10976             }
10977         }
10978 
10979         foreach (i; 0 .. 10)
10980         {
10981             auto str1 = cr(format("1 Jan %d 00:00 GMT", i));
10982             auto str2 = cr(format("1 Jan %d 00:00 -1200", i));
10983             assertThrown!DateTimeException(parseRFC822DateTime(str1));
10984             assertThrown!DateTimeException(parseRFC822DateTime(str1));
10985         }
10986 
10987         // test time zones
10988         {
10989             auto dt = DateTime(1982, 5, 3, 12, 22, 4);
10990             test("Wed, 03 May 1982 12:22:04 UT", SysTime(dt, UTC()));
10991             test("Wed, 03 May 1982 12:22:04 GMT", SysTime(dt, UTC()));
10992             test("Wed, 03 May 1982 12:22:04 EST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
10993             test("Wed, 03 May 1982 12:22:04 EDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-4))));
10994             test("Wed, 03 May 1982 12:22:04 CST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
10995             test("Wed, 03 May 1982 12:22:04 CDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
10996             test("Wed, 03 May 1982 12:22:04 MST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
10997             test("Wed, 03 May 1982 12:22:04 MDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-6))));
10998             test("Wed, 03 May 1982 12:22:04 PST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-8))));
10999             test("Wed, 03 May 1982 12:22:04 PDT", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-7))));
11000 
11001             auto badTZ = new immutable SimpleTimeZone(Duration.zero);
11002             foreach (dchar c; filter!(a => a != 'j' && a != 'J')(letters))
11003             {
11004                 scope(failure) writefln("c: %s", c);
11005                 test(format("Wed, 03 May 1982 12:22:04 %s", c), SysTime(dt, badTZ));
11006                 test(format("Wed, 03 May 1982 12:22:04%s", c), SysTime(dt, badTZ));
11007             }
11008 
11009             foreach (dchar c; ['j', 'J'])
11010             {
11011                 scope(failure) writefln("c: %s", c);
11012                 assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04 %s", c))));
11013                 assertThrown!DateTimeException(parseRFC822DateTime(cr(format("Wed, 03 May 1982 12:22:04%s", c))));
11014             }
11015 
11016             foreach (string s; ["AAA", "GQW", "DDT", "PDA", "GT", "GM"])
11017             {
11018                 scope(failure) writefln("s: %s", s);
11019                 test(format("Wed, 03 May 1982 12:22:04 %s", s), SysTime(dt, badTZ));
11020             }
11021 
11022             // test trailing stuff that gets ignored
11023             {
11024                 foreach (c; chain(iota(0, 33), ['('], iota(127, ubyte.max + 1)))
11025                 {
11026                     scope(failure) writefln("c: %d", c);
11027                     test(format("21Dec1213:14:15+0000%c", cast(char) c), std1);
11028                     test(format("21Dec1213:14:15+0000%c  ", cast(char) c), std1);
11029                     test(format("21Dec1213:14:15+0000%chello", cast(char) c), std1);
11030                 }
11031             }
11032 
11033             // test trailing stuff that doesn't get ignored
11034             {
11035                 foreach (c; chain(iota(33, '('), iota('(' + 1, 127)))
11036                 {
11037                     scope(failure) writefln("c: %d", c);
11038                     assertThrown!DateTimeException(
11039                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c", cast(char) c))));
11040                     assertThrown!DateTimeException(
11041                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%c  ", cast(char) c))));
11042                     assertThrown!DateTimeException(
11043                         parseRFC822DateTime(cr(format("21Dec1213:14:15+0000%chello", cast(char) c))));
11044                 }
11045             }
11046         }
11047 
11048         // test that the checks for minimum length work correctly and avoid
11049         // any RangeErrors.
11050         test("7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11051                                      new immutable SimpleTimeZone(Duration.zero)));
11052         test("Fri,7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11053                                          new immutable SimpleTimeZone(Duration.zero)));
11054         test("7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11055                                         new immutable SimpleTimeZone(Duration.zero)));
11056         test("Fri,7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
11057                                             new immutable SimpleTimeZone(Duration.zero)));
11058 
11059         auto tooShortMsg = collectExceptionMsg!DateTimeException(parseRFC822DateTime(""));
11060         foreach (str; ["Fri,7Dec1200:00:00", "7Dec1200:00:00"])
11061         {
11062             foreach (i; 0 .. str.length)
11063             {
11064                 auto value = str[0 .. $ - i];
11065                 scope(failure) writeln(value);
11066                 assert(collectExceptionMsg!DateTimeException(parseRFC822DateTime(value)) == tooShortMsg);
11067             }
11068         }
11069     }();}
11070 }
11071 
11072 
11073 private:
11074 
11075 /+
11076     Returns the given hnsecs as an ISO string of fractional seconds.
11077   +/
11078 string fracSecsToISOString(int hnsecs, int prec = -1) @safe pure nothrow
11079 {
11080     import std.array : appender;
11081     auto w = appender!string();
11082     try
11083         fracSecsToISOString(w, hnsecs, prec);
11084     catch (Exception e)
11085         assert(0, "fracSecsToISOString() threw.");
11086     return w.data;
11087 }
11088 
11089 void fracSecsToISOString(W)(ref W writer, int hnsecs, int prec = -1)
11090 {
11091     import std.conv : toChars;
11092     import std.range : padLeft;
11093 
11094     assert(hnsecs >= 0);
11095 
11096     if (prec == 0)
11097         return;
11098 
11099     if (hnsecs == 0)
11100         return;
11101 
11102     put(writer, '.');
11103     auto chars = hnsecs.toChars.padLeft('0', 7);
11104 
11105     if (prec == -1)
11106     {
11107         while (chars.back == '0')
11108             chars.popBack();
11109         put(writer, chars);
11110     }
11111     else
11112         put(writer, chars[0 .. prec]);
11113 }
11114 
11115 @safe unittest
11116 {
11117     assert(fracSecsToISOString(0) == "");
11118     assert(fracSecsToISOString(1) == ".0000001");
11119     assert(fracSecsToISOString(10) == ".000001");
11120     assert(fracSecsToISOString(100) == ".00001");
11121     assert(fracSecsToISOString(1000) == ".0001");
11122     assert(fracSecsToISOString(10_000) == ".001");
11123     assert(fracSecsToISOString(100_000) == ".01");
11124     assert(fracSecsToISOString(1_000_000) == ".1");
11125     assert(fracSecsToISOString(1_000_001) == ".1000001");
11126     assert(fracSecsToISOString(1_001_001) == ".1001001");
11127     assert(fracSecsToISOString(1_071_601) == ".1071601");
11128     assert(fracSecsToISOString(1_271_641) == ".1271641");
11129     assert(fracSecsToISOString(9_999_999) == ".9999999");
11130     assert(fracSecsToISOString(9_999_990) == ".999999");
11131     assert(fracSecsToISOString(9_999_900) == ".99999");
11132     assert(fracSecsToISOString(9_999_000) == ".9999");
11133     assert(fracSecsToISOString(9_990_000) == ".999");
11134     assert(fracSecsToISOString(9_900_000) == ".99");
11135     assert(fracSecsToISOString(9_000_000) == ".9");
11136     assert(fracSecsToISOString(999) == ".0000999");
11137     assert(fracSecsToISOString(9990) == ".000999");
11138     assert(fracSecsToISOString(99_900) == ".00999");
11139     assert(fracSecsToISOString(999_000) == ".0999");
11140 }
11141 
11142 
11143 /+
11144     Returns a Duration corresponding to to the given ISO string of
11145     fractional seconds.
11146   +/
11147 static Duration fracSecsFromISOString(S)(scope const S isoString) @safe pure
11148 if (isSomeString!S)
11149 {
11150     import std.algorithm.searching : all;
11151     import std.ascii : isDigit;
11152     import std.conv : to;
11153     import std.string : representation;
11154 
11155     if (isoString.empty)
11156         return Duration.zero;
11157 
11158     auto str = isoString.representation;
11159 
11160     enforce(str[0] == '.', new DateTimeException("Invalid ISO String"));
11161     str.popFront();
11162 
11163     enforce(!str.empty && all!isDigit(str), new DateTimeException("Invalid ISO String"));
11164 
11165     dchar[7] fullISOString = void;
11166     foreach (i, ref dchar c; fullISOString)
11167     {
11168         if (i < str.length)
11169             c = str[i];
11170         else
11171             c = '0';
11172     }
11173 
11174     return hnsecs(to!int(fullISOString[]));
11175 }
11176 
11177 @safe unittest
11178 {
11179     import core.time;
11180     static void testFSInvalid(string isoString)
11181     {
11182         fracSecsFromISOString(isoString);
11183     }
11184 
11185     assertThrown!DateTimeException(testFSInvalid("."));
11186     assertThrown!DateTimeException(testFSInvalid("0."));
11187     assertThrown!DateTimeException(testFSInvalid("0"));
11188     assertThrown!DateTimeException(testFSInvalid("0000000"));
11189     assertThrown!DateTimeException(testFSInvalid("T"));
11190     assertThrown!DateTimeException(testFSInvalid("T."));
11191     assertThrown!DateTimeException(testFSInvalid(".T"));
11192     assertThrown!DateTimeException(testFSInvalid(".00000Q0"));
11193     assertThrown!DateTimeException(testFSInvalid(".000000Q"));
11194     assertThrown!DateTimeException(testFSInvalid(".0000000Q"));
11195     assertThrown!DateTimeException(testFSInvalid(".0000000000Q"));
11196 
11197     assert(fracSecsFromISOString("") == Duration.zero);
11198     assert(fracSecsFromISOString(".0000001") == hnsecs(1));
11199     assert(fracSecsFromISOString(".000001") == hnsecs(10));
11200     assert(fracSecsFromISOString(".00001") == hnsecs(100));
11201     assert(fracSecsFromISOString(".0001") == hnsecs(1000));
11202     assert(fracSecsFromISOString(".001") == hnsecs(10_000));
11203     assert(fracSecsFromISOString(".01") == hnsecs(100_000));
11204     assert(fracSecsFromISOString(".1") == hnsecs(1_000_000));
11205     assert(fracSecsFromISOString(".1000001") == hnsecs(1_000_001));
11206     assert(fracSecsFromISOString(".1001001") == hnsecs(1_001_001));
11207     assert(fracSecsFromISOString(".1071601") == hnsecs(1_071_601));
11208     assert(fracSecsFromISOString(".1271641") == hnsecs(1_271_641));
11209     assert(fracSecsFromISOString(".9999999") == hnsecs(9_999_999));
11210     assert(fracSecsFromISOString(".9999990") == hnsecs(9_999_990));
11211     assert(fracSecsFromISOString(".999999") == hnsecs(9_999_990));
11212     assert(fracSecsFromISOString(".9999900") == hnsecs(9_999_900));
11213     assert(fracSecsFromISOString(".99999") == hnsecs(9_999_900));
11214     assert(fracSecsFromISOString(".9999000") == hnsecs(9_999_000));
11215     assert(fracSecsFromISOString(".9999") == hnsecs(9_999_000));
11216     assert(fracSecsFromISOString(".9990000") == hnsecs(9_990_000));
11217     assert(fracSecsFromISOString(".999") == hnsecs(9_990_000));
11218     assert(fracSecsFromISOString(".9900000") == hnsecs(9_900_000));
11219     assert(fracSecsFromISOString(".9900") == hnsecs(9_900_000));
11220     assert(fracSecsFromISOString(".99") == hnsecs(9_900_000));
11221     assert(fracSecsFromISOString(".9000000") == hnsecs(9_000_000));
11222     assert(fracSecsFromISOString(".9") == hnsecs(9_000_000));
11223     assert(fracSecsFromISOString(".0000999") == hnsecs(999));
11224     assert(fracSecsFromISOString(".0009990") == hnsecs(9990));
11225     assert(fracSecsFromISOString(".000999") == hnsecs(9990));
11226     assert(fracSecsFromISOString(".0099900") == hnsecs(99_900));
11227     assert(fracSecsFromISOString(".00999") == hnsecs(99_900));
11228     assert(fracSecsFromISOString(".0999000") == hnsecs(999_000));
11229     assert(fracSecsFromISOString(".0999") == hnsecs(999_000));
11230     assert(fracSecsFromISOString(".00000000") == Duration.zero);
11231     assert(fracSecsFromISOString(".00000001") == Duration.zero);
11232     assert(fracSecsFromISOString(".00000009") == Duration.zero);
11233     assert(fracSecsFromISOString(".1234567890") == hnsecs(1_234_567));
11234     assert(fracSecsFromISOString(".12345678901234567890") == hnsecs(1_234_567));
11235 }
11236 
11237 
11238 /+
11239     This function is used to split out the units without getting the remaining
11240     hnsecs.
11241 
11242     Params:
11243         units  = The units to split out.
11244         hnsecs = The current total hnsecs.
11245 
11246     Returns:
11247         The split out value.
11248   +/
11249 long getUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
11250 if (validTimeUnits(units) &&
11251     CmpTimeUnits!(units, "months") < 0)
11252 {
11253     return convert!("hnsecs", units)(hnsecs);
11254 }
11255 
11256 @safe unittest
11257 {
11258     auto hnsecs = 2595000000007L;
11259     immutable days = getUnitsFromHNSecs!"days"(hnsecs);
11260     assert(days == 3);
11261     assert(hnsecs == 2595000000007L);
11262 }
11263 
11264 
11265 /+
11266     This function is used to split out the units without getting the units but
11267     just the remaining hnsecs.
11268 
11269     Params:
11270         units  = The units to split out.
11271         hnsecs = The current total hnsecs.
11272 
11273     Returns:
11274         The remaining hnsecs.
11275   +/
11276 long removeUnitsFromHNSecs(string units)(long hnsecs) @safe pure nothrow
11277 if (validTimeUnits(units) &&
11278     CmpTimeUnits!(units, "months") < 0)
11279 {
11280     immutable value = convert!("hnsecs", units)(hnsecs);
11281     return hnsecs - convert!(units, "hnsecs")(value);
11282 }
11283 
11284 @safe unittest
11285 {
11286     auto hnsecs = 2595000000007L;
11287     auto returned = removeUnitsFromHNSecs!"days"(hnsecs);
11288     assert(returned == 3000000007);
11289     assert(hnsecs == 2595000000007L);
11290 }
11291 
11292 
11293 /+
11294     Strips what RFC 5322, section 3.2.2 refers to as CFWS from the left-hand
11295     side of the given range (it strips comments delimited by $(D '(') and
11296     `'`') as well as folding whitespace).
11297 
11298     It is assumed that the given range contains the value of a header field and
11299     no terminating CRLF for the line (though the CRLF for folding whitespace is
11300     of course expected and stripped) and thus that the only case of CR or LF is
11301     in folding whitespace.
11302 
11303     If a comment does not terminate correctly (e.g. mismatched parens) or if the
11304     the FWS is malformed, then the range will be empty when stripCWFS is done.
11305     However, only minimal validation of the content is done (e.g. quoted pairs
11306     within a comment aren't validated beyond \$LPAREN or \$RPAREN, because
11307     they're inside a comment, and thus their value doesn't matter anyway). It's
11308     only when the content does not conform to the grammar rules for FWS and thus
11309     literally cannot be parsed that content is considered invalid, and an empty
11310     range is returned.
11311 
11312     Note that _stripCFWS is eager, not lazy. It does not create a new range.
11313     Rather, it pops off the CFWS from the range and returns it.
11314   +/
11315 R _stripCFWS(R)(R range)
11316 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R &&
11317     (is(immutable ElementType!R == immutable char) || is(immutable ElementType!R == immutable ubyte)))
11318 {
11319     immutable e = range.length;
11320     outer: for (size_t i = 0; i < e; )
11321     {
11322         switch (range[i])
11323         {
11324             case ' ': case '\t':
11325             {
11326                 ++i;
11327                 break;
11328             }
11329             case '\r':
11330             {
11331                 if (i + 2 < e && range[i + 1] == '\n' && (range[i + 2] == ' ' || range[i + 2] == '\t'))
11332                 {
11333                     i += 3;
11334                     break;
11335                 }
11336                 break outer;
11337             }
11338             case '\n':
11339             {
11340                 if (i + 1 < e && (range[i + 1] == ' ' || range[i + 1] == '\t'))
11341                 {
11342                     i += 2;
11343                     break;
11344                 }
11345                 break outer;
11346             }
11347             case '(':
11348             {
11349                 ++i;
11350                 size_t commentLevel = 1;
11351                 while (i < e)
11352                 {
11353                     if (range[i] == '(')
11354                         ++commentLevel;
11355                     else if (range[i] == ')')
11356                     {
11357                         ++i;
11358                         if (--commentLevel == 0)
11359                             continue outer;
11360                         continue;
11361                     }
11362                     else if (range[i] == '\\')
11363                     {
11364                         if (++i == e)
11365                             break outer;
11366                     }
11367                     ++i;
11368                 }
11369                 break outer;
11370             }
11371             default: return range[i .. e];
11372         }
11373     }
11374     return range[e .. e];
11375 }
11376 
11377 @system unittest
11378 {
11379     import std.algorithm.comparison : equal;
11380     import std.algorithm.iteration : map;
11381     import std.meta : AliasSeq;
11382     import std.stdio : writeln;
11383     import std.string : representation;
11384 
11385     static foreach (cr; AliasSeq!(function(string a){return cast(ubyte[]) a;},
11386                            function(string a){return map!(b => cast(char) b)(a.representation);}))
11387     {
11388         scope(failure) writeln(typeof(cr).stringof);
11389 
11390         assert(_stripCFWS(cr("")).empty);
11391         assert(_stripCFWS(cr("\r")).empty);
11392         assert(_stripCFWS(cr("\r\n")).empty);
11393         assert(_stripCFWS(cr("\r\n ")).empty);
11394         assert(_stripCFWS(cr(" \t\r\n")).empty);
11395         assert(equal(_stripCFWS(cr(" \t\r\n hello")), cr("hello")));
11396         assert(_stripCFWS(cr(" \t\r\nhello")).empty);
11397         assert(_stripCFWS(cr(" \t\r\n\v")).empty);
11398         assert(equal(_stripCFWS(cr("\v \t\r\n\v")), cr("\v \t\r\n\v")));
11399         assert(_stripCFWS(cr("()")).empty);
11400         assert(_stripCFWS(cr("(hello world)")).empty);
11401         assert(_stripCFWS(cr("(hello world)(hello world)")).empty);
11402         assert(_stripCFWS(cr("(hello world\r\n foo\r where's\nwaldo)")).empty);
11403         assert(_stripCFWS(cr(" \t (hello \tworld\r\n foo\r where's\nwaldo)\t\t ")).empty);
11404         assert(_stripCFWS(cr("      ")).empty);
11405         assert(_stripCFWS(cr("\t\t\t")).empty);
11406         assert(_stripCFWS(cr("\t \r\n\r \n")).empty);
11407         assert(_stripCFWS(cr("(hello world) (can't find waldo) (he's lost)")).empty);
11408         assert(_stripCFWS(cr("(hello\\) world) (can't \\(find waldo) (he's \\(\\)lost)")).empty);
11409         assert(_stripCFWS(cr("(((((")).empty);
11410         assert(_stripCFWS(cr("(((()))")).empty);
11411         assert(_stripCFWS(cr("(((())))")).empty);
11412         assert(equal(_stripCFWS(cr("(((()))))")), cr(")")));
11413         assert(equal(_stripCFWS(cr(")))))")), cr(")))))")));
11414         assert(equal(_stripCFWS(cr("()))))")), cr("))))")));
11415         assert(equal(_stripCFWS(cr(" hello hello ")), cr("hello hello ")));
11416         assert(equal(_stripCFWS(cr("\thello (world)")), cr("hello (world)")));
11417         assert(equal(_stripCFWS(cr(" \r\n \\((\\))  foo")), cr("\\((\\))  foo")));
11418         assert(equal(_stripCFWS(cr(" \r\n (\\((\\)))  foo")), cr("foo")));
11419         assert(equal(_stripCFWS(cr(" \r\n (\\(()))  foo")), cr(")  foo")));
11420         assert(_stripCFWS(cr(" \r\n (((\\)))  foo")).empty);
11421 
11422         assert(_stripCFWS(cr("(hello)(hello)")).empty);
11423         assert(_stripCFWS(cr(" \r\n (hello)\r\n (hello)")).empty);
11424         assert(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n ")).empty);
11425         assert(_stripCFWS(cr("\t\t\t\t(hello)\t\t\t\t(hello)\t\t\t\t")).empty);
11426         assert(equal(_stripCFWS(cr(" \r\n (hello)\r\n (hello) \r\n hello")), cr("hello")));
11427         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n hello")), cr("hello")));
11428         assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\r\n\t(hello)\t\r\n hello")), cr("hello")));
11429         assert(equal(_stripCFWS(cr("\t\r\n\t(hello)\t\r\n\t(hello)\t\r\n hello")), cr("hello")));
11430         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n \r\n (hello) \r\n hello")), cr("hello")));
11431         assert(equal(_stripCFWS(cr(" \r\n (hello) \r\n (hello) \r\n \r\n hello")), cr("hello")));
11432         assert(equal(_stripCFWS(cr(" \r\n \r\n (hello)\t\r\n (hello) \r\n hello")), cr("hello")));
11433         assert(equal(_stripCFWS(cr(" \r\n\t\r\n\t(hello)\t\r\n (hello) \r\n hello")), cr("hello")));
11434 
11435         assert(equal(_stripCFWS(cr(" (\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
11436         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) foo")), cr("foo")));
11437         assert(equal(_stripCFWS(cr(" (\t\r\n ( \r\n ) \r\n ) foo")), cr("foo")));
11438         assert(equal(_stripCFWS(cr(" (\r\n\t( \r\n ) \r\n ) foo")), cr("foo")));
11439         assert(equal(_stripCFWS(cr(" ( \r\n (\t\r\n ) \r\n ) foo")), cr("foo")));
11440         assert(equal(_stripCFWS(cr(" ( \r\n (\r\n ) \r\n ) foo")), cr("foo")));
11441         assert(equal(_stripCFWS(cr(" ( \r\n (\r\n\t) \r\n ) foo")), cr("foo")));
11442         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n) \r\n ) foo")), cr("foo")));
11443         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\t\r\n ) foo")), cr("foo")));
11444         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n )\r\n ) foo")), cr("foo")));
11445         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n) foo")), cr("foo")));
11446         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n\t) foo")), cr("foo")));
11447         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n ) \r\n foo")), cr("foo")));
11448         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\t\r\n foo")), cr("foo")));
11449         assert(equal(_stripCFWS(cr(" ( \r\n ( \r\n ) \r\n )\r\n foo")), cr("foo")));
11450 
11451         assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11452         assert(equal(_stripCFWS(cr(" ( \r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11453         assert(equal(_stripCFWS(cr(" (\t\r\n \r\n ( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11454         assert(equal(_stripCFWS(cr(" (\r\n \r\n\t( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11455         assert(equal(_stripCFWS(cr(" (\r\n \r\n( \r\n \r\n ) \r\n ) foo")), cr("foo")));
11456         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n\t) \r\n ) foo")), cr("foo")));
11457         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\t\r\n ) foo")), cr("foo")));
11458         assert(equal(_stripCFWS(cr(" (\r\n \r\n ( \r\n \r\n )\r\n ) foo")), cr("foo")));
11459 
11460         assert(equal(_stripCFWS(cr(" ( \r\n bar \r\n ( \r\n bar \r\n ) \r\n ) foo")), cr("foo")));
11461         assert(equal(_stripCFWS(cr(" ( \r\n () \r\n ( \r\n () \r\n ) \r\n ) foo")), cr("foo")));
11462         assert(equal(_stripCFWS(cr(" ( \r\n \\\\ \r\n ( \r\n \\\\ \r\n ) \r\n ) foo")), cr("foo")));
11463 
11464         assert(_stripCFWS(cr("(hello)(hello)")).empty);
11465         assert(_stripCFWS(cr(" \n (hello)\n (hello) \n ")).empty);
11466         assert(_stripCFWS(cr(" \n (hello) \n (hello) \n ")).empty);
11467         assert(equal(_stripCFWS(cr(" \n (hello)\n (hello) \n hello")), cr("hello")));
11468         assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n hello")), cr("hello")));
11469         assert(equal(_stripCFWS(cr("\t\n\t(hello)\n\t(hello)\t\n hello")), cr("hello")));
11470         assert(equal(_stripCFWS(cr("\t\n\t(hello)\t\n\t(hello)\t\n hello")), cr("hello")));
11471         assert(equal(_stripCFWS(cr(" \n (hello) \n \n (hello) \n hello")), cr("hello")));
11472         assert(equal(_stripCFWS(cr(" \n (hello) \n (hello) \n \n hello")), cr("hello")));
11473         assert(equal(_stripCFWS(cr(" \n \n (hello)\t\n (hello) \n hello")), cr("hello")));
11474         assert(equal(_stripCFWS(cr(" \n\t\n\t(hello)\t\n (hello) \n hello")), cr("hello")));
11475     }
11476 }
11477 
11478 // This is so that we don't have to worry about std.conv.to throwing. It also
11479 // doesn't have to worry about quite as many cases as std.conv.to, since it
11480 // doesn't have to worry about a sign on the value or about whether it fits.
11481 T _convDigits(T, R)(R str)
11482 if (isIntegral!T && isSigned!T) // The constraints on R were already covered by parseRFC822DateTime.
11483 {
11484     import std.ascii : isDigit;
11485 
11486     assert(!str.empty);
11487     T num = 0;
11488     foreach (i; 0 .. str.length)
11489     {
11490         if (i != 0)
11491             num *= 10;
11492         if (!isDigit(str[i]))
11493             return -1;
11494         num += str[i] - '0';
11495     }
11496     return num;
11497 }
11498 
11499 @safe unittest
11500 {
11501     import std.conv : to;
11502     import std.range : chain, iota;
11503     foreach (i; chain(iota(0, 101), [250, 999, 1000, 1001, 2345, 9999]))
11504     {
11505         assert(_convDigits!int(to!string(i)) == i, i.to!string);
11506     }
11507     foreach (str; ["-42", "+42", "1a", "1 ", " ", " 42 "])
11508     {
11509         assert(_convDigits!int(str) == -1, str);
11510     }
11511 }
11512 
11513 
11514 // NOTE: all the non-simple array literals are wrapped in functions, because
11515 // otherwise importing causes re-evaluation of the static initializers using
11516 // CTFE with unittests enabled
11517 version (StdUnittest)
11518 {
11519 private @safe:
11520     // Variables to help in testing.
11521     Duration currLocalDiffFromUTC;
11522     immutable (TimeZone)[] testTZs;
11523 
11524     // All of these helper arrays are sorted in ascending order.
11525     auto testYearsBC = [-1999, -1200, -600, -4, -1, 0];
11526     auto testYearsAD = [1, 4, 1000, 1999, 2000, 2012];
11527 
11528     // I'd use a Tuple, but I get forward reference errors if I try.
11529     struct MonthDay
11530     {
11531         Month month;
11532         short day;
11533 
11534         this(int m, short d)
11535         {
11536             month = cast(Month) m;
11537             day = d;
11538         }
11539     }
11540 
11541     MonthDay[] testMonthDays()
11542     {
11543        static result = [MonthDay(1, 1),
11544                                 MonthDay(1, 2),
11545                                 MonthDay(3, 17),
11546                                 MonthDay(7, 4),
11547                                 MonthDay(10, 27),
11548                                 MonthDay(12, 30),
11549                                 MonthDay(12, 31)];
11550        return result;
11551     }
11552 
11553     auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31];
11554 
11555     TimeOfDay[] testTODs()
11556     {
11557        static result = [TimeOfDay(0, 0, 0),
11558                      TimeOfDay(0, 0, 1),
11559                      TimeOfDay(0, 1, 0),
11560                      TimeOfDay(1, 0, 0),
11561                      TimeOfDay(13, 13, 13),
11562                      TimeOfDay(23, 59, 59)];
11563        return result;
11564     }
11565 
11566     auto testHours = [0, 1, 12, 22, 23];
11567     auto testMinSecs = [0, 1, 30, 58, 59];
11568 
11569     // Throwing exceptions is incredibly expensive, so we want to use a smaller
11570     // set of values for tests using assertThrown.
11571     TimeOfDay[] testTODsThrown()
11572     {
11573        static result = [TimeOfDay(0, 0, 0),
11574                            TimeOfDay(13, 13, 13),
11575                            TimeOfDay(23, 59, 59)];
11576        return result;
11577     }
11578 
11579     Date[] testDatesBC;
11580     Date[] testDatesAD;
11581 
11582     DateTime[] testDateTimesBC;
11583     DateTime[] testDateTimesAD;
11584 
11585     Duration[] testFracSecs;
11586 
11587     SysTime[] testSysTimesBC;
11588     SysTime[] testSysTimesAD;
11589 
11590     // I'd use a Tuple, but I get forward reference errors if I try.
11591     struct GregDay { int day; Date date; }
11592     GregDay[] testGregDaysBC()
11593     {
11594        static result = [GregDay(-1_373_427, Date(-3760, 9, 7)), // Start of the Hebrew Calendar
11595                            GregDay(-735_233, Date(-2012, 1, 1)),
11596                            GregDay(-735_202, Date(-2012, 2, 1)),
11597                            GregDay(-735_175, Date(-2012, 2, 28)),
11598                            GregDay(-735_174, Date(-2012, 2, 29)),
11599                            GregDay(-735_173, Date(-2012, 3, 1)),
11600                            GregDay(-734_502, Date(-2010, 1, 1)),
11601                            GregDay(-734_472, Date(-2010, 1, 31)),
11602                            GregDay(-734_471, Date(-2010, 2, 1)),
11603                            GregDay(-734_444, Date(-2010, 2, 28)),
11604                            GregDay(-734_443, Date(-2010, 3, 1)),
11605                            GregDay(-734_413, Date(-2010, 3, 31)),
11606                            GregDay(-734_412, Date(-2010, 4, 1)),
11607                            GregDay(-734_383, Date(-2010, 4, 30)),
11608                            GregDay(-734_382, Date(-2010, 5, 1)),
11609                            GregDay(-734_352, Date(-2010, 5, 31)),
11610                            GregDay(-734_351, Date(-2010, 6, 1)),
11611                            GregDay(-734_322, Date(-2010, 6, 30)),
11612                            GregDay(-734_321, Date(-2010, 7, 1)),
11613                            GregDay(-734_291, Date(-2010, 7, 31)),
11614                            GregDay(-734_290, Date(-2010, 8, 1)),
11615                            GregDay(-734_260, Date(-2010, 8, 31)),
11616                            GregDay(-734_259, Date(-2010, 9, 1)),
11617                            GregDay(-734_230, Date(-2010, 9, 30)),
11618                            GregDay(-734_229, Date(-2010, 10, 1)),
11619                            GregDay(-734_199, Date(-2010, 10, 31)),
11620                            GregDay(-734_198, Date(-2010, 11, 1)),
11621                            GregDay(-734_169, Date(-2010, 11, 30)),
11622                            GregDay(-734_168, Date(-2010, 12, 1)),
11623                            GregDay(-734_139, Date(-2010, 12, 30)),
11624                            GregDay(-734_138, Date(-2010, 12, 31)),
11625                            GregDay(-731_215, Date(-2001, 1, 1)),
11626                            GregDay(-730_850, Date(-2000, 1, 1)),
11627                            GregDay(-730_849, Date(-2000, 1, 2)),
11628                            GregDay(-730_486, Date(-2000, 12, 30)),
11629                            GregDay(-730_485, Date(-2000, 12, 31)),
11630                            GregDay(-730_484, Date(-1999, 1, 1)),
11631                            GregDay(-694_690, Date(-1901, 1, 1)),
11632                            GregDay(-694_325, Date(-1900, 1, 1)),
11633                            GregDay(-585_118, Date(-1601, 1, 1)),
11634                            GregDay(-584_753, Date(-1600, 1, 1)),
11635                            GregDay(-584_388, Date(-1600, 12, 31)),
11636                            GregDay(-584_387, Date(-1599, 1, 1)),
11637                            GregDay(-365_972, Date(-1001, 1, 1)),
11638                            GregDay(-365_607, Date(-1000, 1, 1)),
11639                            GregDay(-183_351, Date(-501, 1, 1)),
11640                            GregDay(-182_986, Date(-500, 1, 1)),
11641                            GregDay(-182_621, Date(-499, 1, 1)),
11642                            GregDay(-146_827, Date(-401, 1, 1)),
11643                            GregDay(-146_462, Date(-400, 1, 1)),
11644                            GregDay(-146_097, Date(-400, 12, 31)),
11645                            GregDay(-110_302, Date(-301, 1, 1)),
11646                            GregDay(-109_937, Date(-300, 1, 1)),
11647                            GregDay(-73_778, Date(-201, 1, 1)),
11648                            GregDay(-73_413, Date(-200, 1, 1)),
11649                            GregDay(-38_715, Date(-105, 1, 1)),
11650                            GregDay(-37_254, Date(-101, 1, 1)),
11651                            GregDay(-36_889, Date(-100, 1, 1)),
11652                            GregDay(-36_524, Date(-99, 1, 1)),
11653                            GregDay(-36_160, Date(-99, 12, 31)),
11654                            GregDay(-35_794, Date(-97, 1, 1)),
11655                            GregDay(-18_627, Date(-50, 1, 1)),
11656                            GregDay(-18_262, Date(-49, 1, 1)),
11657                            GregDay(-3652, Date(-9, 1, 1)),
11658                            GregDay(-2191, Date(-5, 1, 1)),
11659                            GregDay(-1827, Date(-5, 12, 31)),
11660                            GregDay(-1826, Date(-4, 1, 1)),
11661                            GregDay(-1825, Date(-4, 1, 2)),
11662                            GregDay(-1462, Date(-4, 12, 30)),
11663                            GregDay(-1461, Date(-4, 12, 31)),
11664                            GregDay(-1460, Date(-3, 1, 1)),
11665                            GregDay(-1096, Date(-3, 12, 31)),
11666                            GregDay(-1095, Date(-2, 1, 1)),
11667                            GregDay(-731, Date(-2, 12, 31)),
11668                            GregDay(-730, Date(-1, 1, 1)),
11669                            GregDay(-367, Date(-1, 12, 30)),
11670                            GregDay(-366, Date(-1, 12, 31)),
11671                            GregDay(-365, Date(0, 1, 1)),
11672                            GregDay(-31, Date(0, 11, 30)),
11673                            GregDay(-30, Date(0, 12, 1)),
11674                            GregDay(-1, Date(0, 12, 30)),
11675                            GregDay(0, Date(0, 12, 31))];
11676        return result;
11677     }
11678 
11679     GregDay[] testGregDaysAD()
11680     {
11681        static result = [GregDay(1, Date(1, 1, 1)),
11682                            GregDay(2, Date(1, 1, 2)),
11683                            GregDay(32, Date(1, 2, 1)),
11684                            GregDay(365, Date(1, 12, 31)),
11685                            GregDay(366, Date(2, 1, 1)),
11686                            GregDay(731, Date(3, 1, 1)),
11687                            GregDay(1096, Date(4, 1, 1)),
11688                            GregDay(1097, Date(4, 1, 2)),
11689                            GregDay(1460, Date(4, 12, 30)),
11690                            GregDay(1461, Date(4, 12, 31)),
11691                            GregDay(1462, Date(5, 1, 1)),
11692                            GregDay(17_898, Date(50, 1, 1)),
11693                            GregDay(35_065, Date(97, 1, 1)),
11694                            GregDay(36_160, Date(100, 1, 1)),
11695                            GregDay(36_525, Date(101, 1, 1)),
11696                            GregDay(37_986, Date(105, 1, 1)),
11697                            GregDay(72_684, Date(200, 1, 1)),
11698                            GregDay(73_049, Date(201, 1, 1)),
11699                            GregDay(109_208, Date(300, 1, 1)),
11700                            GregDay(109_573, Date(301, 1, 1)),
11701                            GregDay(145_732, Date(400, 1, 1)),
11702                            GregDay(146_098, Date(401, 1, 1)),
11703                            GregDay(182_257, Date(500, 1, 1)),
11704                            GregDay(182_622, Date(501, 1, 1)),
11705                            GregDay(364_878, Date(1000, 1, 1)),
11706                            GregDay(365_243, Date(1001, 1, 1)),
11707                            GregDay(584_023, Date(1600, 1, 1)),
11708                            GregDay(584_389, Date(1601, 1, 1)),
11709                            GregDay(693_596, Date(1900, 1, 1)),
11710                            GregDay(693_961, Date(1901, 1, 1)),
11711                            GregDay(729_755, Date(1999, 1, 1)),
11712                            GregDay(730_120, Date(2000, 1, 1)),
11713                            GregDay(730_121, Date(2000, 1, 2)),
11714                            GregDay(730_484, Date(2000, 12, 30)),
11715                            GregDay(730_485, Date(2000, 12, 31)),
11716                            GregDay(730_486, Date(2001, 1, 1)),
11717                            GregDay(733_773, Date(2010, 1, 1)),
11718                            GregDay(733_774, Date(2010, 1, 2)),
11719                            GregDay(733_803, Date(2010, 1, 31)),
11720                            GregDay(733_804, Date(2010, 2, 1)),
11721                            GregDay(733_831, Date(2010, 2, 28)),
11722                            GregDay(733_832, Date(2010, 3, 1)),
11723                            GregDay(733_862, Date(2010, 3, 31)),
11724                            GregDay(733_863, Date(2010, 4, 1)),
11725                            GregDay(733_892, Date(2010, 4, 30)),
11726                            GregDay(733_893, Date(2010, 5, 1)),
11727                            GregDay(733_923, Date(2010, 5, 31)),
11728                            GregDay(733_924, Date(2010, 6, 1)),
11729                            GregDay(733_953, Date(2010, 6, 30)),
11730                            GregDay(733_954, Date(2010, 7, 1)),
11731                            GregDay(733_984, Date(2010, 7, 31)),
11732                            GregDay(733_985, Date(2010, 8, 1)),
11733                            GregDay(734_015, Date(2010, 8, 31)),
11734                            GregDay(734_016, Date(2010, 9, 1)),
11735                            GregDay(734_045, Date(2010, 9, 30)),
11736                            GregDay(734_046, Date(2010, 10, 1)),
11737                            GregDay(734_076, Date(2010, 10, 31)),
11738                            GregDay(734_077, Date(2010, 11, 1)),
11739                            GregDay(734_106, Date(2010, 11, 30)),
11740                            GregDay(734_107, Date(2010, 12, 1)),
11741                            GregDay(734_136, Date(2010, 12, 30)),
11742                            GregDay(734_137, Date(2010, 12, 31)),
11743                            GregDay(734_503, Date(2012, 1, 1)),
11744                            GregDay(734_534, Date(2012, 2, 1)),
11745                            GregDay(734_561, Date(2012, 2, 28)),
11746                            GregDay(734_562, Date(2012, 2, 29)),
11747                            GregDay(734_563, Date(2012, 3, 1)),
11748                            GregDay(734_858, Date(2012, 12, 21))];
11749        return result;
11750     }
11751 
11752     // I'd use a Tuple, but I get forward reference errors if I try.
11753     struct DayOfYear { int day; MonthDay md; }
11754     DayOfYear[] testDaysOfYear()
11755     {
11756        static result = [DayOfYear(1, MonthDay(1, 1)),
11757                            DayOfYear(2, MonthDay(1, 2)),
11758                            DayOfYear(3, MonthDay(1, 3)),
11759                            DayOfYear(31, MonthDay(1, 31)),
11760                            DayOfYear(32, MonthDay(2, 1)),
11761                            DayOfYear(59, MonthDay(2, 28)),
11762                            DayOfYear(60, MonthDay(3, 1)),
11763                            DayOfYear(90, MonthDay(3, 31)),
11764                            DayOfYear(91, MonthDay(4, 1)),
11765                            DayOfYear(120, MonthDay(4, 30)),
11766                            DayOfYear(121, MonthDay(5, 1)),
11767                            DayOfYear(151, MonthDay(5, 31)),
11768                            DayOfYear(152, MonthDay(6, 1)),
11769                            DayOfYear(181, MonthDay(6, 30)),
11770                            DayOfYear(182, MonthDay(7, 1)),
11771                            DayOfYear(212, MonthDay(7, 31)),
11772                            DayOfYear(213, MonthDay(8, 1)),
11773                            DayOfYear(243, MonthDay(8, 31)),
11774                            DayOfYear(244, MonthDay(9, 1)),
11775                            DayOfYear(273, MonthDay(9, 30)),
11776                            DayOfYear(274, MonthDay(10, 1)),
11777                            DayOfYear(304, MonthDay(10, 31)),
11778                            DayOfYear(305, MonthDay(11, 1)),
11779                            DayOfYear(334, MonthDay(11, 30)),
11780                            DayOfYear(335, MonthDay(12, 1)),
11781                            DayOfYear(363, MonthDay(12, 29)),
11782                            DayOfYear(364, MonthDay(12, 30)),
11783                            DayOfYear(365, MonthDay(12, 31))];
11784        return result;
11785     }
11786 
11787     DayOfYear[] testDaysOfLeapYear()
11788     {
11789        static result = [DayOfYear(1, MonthDay(1, 1)),
11790                                DayOfYear(2, MonthDay(1, 2)),
11791                                DayOfYear(3, MonthDay(1, 3)),
11792                                DayOfYear(31, MonthDay(1, 31)),
11793                                DayOfYear(32, MonthDay(2, 1)),
11794                                DayOfYear(59, MonthDay(2, 28)),
11795                                DayOfYear(60, MonthDay(2, 29)),
11796                                DayOfYear(61, MonthDay(3, 1)),
11797                                DayOfYear(91, MonthDay(3, 31)),
11798                                DayOfYear(92, MonthDay(4, 1)),
11799                                DayOfYear(121, MonthDay(4, 30)),
11800                                DayOfYear(122, MonthDay(5, 1)),
11801                                DayOfYear(152, MonthDay(5, 31)),
11802                                DayOfYear(153, MonthDay(6, 1)),
11803                                DayOfYear(182, MonthDay(6, 30)),
11804                                DayOfYear(183, MonthDay(7, 1)),
11805                                DayOfYear(213, MonthDay(7, 31)),
11806                                DayOfYear(214, MonthDay(8, 1)),
11807                                DayOfYear(244, MonthDay(8, 31)),
11808                                DayOfYear(245, MonthDay(9, 1)),
11809                                DayOfYear(274, MonthDay(9, 30)),
11810                                DayOfYear(275, MonthDay(10, 1)),
11811                                DayOfYear(305, MonthDay(10, 31)),
11812                                DayOfYear(306, MonthDay(11, 1)),
11813                                DayOfYear(335, MonthDay(11, 30)),
11814                                DayOfYear(336, MonthDay(12, 1)),
11815                                DayOfYear(364, MonthDay(12, 29)),
11816                                DayOfYear(365, MonthDay(12, 30)),
11817                                DayOfYear(366, MonthDay(12, 31))];
11818        return result;
11819     }
11820 
11821     void initializeTests()
11822     {
11823         import std.algorithm.sorting : sort;
11824         import std.typecons : Rebindable;
11825         immutable lt = LocalTime().utcToTZ(0);
11826         currLocalDiffFromUTC = dur!"hnsecs"(lt);
11827 
11828         version (Posix)
11829         {
11830             import std.datetime.timezone : PosixTimeZone;
11831             immutable otherTZ = lt < 0 ? PosixTimeZone.getTimeZone("Australia/Sydney")
11832                                        : PosixTimeZone.getTimeZone("America/Denver");
11833         }
11834         else version (Windows)
11835         {
11836             import std.datetime.timezone : WindowsTimeZone;
11837             immutable otherTZ = lt < 0 ? WindowsTimeZone.getTimeZone("AUS Eastern Standard Time")
11838                                        : WindowsTimeZone.getTimeZone("Mountain Standard Time");
11839         }
11840 
11841         immutable ot = otherTZ.utcToTZ(0);
11842 
11843         auto diffs = [0L, lt, ot];
11844         auto diffAA = [0L : Rebindable!(immutable TimeZone)(UTC())];
11845         diffAA[lt] = Rebindable!(immutable TimeZone)(LocalTime());
11846         diffAA[ot] = Rebindable!(immutable TimeZone)(otherTZ);
11847 
11848         sort(diffs);
11849         testTZs = [diffAA[diffs[0]], diffAA[diffs[1]], diffAA[diffs[2]]];
11850 
11851         testFracSecs = [Duration.zero, hnsecs(1), hnsecs(5007), hnsecs(9_999_999)];
11852 
11853         foreach (year; testYearsBC)
11854         {
11855             foreach (md; testMonthDays)
11856                 testDatesBC ~= Date(year, md.month, md.day);
11857         }
11858 
11859         foreach (year; testYearsAD)
11860         {
11861             foreach (md; testMonthDays)
11862                 testDatesAD ~= Date(year, md.month, md.day);
11863         }
11864 
11865         foreach (dt; testDatesBC)
11866         {
11867             foreach (tod; testTODs)
11868                 testDateTimesBC ~= DateTime(dt, tod);
11869         }
11870 
11871         foreach (dt; testDatesAD)
11872         {
11873             foreach (tod; testTODs)
11874                 testDateTimesAD ~= DateTime(dt, tod);
11875         }
11876 
11877         foreach (dt; testDateTimesBC)
11878         {
11879             foreach (tz; testTZs)
11880             {
11881                 foreach (fs; testFracSecs)
11882                     testSysTimesBC ~= SysTime(dt, fs, tz);
11883             }
11884         }
11885 
11886         foreach (dt; testDateTimesAD)
11887         {
11888             foreach (tz; testTZs)
11889             {
11890                 foreach (fs; testFracSecs)
11891                     testSysTimesAD ~= SysTime(dt, fs, tz);
11892             }
11893         }
11894     }
11895 }