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         equals_t opEquals(TimeSpan t)
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
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         TimeSpan opBinary (string op) (TimeSpan t) if (op == "+" || op == "-")
178         {
179             mixin("return TimeSpan(this.duration_ " ~ op ~ " t.duration_);");
180         }
181 
182         unittest
183         {
184             TimeSpan time_span;
185             time_span.duration_ = 5.hnsecs;
186 
187             TimeSpan test_span;
188             test_span.duration_ = 10.hnsecs;
189 
190             auto res = time_span + test_span;
191             test!("==")(res.ticks(), 15);
192 
193             test_span.duration_ = 3.hnsecs;
194 
195             res = time_span - test_span;
196             test!("==")(res.ticks(), 2);
197         }
198 
199         /**
200          * Add or subtract the specified TimeSpan to this TimeSpan, assigning
201          * the result to this instance.
202          *
203          * Params:  op = operation to perform
204          *          t = A TimeSpan value to add or subtract
205          * Returns: a copy of this instance after adding or subtracting t.
206          */
207 
208         TimeSpan opOpAssign (string op) (TimeSpan t) if (op == "+" || op == "-")
209         {
210             mixin("duration_ " ~ op ~ "= t.duration_;");
211             return this;
212         }
213 
214         unittest
215         {
216             TimeSpan time_span;
217             time_span.duration_ = 5.hnsecs;
218 
219             TimeSpan test_span;
220             test_span.duration_ = 10.hnsecs;
221 
222             time_span += test_span;
223             test!("==")(time_span.ticks(), 15);
224 
225             test_span.duration_ = 3.hnsecs;
226 
227             time_span -= test_span;
228             test!("==")(time_span.ticks(), 12);
229         }
230 
231         /**
232          * Scale the TimeSpan by the specified amount.  This should not be
233          * used to convert to a different unit.  Use the unit accessors
234          * instead.  This should only be used as a scaling mechanism.  For
235          * example, if you have a timeout and you want to sleep for twice the
236          * timeout, you would use timeout * 2. Returns a new TimeSpan.
237          *
238          * Params: op = operation to perform
239          *         v = A multiplier or divisor to use for scaling this time span.
240          * Returns: A new TimeSpan that is scaled by v
241          */
242         TimeSpan opBinary (string op) (long v) if (op == "*" || op == "/")
243         {
244                 mixin("return TimeSpan(duration_ " ~ op ~ " v);");
245         }
246 
247         unittest
248         {
249             TimeSpan time_span;
250             time_span.duration_ = 5.hnsecs;
251 
252             auto res = time_span * 10;
253             test!("==")(res.ticks(), 50);
254 
255             res = time_span / 5;
256             test!("==")(res.ticks(), 1);
257         }
258 
259         /**
260          * Scales this TimeSpan and assigns the result to this instance.
261          *
262          * Params: op = operation to perform
263          *         v = A multipler or divisor to use for scaling
264          * Returns: A copy of this instance after scaling
265          */
266         TimeSpan opOpAssign (string op) (long v) if (op == "*" || op == "/")
267         {
268                 mixin("duration_ " ~ op ~ "= v;");
269                 return this;
270         }
271 
272         unittest
273         {
274             TimeSpan time_span;
275             time_span.duration_ = 5.hnsecs;
276 
277             time_span *= 10;
278             test!("==")(time_span.ticks(), 50);
279 
280             time_span /= 5;
281             test!("==")(time_span.ticks(), 10);
282         }
283 
284         /**
285          * Perform integer division with the given time span.
286          *
287          * Params: op = operation to perform
288          *         t = A divisor used for dividing
289          * Returns: The result of integer division between this instance and
290          * t.
291          */
292         long opBinary (string op) (TimeSpan t) if (op == "/")
293         {
294             return duration_ / t.duration_;
295         }
296 
297         unittest
298         {
299             TimeSpan time_span;
300             time_span.duration_ = 10.hnsecs;
301 
302             TimeSpan test_span;
303             test_span.duration_ = 5.hnsecs;
304 
305             test!("==")(time_span / test_span, 2);
306         }
307 
308         /**
309          * Negate a time span. Returns a new TimeSpan.
310          *
311          * Params:  op = operation to perform
312          * Returns: The negative equivalent to this time span
313          */
314         TimeSpan opUnary (string op) () if (op == "-")
315         {
316                 return TimeSpan(-duration_);
317         }
318 
319         unittest
320         {
321             TimeSpan time_span;
322             time_span.duration_ = 10.hnsecs;
323 
324             auto res = (-time_span);
325 
326             test!("==")(res.ticks(), -10);
327         }
328 
329         /**
330          * Convert to nanoseconds
331          *
332          * Note: this may incur loss of data because nanoseconds cannot
333          * represent the range of data a TimeSpan can represent.
334          *
335          * Returns: The number of nanoseconds that this TimeSpan represents.
336          */
337         long nanos()
338         {
339             return duration_.total!"nsecs";
340         }
341 
342         /**
343          * Convert to microseconds
344          *
345          * Returns: The number of microseconds that this TimeSpan represents.
346          */
347         long micros()
348         {
349             return duration_.total!"usecs";
350         }
351 
352         /**
353          * Convert to milliseconds
354          *
355          * Returns: The number of milliseconds that this TimeSpan represents.
356          */
357         long millis()
358         {
359             return duration_.total!"msecs";
360         }
361 
362         /**
363          * Convert to seconds
364          *
365          * Returns: The number of seconds that this TimeSpan represents.
366          */
367         long seconds()
368         {
369             return duration_.total!"seconds";
370         }
371 
372         /**
373          * Convert to minutes
374          *
375          * Returns: The number of minutes that this TimeSpan represents.
376          */
377         long minutes()
378         {
379             return duration_.total!"minutes";
380         }
381 
382         /**
383          * Convert to hours
384          *
385          * Returns: The number of hours that this TimeSpan represents.
386          */
387         long hours()
388         {
389             return duration_.total!"hours";
390         }
391 
392         /**
393          * Convert to days
394          *
395          * Returns: The number of days that this TimeSpan represents.
396          */
397         long days()
398         {
399             return duration_.total!"days";
400         }
401 
402         /**
403          * Convert to a floating point interval representing seconds.
404          *
405          * Note: This may cause a loss of precision as a double cannot exactly
406          * represent some fractional values.
407          *
408          * Returns: An interval representing the seconds and fractional
409          * seconds that this TimeSpan represents.
410          */
411         double interval()
412         {
413             return (cast(double) duration_.total!"hnsecs") / TicksPerSecond;
414         }
415 
416         /**
417          * Convert to TimeOfDay
418          *
419          * Returns: the TimeOfDay this TimeSpan represents.
420          */
421         TimeOfDay time()
422         {
423                 return TimeOfDay(duration_);
424         }
425 
426         /**
427          * Construct a TimeSpan from the given number of nanoseconds
428          *
429          * Note: This may cause a loss of data since a TimeSpan's resolution
430          * is in 100ns increments.
431          *
432          * Params: value = The number of nanoseconds.
433          * Returns: A TimeSpan representing the given number of nanoseconds.
434          */
435         static TimeSpan fromNanos(long value)
436         {
437             return TimeSpan(value.dur!"nsecs");
438         }
439 
440         /**
441          * Construct a TimeSpan from the given number of microseconds
442          *
443          * Params: value = The number of microseconds.
444          * Returns: A TimeSpan representing the given number of microseconds.
445          */
446         static TimeSpan fromMicros(long value)
447         {
448             return TimeSpan(value.dur!"usecs");
449         }
450 
451         /**
452          * Construct a TimeSpan from the given number of milliseconds
453          *
454          * Params: value = The number of milliseconds.
455          * Returns: A TimeSpan representing the given number of milliseconds.
456          */
457         static TimeSpan fromMillis(long value)
458         {
459                 return TimeSpan(value.dur!"msecs");
460         }
461 
462         /**
463          * Construct a TimeSpan from the given number of seconds
464          *
465          * Params: value = The number of seconds.
466          * Returns: A TimeSpan representing the given number of seconds.
467          */
468         static TimeSpan fromSeconds(long value)
469         {
470             return TimeSpan(value.dur!"seconds");
471         }
472 
473         /**
474          * Construct a TimeSpan from the given number of minutes
475          *
476          * Params: value = The number of minutes.
477          * Returns: A TimeSpan representing the given number of minutes.
478          */
479         static TimeSpan fromMinutes(long value)
480         {
481             return TimeSpan(value.dur!"minutes");
482         }
483 
484         /**
485          * Construct a TimeSpan from the given number of hours
486          *
487          * Params: value = The number of hours.
488          * Returns: A TimeSpan representing the given number of hours.
489          */
490         static TimeSpan fromHours(long value)
491         {
492             return TimeSpan(value.dur!"hours");
493         }
494 
495         /**
496          * Construct a TimeSpan from the given number of days
497          *
498          * Params: value = The number of days.
499          * Returns: A TimeSpan representing the given number of days.
500          */
501         static TimeSpan fromDays(long value)
502         {
503             return TimeSpan(value.dur!"days");
504         }
505 
506         /**
507          * Construct a TimeSpan from the given interval.  The interval
508          * represents seconds as a double.  This allows both whole and
509          * fractional seconds to be passed in.
510          *
511          * Params: sec = The interval to convert in seconds.
512          * Returns: A TimeSpan representing the given interval.
513          */
514         static TimeSpan fromInterval(double sec)
515         {
516             return TimeSpan((cast(long)(sec * TicksPerSecond + .1)).dur!"hnsecs");
517         }
518 }
519 
520 
521 /******************************************************************************
522 
523         Represents a point in time.
524 
525         Remarks: Time represents dates and times between 12:00:00
526         midnight on January 1, 10000 BC and 11:59:59 PM on December 31,
527         9999 AD.
528 
529         Time values are measured in 100-nanosecond intervals, or ticks.
530         A date value is the number of ticks that have elapsed since
531         12:00:00 midnight on January 1, 0001 AD in the Gregorian
532         calendar.
533 
534         Negative Time values are offsets from that same reference point,
535         but backwards in history.  Time values are not specific to any
536         calendar, but for an example, the beginning of December 31, 1 BC
537         in the Gregorian calendar is Time.epoch - TimeSpan.days(1).
538 
539 ******************************************************************************/
540 
541 struct Time
542 {
543         private long ticks_;
544 
545         private enum : long
546         {
547                 maximum = (TimeSpan.DaysPer400Years * 25 - 366) * TimeSpan.TicksPerDay - 1,
548                 minimum = -((TimeSpan.DaysPer400Years * 25 - 366) * TimeSpan.TicksPerDay - 1),
549         }
550 
551         /// Represents the smallest and largest Time value.
552         enum Time min       = {minimum},
553                           max       = {maximum};
554 
555         /// Represents the epoch (1/1/0001)
556         enum Time epoch     = {0};
557 
558         /// Represents the epoch of 1/1/1601 (Commonly used in Windows systems)
559         enum Time epoch1601 = {TimeSpan.Epoch1601};
560 
561         /// Represents the epoch of 1/1/1970 (Commonly used in Unix systems)
562         enum Time epoch1970 = {TimeSpan.Epoch1970};
563 
564         /**********************************************************************
565 
566                 $(I Property.) Retrieves the number of ticks for this Time.
567                 This value can be used to construct another Time struct by
568                 writing:
569 
570                 ---------
571                 long ticks = myTime.ticks;
572                 Time copyOfMyTime = Time(ticks);
573                 ---------
574 
575 
576                 Returns: A long represented by the time of this
577                          instance.
578 
579         **********************************************************************/
580 
581         long ticks ()
582         {
583                 return ticks_;
584         }
585 
586         /**********************************************************************
587 
588                 Determines whether two Time values are equal.
589 
590                 Params:  t = A Time _value.
591                 Returns: true if both instances are equal; otherwise, false
592 
593         **********************************************************************/
594 
595         int opEquals (Time t)
596         {
597                 return ticks_ is t.ticks_;
598         }
599 
600         /**********************************************************************
601 
602                 Compares two Time values.
603 
604         **********************************************************************/
605 
606         int opCmp (Time t)
607         {
608                 if (ticks_ < t.ticks_)
609                     return -1;
610 
611                 if (ticks_ > t.ticks_)
612                     return 1;
613 
614                 return 0;
615         }
616 
617         /**********************************************************************
618 
619                 Adds or subtracts the specified time span to the time,
620                 returning a new time.
621 
622                 Params:  op = operation to perform
623                          t = A TimeSpan value.
624                 Returns: A Time that is the sum or difference of this instance
625                          and t.
626 
627         **********************************************************************/
628 
629         Time opBinary (string op) (TimeSpan t) if (op == "+" || op == "-")
630         {
631             mixin("return Time(ticks_ " ~ op ~ " t.duration_.total!`hnsecs`);");
632         }
633 
634         unittest
635         {
636             Time time_span;
637             time_span.ticks_ = 5;
638 
639             TimeSpan test_span;
640             test_span.duration_ = 10.dur!"hnsecs";
641 
642             auto res = time_span + test_span;
643             test!("==")(res.ticks(), 15);
644 
645             test_span.duration_ = 3.dur!"hnsecs";
646 
647             res = time_span - test_span;
648             test!("==")(res.ticks(), 2);
649         }
650 
651         /**********************************************************************
652 
653                 Adds or subtracts the specified time span to the time, assigning
654                 the result to this instance.
655 
656                 Params:  op = operation to perform
657                          t = A TimeSpan value.
658                 Returns: The current Time instance, with t added or subtracted
659                          to the time.
660 
661         **********************************************************************/
662 
663         Time opOpAssign (string op) (TimeSpan t) if (op == "+" || op == "-")
664         {
665                 mixin("ticks_ " ~ op ~ "= t.duration_.total!`hnsecs`;");
666                 return this;
667         }
668 
669         unittest
670         {
671             Time time_span;
672             time_span.ticks_ = 5;
673 
674             TimeSpan test_span;
675             test_span.duration_ = 10.dur!"hnsecs";
676 
677             time_span += test_span;
678             test!("==")(time_span.ticks(), 15);
679 
680             test_span.duration_ = 3.dur!"hnsecs";
681 
682             time_span -= test_span;
683             test!("==")(time_span.ticks(), 12);
684         }
685 
686         /**********************************************************************
687 
688                 Returns a time span which represents the difference in time
689                 between this and the given Time.
690 
691                 Params:  op = operation to perform
692                          t = A Time value.
693                 Returns: A TimeSpan which represents the difference between
694                          this and t.
695 
696         **********************************************************************/
697 
698         TimeSpan opBinary (string op) (Time t) if (op == "-")
699         {
700             return TimeSpan((ticks - t.ticks_).dur!"hnsecs");
701         }
702 
703         unittest
704         {
705             Time time_span;
706             time_span.ticks_ = 5;
707 
708             TimeSpan test_span;
709             test_span.duration_ = 3.dur!"hnsecs";
710 
711             auto res = time_span - test_span;
712             test!("==")(res.ticks(), 2);
713         }
714 
715         /**********************************************************************
716 
717                 $(I Property.) Retrieves the date component.
718 
719                 Returns: A new Time instance with the same date as
720                          this instance, but with the time truncated.
721 
722         **********************************************************************/
723 
724         Time date ()
725         {
726                 return this - TimeOfDay.modulo24(ticks_);
727         }
728 
729         /**********************************************************************
730 
731                 $(I Property.) Retrieves the time of day.
732 
733                 Returns: A TimeOfDay representing the fraction of the day
734                          elapsed since midnight.
735 
736         **********************************************************************/
737 
738         TimeOfDay time ()
739         {
740                 return TimeOfDay (ticks_);
741         }
742 
743         /**********************************************************************
744 
745                 $(I Property.) Retrieves the equivalent TimeSpan.
746 
747                 Returns: A TimeSpan representing this Time.
748 
749         **********************************************************************/
750 
751         TimeSpan span ()
752         {
753                 return TimeSpan (ticks_);
754         }
755 
756         /**********************************************************************
757 
758                 $(I Property.) Retrieves a TimeSpan that corresponds to Unix
759                 time (time since 1/1/1970).  Use the TimeSpan accessors to get
760                 the time in seconds, milliseconds, etc.
761 
762                 Returns: A TimeSpan representing this Time as Unix time.
763 
764                 -------------------------------------
765                 auto unixTime = Clock.now.unix.seconds;
766                 auto javaTime = Clock.now.unix.millis;
767                 -------------------------------------
768 
769         **********************************************************************/
770 
771         TimeSpan unix()
772         {
773                 return TimeSpan(ticks_ - epoch1970.ticks_);
774         }
775 
776         /**********************************************************************
777 
778             Constructs a Time instance from the Unix time (time since 1/1/1970).
779 
780             Params:
781                 unix_time = number of seconds since 1/1/1970
782 
783             Returns:
784                 Time instance corresponding the given unix time.
785 
786         ***********************************************************************/
787 
788         static Time fromUnixTime (time_t unix_time)
789         {
790             return Time(epoch1970.ticks_ + unix_time * TimeSpan.TicksPerSecond);
791         }
792 }
793 
794 
795 /******************************************************************************
796 
797         Represents a time of day. This is different from TimeSpan in that
798         each component is represented within the limits of everyday time,
799         rather than from the start of the Epoch. Effectively, the TimeOfDay
800         epoch is the first second of each day.
801 
802         This is handy for dealing strictly with a 24-hour clock instead of
803         potentially thousands of years. For example:
804         ---
805         auto time = Clock.now.time;
806         assert (time.millis < 1000);
807         assert (time.seconds < 60);
808         assert (time.minutes < 60);
809         assert (time.hours < 24);
810         ---
811 
812         You can create a TimeOfDay from an existing Time or TimeSpan instance
813         via the respective time() method. To convert back to a TimeSpan, use
814         the span() method
815 
816 ******************************************************************************/
817 
818 struct TimeOfDay
819 {
820         /**
821          * hours component of the time of day.  This should be between 0 and
822          * 23, inclusive.
823          */
824         public uint     hours;
825 
826         /**
827          * minutes component of the time of day.  This should be between 0 and
828          * 59, inclusive.
829          */
830         public uint     minutes;
831 
832         /**
833          * seconds component of the time of day.  This should be between 0 and
834          * 59, inclusive.
835          */
836         public uint     seconds;
837 
838         /**
839          * milliseconds component of the time of day.  This should be between
840          * 0 and 999, inclusive.
841          */
842         public uint     millis;
843 
844         /**
845          * constructor.
846          * Params: hours = number of hours since midnight
847          *         minutes = number of minutes into the hour
848          *         seconds = number of seconds into the minute
849          *         millis = number of milliseconds into the second
850          *
851          * Returns: a TimeOfDay representing the given time fields.
852          *
853          * Note: There is no verification of the range of values, or
854          * normalization made.  So if you pass in larger values than the
855          * maximum value for that field, they will be stored as that value.
856          *
857          * example:
858          * --------------
859          * auto tod = TimeOfDay(100, 100, 100, 10000);
860          * assert(tod.hours == 100);
861          * assert(tod.minutes == 100);
862          * assert(tod.seconds == 100);
863          * assert(tod.millis == 10000);
864          * --------------
865          */
866         static TimeOfDay opCall (uint hours, uint minutes, uint seconds, uint millis=0)
867         {
868                 TimeOfDay t = void;
869                 t.hours   = hours;
870                 t.minutes = minutes;
871                 t.seconds = seconds;
872                 t.millis  = millis;
873                 return t;
874         }
875 
876         /**
877          * constructor.
878          * Params: ticks = ticks representing a Time value.  This is normalized
879          * so that it represent a time of day (modulo-24 etc)
880          *
881          * Returns: a TimeOfDay value that corresponds to the time of day of
882          * the given number of ticks.
883          */
884         static TimeOfDay opCall (long ticks)
885         {
886             return TimeOfDay(modulo24(ticks));
887         }
888 
889         /// Ditto
890         static TimeOfDay opCall (Duration dur)
891         {
892             // Note: Since this represents a time of day, hours needs to be
893             // 0 <= hours < 24. Using `days` ensures that, even if we don't
894             // use the value.
895             auto splitted = dur.split!("days", "hours", "minutes", "seconds", "msecs");
896             return TimeOfDay(cast(uint)splitted.hours, cast(uint)splitted.minutes,
897                              cast(uint)splitted.seconds, cast(uint)splitted.msecs);
898         }
899 
900         /**
901          * construct a TimeSpan from the current fields
902          *
903          * Returns: a TimeOfDay representing the field values.
904          *
905          * Note: that fields are not checked against a valid range, so
906          * setting 60 for minutes is allowed, and will just add 1 to the hour
907          * component, and set the minute component to 0.  The result is
908          * normalized, so the hours wrap.  If you pass in 25 hours, the
909          * resulting TimeOfDay will have a hour component of 1.
910          */
911         TimeSpan span ()
912         {
913                 return TimeSpan.fromHours(hours) +
914                        TimeSpan.fromMinutes(minutes) +
915                        TimeSpan.fromSeconds(seconds) +
916                        TimeSpan.fromMillis(millis);
917         }
918 
919         /**
920          * internal routine to adjust ticks by one day. Also adjusts for
921          * offsets in the BC era
922          */
923         package static TimeSpan modulo24 (long ticks)
924         {
925                 ticks %= TimeSpan.TicksPerDay;
926                 if (ticks < 0)
927                     ticks += TimeSpan.TicksPerDay;
928                 return TimeSpan (ticks);
929         }
930 }
931 
932 /******************************************************************************
933 
934     Generic Date representation
935 
936 ******************************************************************************/
937 
938 struct Date
939 {
940         public uint         era,            /// AD, BC
941                             day,            /// 1 .. 31
942                             year,           /// 0 to 9999
943                             month,          /// 1 .. 12
944                             dow,            /// 0 .. 6
945                             doy;            /// 1 .. 366
946 }
947 
948 
949 /******************************************************************************
950 
951     Combination of a Date and a TimeOfDay
952 
953 ******************************************************************************/
954 
955 struct DateTime
956 {
957         public Date         date;       /// date representation
958         public TimeOfDay    time;       /// time representation
959 }
960 
961 unittest
962 {
963     auto unix = time(null);
964 
965     test!("==")((Time.fromUnixTime(unix) - Time.epoch1970).seconds, unix);
966 }