1 /******************************************************************************
2 
3         Copyright:
4             Copyright (c) 2007 Tango contributors.
5             Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH.
6             All rights reserved.
7 
8         License:
9             Tango Dual License: 3-Clause BSD License / Academic Free License v3.0.
10             See LICENSE_TANGO.txt for details.
11 
12         Version:
13             mid 2005: Initial release
14             Apr 2007: heavily reshaped
15             Dec 2007: moved to ocean.time
16 
17         Authors: John Chapman, Kris, scheivguy
18 
19 ******************************************************************************/
20 
21 module ocean.time.Time;
22 
23 import core.time;
24 import core.stdc.time: time_t;
25 import ocean.meta.types.Qualifiers;
26 
27 version (unittest)
28 {
29     import core.stdc.time;
30     import ocean.core.Test;
31 }
32 
33 /******************************************************************************
34 
35     This struct represents a length of time.  The underlying representation is
36     in units of 100ns.  This allows the length of time to span to roughly
37     +/- 10000 years.
38 
39     Notably missing from this is a representation of weeks, months and years.
40     This is because weeks, months, and years vary according to local calendars.
41     Use ocean.time.chrono.* to deal with these concepts.
42 
43     Note: nobody should change this struct without really good reason as it is
44     required to be a part of some interfaces.  It should be treated as a
45     builtin type. Also note that there is deliberately no opCall constructor
46     here, since it tends to produce too much overhead.   If you wish to build
47     a TimeSpan struct from a ticks value, use D's builtin ability to create a
48     struct with given member values (See the description of ticks() for an
49     example of how to do this).
50 
51     Example:
52     -------------------
53     Time start = Clock.now;
54     Thread.sleep(0.150);
55     Stdout.formatln("slept for {} ms", (Clock.now-start).millis);
56     -------------------
57 
58     See_Also: ocean.core.Thread, ocean.time.Clock
59 
60 ******************************************************************************/
61 
62 struct TimeSpan
63 {
64         // this is the only member of the struct.
65         package Duration duration_;
66 
67         /// Convenience function (older compilers don't allow public alias to package)
68         public Duration duration () const { return this.duration_; }
69         /// Allow implicit conversion from `TimeSpan` to `Duration`
70         alias duration this;
71 
72         // useful constants.  Shouldn't be used in normal code, use the
73         // static TimeSpan members below instead.  i.e. instead of
74         // TimeSpan.TicksPerSecond, use TimeSpan.second.ticks
75         //
76         enum : long
77         {
78                 /// basic tick values
79                 NanosecondsPerTick  = 100,
80                 TicksPerMicrosecond = 1000 / NanosecondsPerTick,
81                 TicksPerMillisecond = 1000 * TicksPerMicrosecond,
82                 TicksPerSecond      = 1000 * TicksPerMillisecond,
83                 TicksPerMinute      = 60 * TicksPerSecond,
84                 TicksPerHour        = 60 * TicksPerMinute,
85                 TicksPerDay         = 24 * TicksPerHour,
86 
87                 // millisecond counts
88                 MillisPerSecond     = 1000,
89                 MillisPerMinute     = MillisPerSecond * 60,
90                 MillisPerHour       = MillisPerMinute * 60,
91                 MillisPerDay        = MillisPerHour * 24,
92 
93                 /// day counts
94                 DaysPerYear         = 365,
95                 DaysPer4Years       = DaysPerYear * 4 + 1,
96                 DaysPer100Years     = DaysPer4Years * 25 - 1,
97                 DaysPer400Years     = DaysPer100Years * 4 + 1,
98 
99                 // epoch counts
100                 Epoch1601           = DaysPer400Years * 4 * TicksPerDay,
101                 Epoch1970           = Epoch1601 + TicksPerSecond * 11644473600L,
102         }
103 
104         /**
105          * Minimum TimeSpan
106          */
107         enum TimeSpan min = TimeSpan(Duration.min);
108 
109         /**
110          * Maximum TimeSpan
111          */
112         enum TimeSpan max = TimeSpan(Duration.max);
113 
114         /**
115          * Zero TimeSpan.  Useful for comparisons.
116          */
117         enum TimeSpan zero = TimeSpan(Duration.zero);
118 
119         /// Compatibility constructors
120         public this (long ticks)
121         {
122             this.duration_ = ticks.hnsecs;
123         }
124 
125         ///
126         public this (Duration dur)
127         {
128             this.duration_ = dur;
129         }
130 
131         /**
132          * Get the number of ticks that this timespan represents.
133          *
134          * A tick correspond to an hecto-nanosecond, or 100ns.
135          * This is the way this struct stores data internally,
136          * which is the representation `core.time : Duration` uses.
137          *
138          * This method can be used to construct another `TimeSpan`:
139          * --------
140          * long ticks = myTimeSpan.ticks;
141          * TimeSpan copyOfMyTimeSpan = TimeSpan(ticks);
142          * --------
143          *
144          * See_Also:
145          * https://dlang.org/phobos/core_time.html
146          */
147         long ticks()
148         {
149             return this.duration_.total!"hnsecs";
150         }
151 
152         /**
153          * Determines whether two TimeSpan values are equal
154          */
155         public bool opEquals (in TimeSpan t) const scope
156         {
157                 return this.duration_ == t.duration_;
158         }
159 
160         /**
161          * Compares this object against another TimeSpan value.
162          */
163         public int opCmp (const typeof(this) rhs) const scope
164         {
165             return this.duration_.opCmp(rhs.duration_);
166         }
167 
168         /**
169          * Add or subtract the TimeSpan given to this TimeSpan returning a
170          * new TimeSpan.
171          *
172          * Params:  op = operation to perform
173          *          t = A TimeSpan value to add or subtract
174          * Returns: A TimeSpan value that is the result of this instance, the
175          *          operation, and t.
176          */
177         public TimeSpan opBinary (string op) (in TimeSpan t) const scope
178             if (op == "+" || op == "-")
179         {
180             mixin("return TimeSpan(this.duration_ " ~ op ~ " t.duration_);");
181         }
182 
183         unittest
184         {
185             TimeSpan time_span;
186             time_span.duration_ = 5.hnsecs;
187 
188             TimeSpan test_span;
189             test_span.duration_ = 10.hnsecs;
190 
191             auto res = time_span + test_span;
192             test!("==")(res.ticks(), 15);
193 
194             test_span.duration_ = 3.hnsecs;
195 
196             res = time_span - test_span;
197             test!("==")(res.ticks(), 2);
198         }
199 
200         /**
201          * Add or subtract the specified TimeSpan to this TimeSpan, assigning
202          * the result to this instance.
203          *
204          * Params:  op = operation to perform
205          *          t = A TimeSpan value to add or subtract
206          * Returns: a copy of this instance after adding or subtracting t.
207          */
208 
209         TimeSpan opOpAssign (string op) (TimeSpan t) if (op == "+" || op == "-")
210         {
211             mixin("duration_ " ~ op ~ "= t.duration_;");
212             return this;
213         }
214 
215         unittest
216         {
217             TimeSpan time_span;
218             time_span.duration_ = 5.hnsecs;
219 
220             TimeSpan test_span;
221             test_span.duration_ = 10.hnsecs;
222 
223             time_span += test_span;
224             test!("==")(time_span.ticks(), 15);
225 
226             test_span.duration_ = 3.hnsecs;
227 
228             time_span -= test_span;
229             test!("==")(time_span.ticks(), 12);
230         }
231 
232         /**
233          * Scale the TimeSpan by the specified amount.  This should not be
234          * used to convert to a different unit.  Use the unit accessors
235          * instead.  This should only be used as a scaling mechanism.  For
236          * example, if you have a timeout and you want to sleep for twice the
237          * timeout, you would use timeout * 2. Returns a new TimeSpan.
238          *
239          * Params: op = operation to perform
240          *         v = A multiplier or divisor to use for scaling this time span.
241          * Returns: A new TimeSpan that is scaled by v
242          */
243         public TimeSpan opBinary (string op) (long v) const scope
244             if (op == "*" || op == "/")
245         {
246                 mixin("return TimeSpan(duration_ " ~ op ~ " v);");
247         }
248 
249         unittest
250         {
251             TimeSpan time_span;
252             time_span.duration_ = 5.hnsecs;
253 
254             auto res = time_span * 10;
255             test!("==")(res.ticks(), 50);
256 
257             res = time_span / 5;
258             test!("==")(res.ticks(), 1);
259         }
260 
261         /**
262          * Scales this TimeSpan and assigns the result to this instance.
263          *
264          * Params: op = operation to perform
265          *         v = A multipler or divisor to use for scaling
266          * Returns: A copy of this instance after scaling
267          */
268         TimeSpan opOpAssign (string op) (long v) if (op == "*" || op == "/")
269         {
270                 mixin("duration_ " ~ op ~ "= v;");
271                 return this;
272         }
273 
274         unittest
275         {
276             TimeSpan time_span;
277             time_span.duration_ = 5.hnsecs;
278 
279             time_span *= 10;
280             test!("==")(time_span.ticks(), 50);
281 
282             time_span /= 5;
283             test!("==")(time_span.ticks(), 10);
284         }
285 
286         /**
287          * Perform integer division with the given time span.
288          *
289          * Params: op = operation to perform
290          *         t = A divisor used for dividing
291          * Returns: The result of integer division between this instance and
292          * t.
293          */
294         long opBinary (string op) (in TimeSpan t) const scope if (op == "/")
295         {
296             return duration_ / t.duration_;
297         }
298 
299         unittest
300         {
301             TimeSpan time_span;
302             time_span.duration_ = 10.hnsecs;
303 
304             TimeSpan test_span;
305             test_span.duration_ = 5.hnsecs;
306 
307             test!("==")(time_span / test_span, 2);
308         }
309 
310         /**
311          * Negate a time span. Returns a new TimeSpan.
312          *
313          * Params:  op = operation to perform
314          * Returns: The negative equivalent to this time span
315          */
316         TimeSpan opUnary (string op) () if (op == "-")
317         {
318                 return TimeSpan(-duration_);
319         }
320 
321         unittest
322         {
323             TimeSpan time_span;
324             time_span.duration_ = 10.hnsecs;
325 
326             auto res = (-time_span);
327 
328             test!("==")(res.ticks(), -10);
329         }
330 
331         /**
332          * Convert to nanoseconds
333          *
334          * Note: this may incur loss of data because nanoseconds cannot
335          * represent the range of data a TimeSpan can represent.
336          *
337          * Returns: The number of nanoseconds that this TimeSpan represents.
338          */
339         long nanos()
340         {
341             return duration_.total!"nsecs";
342         }
343 
344         /**
345          * Convert to microseconds
346          *
347          * Returns: The number of microseconds that this TimeSpan represents.
348          */
349         long micros()
350         {
351             return duration_.total!"usecs";
352         }
353 
354         /**
355          * Convert to milliseconds
356          *
357          * Returns: The number of milliseconds that this TimeSpan represents.
358          */
359         long millis()
360         {
361             return duration_.total!"msecs";
362         }
363 
364         /**
365          * Convert to seconds
366          *
367          * Returns: The number of seconds that this TimeSpan represents.
368          */
369         long seconds()
370         {
371             return duration_.total!"seconds";
372         }
373 
374         /**
375          * Convert to minutes
376          *
377          * Returns: The number of minutes that this TimeSpan represents.
378          */
379         long minutes()
380         {
381             return duration_.total!"minutes";
382         }
383 
384         /**
385          * Convert to hours
386          *
387          * Returns: The number of hours that this TimeSpan represents.
388          */
389         long hours()
390         {
391             return duration_.total!"hours";
392         }
393 
394         /**
395          * Convert to days
396          *
397          * Returns: The number of days that this TimeSpan represents.
398          */
399         long days()
400         {
401             return duration_.total!"days";
402         }
403 
404         /**
405          * Convert to a floating point interval representing seconds.
406          *
407          * Note: This may cause a loss of precision as a double cannot exactly
408          * represent some fractional values.
409          *
410          * Returns: An interval representing the seconds and fractional
411          * seconds that this TimeSpan represents.
412          */
413         double interval()
414         {
415             return (cast(double) duration_.total!"hnsecs") / TicksPerSecond;
416         }
417 
418         /**
419          * Convert to TimeOfDay
420          *
421          * Returns: the TimeOfDay this TimeSpan represents.
422          */
423         TimeOfDay time()
424         {
425                 return TimeOfDay(duration_);
426         }
427 
428         /**
429          * Construct a TimeSpan from the given number of nanoseconds
430          *
431          * Note: This may cause a loss of data since a TimeSpan's resolution
432          * is in 100ns increments.
433          *
434          * Params: value = The number of nanoseconds.
435          * Returns: A TimeSpan representing the given number of nanoseconds.
436          */
437         static TimeSpan fromNanos(long value)
438         {
439             return TimeSpan(value.dur!"nsecs");
440         }
441 
442         /**
443          * Construct a TimeSpan from the given number of microseconds
444          *
445          * Params: value = The number of microseconds.
446          * Returns: A TimeSpan representing the given number of microseconds.
447          */
448         static TimeSpan fromMicros(long value)
449         {
450             return TimeSpan(value.dur!"usecs");
451         }
452 
453         /**
454          * Construct a TimeSpan from the given number of milliseconds
455          *
456          * Params: value = The number of milliseconds.
457          * Returns: A TimeSpan representing the given number of milliseconds.
458          */
459         static TimeSpan fromMillis(long value)
460         {
461                 return TimeSpan(value.dur!"msecs");
462         }
463 
464         /**
465          * Construct a TimeSpan from the given number of seconds
466          *
467          * Params: value = The number of seconds.
468          * Returns: A TimeSpan representing the given number of seconds.
469          */
470         static TimeSpan fromSeconds(long value)
471         {
472             return TimeSpan(value.dur!"seconds");
473         }
474 
475         /**
476          * Construct a TimeSpan from the given number of minutes
477          *
478          * Params: value = The number of minutes.
479          * Returns: A TimeSpan representing the given number of minutes.
480          */
481         static TimeSpan fromMinutes(long value)
482         {
483             return TimeSpan(value.dur!"minutes");
484         }
485 
486         /**
487          * Construct a TimeSpan from the given number of hours
488          *
489          * Params: value = The number of hours.
490          * Returns: A TimeSpan representing the given number of hours.
491          */
492         static TimeSpan fromHours(long value)
493         {
494             return TimeSpan(value.dur!"hours");
495         }
496 
497         /**
498          * Construct a TimeSpan from the given number of days
499          *
500          * Params: value = The number of days.
501          * Returns: A TimeSpan representing the given number of days.
502          */
503         static TimeSpan fromDays(long value)
504         {
505             return TimeSpan(value.dur!"days");
506         }
507 
508         /**
509          * Construct a TimeSpan from the given interval.  The interval
510          * represents seconds as a double.  This allows both whole and
511          * fractional seconds to be passed in.
512          *
513          * Params: sec = The interval to convert in seconds.
514          * Returns: A TimeSpan representing the given interval.
515          */
516         static TimeSpan fromInterval(double sec)
517         {
518             return TimeSpan((cast(long)(sec * TicksPerSecond + .1)).dur!"hnsecs");
519         }
520 }
521 
522 
523 /******************************************************************************
524 
525         Represents a point in time.
526 
527         Remarks: Time represents dates and times between 12:00:00
528         midnight on January 1, 10000 BC and 11:59:59 PM on December 31,
529         9999 AD.
530 
531         Time values are measured in 100-nanosecond intervals, or ticks.
532         A date value is the number of ticks that have elapsed since
533         12:00:00 midnight on January 1, 0001 AD in the Gregorian
534         calendar.
535 
536         Negative Time values are offsets from that same reference point,
537         but backwards in history.  Time values are not specific to any
538         calendar, but for an example, the beginning of December 31, 1 BC
539         in the Gregorian calendar is Time.epoch - TimeSpan.days(1).
540 
541 ******************************************************************************/
542 
543 struct Time
544 {
545         private long ticks_;
546 
547         private enum : long
548         {
549                 maximum = (TimeSpan.DaysPer400Years * 25 - 366) * TimeSpan.TicksPerDay - 1,
550                 minimum = -((TimeSpan.DaysPer400Years * 25 - 366) * TimeSpan.TicksPerDay - 1),
551         }
552 
553         /// Represents the smallest and largest Time value.
554         enum Time min       = {minimum},
555                           max       = {maximum};
556 
557         /// Represents the epoch (1/1/0001)
558         enum Time epoch     = {0};
559 
560         /// Represents the epoch of 1/1/1601 (Commonly used in Windows systems)
561         enum Time epoch1601 = {TimeSpan.Epoch1601};
562 
563         /// Represents the epoch of 1/1/1970 (Commonly used in Unix systems)
564         enum Time epoch1970 = {TimeSpan.Epoch1970};
565 
566         /**********************************************************************
567 
568                 $(I Property.) Retrieves the number of ticks for this Time.
569                 This value can be used to construct another Time struct by
570                 writing:
571 
572                 ---------
573                 long ticks = myTime.ticks;
574                 Time copyOfMyTime = Time(ticks);
575                 ---------
576 
577 
578                 Returns: A long represented by the time of this
579                          instance.
580 
581         **********************************************************************/
582 
583         long ticks ()
584         {
585                 return ticks_;
586         }
587 
588         /**********************************************************************
589 
590                 Determines whether two Time values are equal.
591 
592                 Params:  t = A Time _value.
593                 Returns: true if both instances are equal; otherwise, false
594 
595         **********************************************************************/
596 
597         public bool opEquals (in Time t) const scope
598         {
599             return this.ticks_ is t.ticks_;
600         }
601 
602         /**********************************************************************
603 
604                 Compares two Time values.
605 
606         **********************************************************************/
607 
608         public int opCmp (Time t) const scope
609         {
610             if (this.ticks_ < t.ticks_)
611                 return -1;
612 
613             if (this.ticks_ > t.ticks_)
614                 return 1;
615 
616             return 0;
617         }
618 
619         /**********************************************************************
620 
621                 Adds or subtracts the specified time span to the time,
622                 returning a new time.
623 
624                 Params:  op = operation to perform
625                          t = A TimeSpan value.
626                 Returns: A Time that is the sum or difference of this instance
627                          and t.
628 
629         **********************************************************************/
630 
631         Time opBinary (string op) (in TimeSpan t) const scope
632             if (op == "+" || op == "-")
633         {
634             mixin("return Time(ticks_ " ~ op ~ " t.duration_.total!`hnsecs`);");
635         }
636 
637         unittest
638         {
639             Time time_span;
640             time_span.ticks_ = 5;
641 
642             TimeSpan test_span;
643             test_span.duration_ = 10.dur!"hnsecs";
644 
645             auto res = time_span + test_span;
646             test!("==")(res.ticks(), 15);
647 
648             test_span.duration_ = 3.dur!"hnsecs";
649 
650             res = time_span - test_span;
651             test!("==")(res.ticks(), 2);
652         }
653 
654         /**********************************************************************
655 
656                 Adds or subtracts the specified time span to the time, assigning
657                 the result to this instance.
658 
659                 Params:  op = operation to perform
660                          t = A TimeSpan value.
661                 Returns: The current Time instance, with t added or subtracted
662                          to the time.
663 
664         **********************************************************************/
665 
666         Time opOpAssign (string op) (TimeSpan t) if (op == "+" || op == "-")
667         {
668                 mixin("ticks_ " ~ op ~ "= t.duration_.total!`hnsecs`;");
669                 return this;
670         }
671 
672         unittest
673         {
674             Time time_span;
675             time_span.ticks_ = 5;
676 
677             TimeSpan test_span;
678             test_span.duration_ = 10.dur!"hnsecs";
679 
680             time_span += test_span;
681             test!("==")(time_span.ticks(), 15);
682 
683             test_span.duration_ = 3.dur!"hnsecs";
684 
685             time_span -= test_span;
686             test!("==")(time_span.ticks(), 12);
687         }
688 
689         /**********************************************************************
690 
691                 Returns a time span which represents the difference in time
692                 between this and the given Time.
693 
694                 Params:  op = operation to perform
695                          t = A Time value.
696                 Returns: A TimeSpan which represents the difference between
697                          this and t.
698 
699         **********************************************************************/
700 
701         public TimeSpan opBinary (string op) (in Time t) const scope
702             if (op == "-")
703         {
704             return TimeSpan((ticks_ - t.ticks_).dur!"hnsecs");
705         }
706 
707         unittest
708         {
709             Time time_span;
710             time_span.ticks_ = 5;
711 
712             TimeSpan test_span;
713             test_span.duration_ = 3.dur!"hnsecs";
714 
715             auto res = time_span - test_span;
716             test!("==")(res.ticks(), 2);
717         }
718 
719         /**********************************************************************
720 
721                 $(I Property.) Retrieves the date component.
722 
723                 Returns: A new Time instance with the same date as
724                          this instance, but with the time truncated.
725 
726         **********************************************************************/
727 
728         Time date ()
729         {
730                 return this - TimeOfDay.modulo24(ticks_);
731         }
732 
733         /**********************************************************************
734 
735                 $(I Property.) Retrieves the time of day.
736 
737                 Returns: A TimeOfDay representing the fraction of the day
738                          elapsed since midnight.
739 
740         **********************************************************************/
741 
742         TimeOfDay time ()
743         {
744                 return TimeOfDay (ticks_);
745         }
746 
747         /**********************************************************************
748 
749                 $(I Property.) Retrieves the equivalent TimeSpan.
750 
751                 Returns: A TimeSpan representing this Time.
752 
753         **********************************************************************/
754 
755         TimeSpan span ()
756         {
757                 return TimeSpan (ticks_);
758         }
759 
760         /**********************************************************************
761 
762                 $(I Property.) Retrieves a TimeSpan that corresponds to Unix
763                 time (time since 1/1/1970).  Use the TimeSpan accessors to get
764                 the time in seconds, milliseconds, etc.
765 
766                 Returns: A TimeSpan representing this Time as Unix time.
767 
768                 -------------------------------------
769                 auto unixTime = Clock.now.unix.seconds;
770                 auto javaTime = Clock.now.unix.millis;
771                 -------------------------------------
772 
773         **********************************************************************/
774 
775         TimeSpan unix()
776         {
777                 return TimeSpan(ticks_ - epoch1970.ticks_);
778         }
779 
780         /**********************************************************************
781 
782             Constructs a Time instance from the Unix time (time since 1/1/1970).
783 
784             Params:
785                 unix_time = number of seconds since 1/1/1970
786 
787             Returns:
788                 Time instance corresponding the given unix time.
789 
790         ***********************************************************************/
791 
792         static Time fromUnixTime (time_t unix_time)
793         {
794             return Time(epoch1970.ticks_ + unix_time * TimeSpan.TicksPerSecond);
795         }
796 }
797 
798 
799 /******************************************************************************
800 
801         Represents a time of day. This is different from TimeSpan in that
802         each component is represented within the limits of everyday time,
803         rather than from the start of the Epoch. Effectively, the TimeOfDay
804         epoch is the first second of each day.
805 
806         This is handy for dealing strictly with a 24-hour clock instead of
807         potentially thousands of years. For example:
808         ---
809         auto time = Clock.now.time;
810         assert (time.millis < 1000);
811         assert (time.seconds < 60);
812         assert (time.minutes < 60);
813         assert (time.hours < 24);
814         ---
815 
816         You can create a TimeOfDay from an existing Time or TimeSpan instance
817         via the respective time() method. To convert back to a TimeSpan, use
818         the span() method
819 
820 ******************************************************************************/
821 
822 struct TimeOfDay
823 {
824         /**
825          * hours component of the time of day.  This should be between 0 and
826          * 23, inclusive.
827          */
828         public uint     hours;
829 
830         /**
831          * minutes component of the time of day.  This should be between 0 and
832          * 59, inclusive.
833          */
834         public uint     minutes;
835 
836         /**
837          * seconds component of the time of day.  This should be between 0 and
838          * 59, inclusive.
839          */
840         public uint     seconds;
841 
842         /**
843          * milliseconds component of the time of day.  This should be between
844          * 0 and 999, inclusive.
845          */
846         public uint     millis;
847 
848         /**
849          * constructor.
850          * Params: hours = number of hours since midnight
851          *         minutes = number of minutes into the hour
852          *         seconds = number of seconds into the minute
853          *         millis = number of milliseconds into the second
854          *
855          * Returns: a TimeOfDay representing the given time fields.
856          *
857          * Note: There is no verification of the range of values, or
858          * normalization made.  So if you pass in larger values than the
859          * maximum value for that field, they will be stored as that value.
860          *
861          * example:
862          * --------------
863          * auto tod = TimeOfDay(100, 100, 100, 10000);
864          * assert(tod.hours == 100);
865          * assert(tod.minutes == 100);
866          * assert(tod.seconds == 100);
867          * assert(tod.millis == 10000);
868          * --------------
869          */
870         static TimeOfDay opCall (uint hours, uint minutes, uint seconds, uint millis=0)
871         {
872                 TimeOfDay t = void;
873                 t.hours   = hours;
874                 t.minutes = minutes;
875                 t.seconds = seconds;
876                 t.millis  = millis;
877                 return t;
878         }
879 
880         /**
881          * constructor.
882          * Params: ticks = ticks representing a Time value.  This is normalized
883          * so that it represent a time of day (modulo-24 etc)
884          *
885          * Returns: a TimeOfDay value that corresponds to the time of day of
886          * the given number of ticks.
887          */
888         static TimeOfDay opCall (long ticks)
889         {
890             return TimeOfDay(modulo24(ticks));
891         }
892 
893         /// Ditto
894         static TimeOfDay opCall (Duration dur)
895         {
896             // Note: Since this represents a time of day, hours needs to be
897             // 0 <= hours < 24. Using `days` ensures that, even if we don't
898             // use the value.
899             auto splitted = dur.split!("days", "hours", "minutes", "seconds", "msecs");
900             return TimeOfDay(cast(uint)splitted.hours, cast(uint)splitted.minutes,
901                              cast(uint)splitted.seconds, cast(uint)splitted.msecs);
902         }
903 
904         /**
905          * construct a TimeSpan from the current fields
906          *
907          * Returns: a TimeOfDay representing the field values.
908          *
909          * Note: that fields are not checked against a valid range, so
910          * setting 60 for minutes is allowed, and will just add 1 to the hour
911          * component, and set the minute component to 0.  The result is
912          * normalized, so the hours wrap.  If you pass in 25 hours, the
913          * resulting TimeOfDay will have a hour component of 1.
914          */
915         TimeSpan span ()
916         {
917                 return TimeSpan.fromHours(hours) +
918                        TimeSpan.fromMinutes(minutes) +
919                        TimeSpan.fromSeconds(seconds) +
920                        TimeSpan.fromMillis(millis);
921         }
922 
923         /**
924          * internal routine to adjust ticks by one day. Also adjusts for
925          * offsets in the BC era
926          */
927         package static TimeSpan modulo24 (long ticks)
928         {
929                 ticks %= TimeSpan.TicksPerDay;
930                 if (ticks < 0)
931                     ticks += TimeSpan.TicksPerDay;
932                 return TimeSpan (ticks);
933         }
934 }
935 
936 /******************************************************************************
937 
938     Generic Date representation
939 
940 ******************************************************************************/
941 
942 struct Date
943 {
944         public uint         era,            /// AD, BC
945                             day,            /// 1 .. 31
946                             year,           /// 0 to 9999
947                             month,          /// 1 .. 12
948                             dow,            /// 0 .. 6
949                             doy;            /// 1 .. 366
950 }
951 
952 
953 /******************************************************************************
954 
955     Combination of a Date and a TimeOfDay
956 
957 ******************************************************************************/
958 
959 struct DateTime
960 {
961         public Date         date;       /// date representation
962         public TimeOfDay    time;       /// time representation
963 }
964 
965 unittest
966 {
967     auto unix = time(null);
968 
969     test!("==")((Time.fromUnixTime(unix) - Time.epoch1970).seconds, unix);
970 }