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 ocean.transition;
24 
25 import core.stdc.time: time_t;
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 long ticks_;
66 
67         // useful constants.  Shouldn't be used in normal code, use the
68         // static TimeSpan members below instead.  i.e. instead of
69         // TimeSpan.TicksPerSecond, use TimeSpan.second.ticks
70         //
71         enum : long
72         {
73                 /// basic tick values
74                 NanosecondsPerTick  = 100,
75                 TicksPerMicrosecond = 1000 / NanosecondsPerTick,
76                 TicksPerMillisecond = 1000 * TicksPerMicrosecond,
77                 TicksPerSecond      = 1000 * TicksPerMillisecond,
78                 TicksPerMinute      = 60 * TicksPerSecond,
79                 TicksPerHour        = 60 * TicksPerMinute,
80                 TicksPerDay         = 24 * TicksPerHour,
81 
82                 // millisecond counts
83                 MillisPerSecond     = 1000,
84                 MillisPerMinute     = MillisPerSecond * 60,
85                 MillisPerHour       = MillisPerMinute * 60,
86                 MillisPerDay        = MillisPerHour * 24,
87 
88                 /// day counts
89                 DaysPerYear         = 365,
90                 DaysPer4Years       = DaysPerYear * 4 + 1,
91                 DaysPer100Years     = DaysPer4Years * 25 - 1,
92                 DaysPer400Years     = DaysPer100Years * 4 + 1,
93 
94                 // epoch counts
95                 Epoch1601           = DaysPer400Years * 4 * TicksPerDay,
96                 Epoch1970           = Epoch1601 + TicksPerSecond * 11644473600L,
97         }
98 
99         /**
100          * Minimum TimeSpan
101          */
102         enum TimeSpan min = {long.min};
103 
104         /**
105          * Maximum TimeSpan
106          */
107         enum TimeSpan max = {long.max};
108 
109         /**
110          * Zero TimeSpan.  Useful for comparisons.
111          */
112         enum TimeSpan zero = {0};
113 
114         /**
115          * Get the number of ticks that this timespan represents.  This can be
116          * used to construct another TimeSpan:
117          *
118          * --------
119          * long ticks = myTimeSpan.ticks;
120          * TimeSpan copyOfMyTimeSpan = TimeSpan(ticks);
121          * --------
122          */
123         long ticks()
124         {
125                 return ticks_;
126         }
127 
128         /**
129          * Determines whether two TimeSpan values are equal
130          */
131         equals_t opEquals(TimeSpan t)
132         {
133                 return ticks_ is t.ticks_;
134         }
135 
136         /**
137          * Compares this object against another TimeSpan value.
138          */
139         mixin(genOpCmp(`
140             {
141                     if (ticks_ < rhs.ticks_)
142                         return -1;
143 
144                     if (ticks_ > rhs.ticks_)
145                         return 1;
146 
147                     return 0;
148             }
149         `));
150 
151         /**
152          * Add the TimeSpan given to this TimeSpan returning a new TimeSpan.
153          *
154          * Params: t = A TimeSpan value to add
155          * Returns: A TimeSpan value that is the sum of this instance and t.
156          */
157         TimeSpan opAdd(TimeSpan t)
158         {
159                 return TimeSpan(ticks_ + t.ticks_);
160         }
161 
162         /**
163          * Add the specified TimeSpan to this TimeSpan, assigning the result
164          * to this instance.
165          *
166          * Params: t = A TimeSpan value to add
167          * Returns: a copy of this instance after adding t.
168          */
169         TimeSpan opAddAssign(TimeSpan t)
170         {
171                 ticks_ += t.ticks_;
172                 return this;
173         }
174 
175         /**
176          * Subtract the specified TimeSpan from this TimeSpan.
177          *
178          * Params: t = A TimeSpan to subtract
179          * Returns: A new timespan which is the difference between this
180          * instance and t
181          */
182         TimeSpan opSub(TimeSpan t)
183         {
184                 return TimeSpan(ticks_ - t.ticks_);
185         }
186 
187         /**
188          *
189          * Subtract the specified TimeSpan from this TimeSpan and assign the
190          *
191          * Params: t = A TimeSpan to subtract
192          * Returns: A copy of this instance after subtracting t.
193          */
194         TimeSpan opSubAssign(TimeSpan t)
195         {
196                 ticks_ -= t.ticks_;
197                 return this;
198         }
199 
200         /**
201          * Scale the TimeSpan by the specified amount.  This should not be
202          * used to convert to a different unit.  Use the unit accessors
203          * instead.  This should only be used as a scaling mechanism.  For
204          * example, if you have a timeout and you want to sleep for twice the
205          * timeout, you would use timeout * 2.
206          *
207          * Params: v = A multiplier to use for scaling this time span.
208          * Returns: A new TimeSpan that is scaled by v
209          */
210         TimeSpan opMul(long v)
211         {
212                 return TimeSpan(ticks_ * v);
213         }
214 
215         /**
216          * Scales this TimeSpan and assigns the result to this instance.
217          *
218          * Params: v = A multipler to use for scaling
219          * Returns: A copy of this instance after scaling
220          */
221         TimeSpan opMulAssign(long v)
222         {
223                 ticks_ *= v;
224                 return this;
225         }
226 
227         /**
228          * Divide the TimeSpan by the specified amount.  This should not be
229          * used to convert to a different unit.  Use the unit accessors
230          * instead.  This should only be used as a scaling mechanism.  For
231          * example, if you have a timeout and you want to sleep for half the
232          * timeout, you would use timeout / 2.
233          *
234          *
235          * Params: v = A divisor to use for scaling this time span.
236          * Returns: A new TimeSpan that is divided by v
237          */
238         TimeSpan opDiv(long v)
239         {
240                 return TimeSpan(ticks_ / v);
241         }
242 
243         /**
244          * Divides this TimeSpan and assigns the result to this instance.
245          *
246          * Params: v = A multipler to use for dividing
247          * Returns: A copy of this instance after dividing
248          */
249         TimeSpan opDivAssign(long v)
250         {
251                 ticks_ /= v;
252                 return this;
253         }
254 
255         /**
256          * Perform integer division with the given time span.
257          *
258          * Params: t = A divisor used for dividing
259          * Returns: The result of integer division between this instance and
260          * t.
261          */
262         long opDiv(TimeSpan t)
263         {
264                 return ticks_ / t.ticks;
265         }
266 
267         /**
268          * Negate a time span
269          *
270          * Returns: The negative equivalent to this time span
271          */
272         TimeSpan opNeg()
273         {
274                 return TimeSpan(-ticks_);
275         }
276 
277         /**
278          * Convert to nanoseconds
279          *
280          * Note: this may incur loss of data because nanoseconds cannot
281          * represent the range of data a TimeSpan can represent.
282          *
283          * Returns: The number of nanoseconds that this TimeSpan represents.
284          */
285         long nanos()
286         {
287                 return ticks_ * NanosecondsPerTick;
288         }
289 
290         /**
291          * Convert to microseconds
292          *
293          * Returns: The number of microseconds that this TimeSpan represents.
294          */
295         long micros()
296         {
297                 return ticks_ / TicksPerMicrosecond;
298         }
299 
300         /**
301          * Convert to milliseconds
302          *
303          * Returns: The number of milliseconds that this TimeSpan represents.
304          */
305         long millis()
306         {
307                 return ticks_ / TicksPerMillisecond;
308         }
309 
310         /**
311          * Convert to seconds
312          *
313          * Returns: The number of seconds that this TimeSpan represents.
314          */
315         long seconds()
316         {
317                 return ticks_ / TicksPerSecond;
318         }
319 
320         /**
321          * Convert to minutes
322          *
323          * Returns: The number of minutes that this TimeSpan represents.
324          */
325         long minutes()
326         {
327                 return ticks_ / TicksPerMinute;
328         }
329 
330         /**
331          * Convert to hours
332          *
333          * Returns: The number of hours that this TimeSpan represents.
334          */
335         long hours()
336         {
337                 return ticks_ / TicksPerHour;
338         }
339 
340         /**
341          * Convert to days
342          *
343          * Returns: The number of days that this TimeSpan represents.
344          */
345         long days()
346         {
347                 return ticks_ / TicksPerDay;
348         }
349 
350         /**
351          * Convert to a floating point interval representing seconds.
352          *
353          * Note: This may cause a loss of precision as a double cannot exactly
354          * represent some fractional values.
355          *
356          * Returns: An interval representing the seconds and fractional
357          * seconds that this TimeSpan represents.
358          */
359         double interval()
360         {
361                 return (cast(double) ticks_) / TicksPerSecond;
362         }
363 
364         /**
365          * Convert to TimeOfDay
366          *
367          * Returns: the TimeOfDay this TimeSpan represents.
368          */
369         TimeOfDay time()
370         {
371                 return TimeOfDay(ticks_);
372         }
373 
374         /**
375          * Construct a TimeSpan from the given number of nanoseconds
376          *
377          * Note: This may cause a loss of data since a TimeSpan's resolution
378          * is in 100ns increments.
379          *
380          * Params: value = The number of nanoseconds.
381          * Returns: A TimeSpan representing the given number of nanoseconds.
382          */
383         static TimeSpan fromNanos(long value)
384         {
385                 return TimeSpan(value / NanosecondsPerTick);
386         }
387 
388         /**
389          * Construct a TimeSpan from the given number of microseconds
390          *
391          * Params: value = The number of microseconds.
392          * Returns: A TimeSpan representing the given number of microseconds.
393          */
394         static TimeSpan fromMicros(long value)
395         {
396                 return TimeSpan(TicksPerMicrosecond * value);
397         }
398 
399         /**
400          * Construct a TimeSpan from the given number of milliseconds
401          *
402          * Params: value = The number of milliseconds.
403          * Returns: A TimeSpan representing the given number of milliseconds.
404          */
405         static TimeSpan fromMillis(long value)
406         {
407                 return TimeSpan(TicksPerMillisecond * value);
408         }
409 
410         /**
411          * Construct a TimeSpan from the given number of seconds
412          *
413          * Params: value = The number of seconds.
414          * Returns: A TimeSpan representing the given number of seconds.
415          */
416         static TimeSpan fromSeconds(long value)
417         {
418                 return TimeSpan(TicksPerSecond * value);
419         }
420 
421         /**
422          * Construct a TimeSpan from the given number of minutes
423          *
424          * Params: value = The number of minutes.
425          * Returns: A TimeSpan representing the given number of minutes.
426          */
427         static TimeSpan fromMinutes(long value)
428         {
429                 return TimeSpan(TicksPerMinute * value);
430         }
431 
432         /**
433          * Construct a TimeSpan from the given number of hours
434          *
435          * Params: value = The number of hours.
436          * Returns: A TimeSpan representing the given number of hours.
437          */
438         static TimeSpan fromHours(long value)
439         {
440                 return TimeSpan(TicksPerHour * value);
441         }
442 
443         /**
444          * Construct a TimeSpan from the given number of days
445          *
446          * Params: value = The number of days.
447          * Returns: A TimeSpan representing the given number of days.
448          */
449         static TimeSpan fromDays(long value)
450         {
451                 return TimeSpan(TicksPerDay * value);
452         }
453 
454         /**
455          * Construct a TimeSpan from the given interval.  The interval
456          * represents seconds as a double.  This allows both whole and
457          * fractional seconds to be passed in.
458          *
459          * Params: sec = The interval to convert in seconds.
460          * Returns: A TimeSpan representing the given interval.
461          */
462         static TimeSpan fromInterval(double sec)
463         {
464                 return TimeSpan(cast(long)(sec * TicksPerSecond + .1));
465         }
466 }
467 
468 
469 /******************************************************************************
470 
471         Represents a point in time.
472 
473         Remarks: Time represents dates and times between 12:00:00
474         midnight on January 1, 10000 BC and 11:59:59 PM on December 31,
475         9999 AD.
476 
477         Time values are measured in 100-nanosecond intervals, or ticks.
478         A date value is the number of ticks that have elapsed since
479         12:00:00 midnight on January 1, 0001 AD in the Gregorian
480         calendar.
481 
482         Negative Time values are offsets from that same reference point,
483         but backwards in history.  Time values are not specific to any
484         calendar, but for an example, the beginning of December 31, 1 BC
485         in the Gregorian calendar is Time.epoch - TimeSpan.days(1).
486 
487 ******************************************************************************/
488 
489 struct Time
490 {
491         private long ticks_;
492 
493         private enum : long
494         {
495                 maximum = (TimeSpan.DaysPer400Years * 25 - 366) * TimeSpan.TicksPerDay - 1,
496                 minimum = -((TimeSpan.DaysPer400Years * 25 - 366) * TimeSpan.TicksPerDay - 1),
497         }
498 
499         /// Represents the smallest and largest Time value.
500         enum Time min       = {minimum},
501                           max       = {maximum};
502 
503         /// Represents the epoch (1/1/0001)
504         enum Time epoch     = {0};
505 
506         /// Represents the epoch of 1/1/1601 (Commonly used in Windows systems)
507         enum Time epoch1601 = {TimeSpan.Epoch1601};
508 
509         /// Represents the epoch of 1/1/1970 (Commonly used in Unix systems)
510         enum Time epoch1970 = {TimeSpan.Epoch1970};
511 
512         /**********************************************************************
513 
514                 $(I Property.) Retrieves the number of ticks for this Time.
515                 This value can be used to construct another Time struct by
516                 writing:
517 
518                 ---------
519                 long ticks = myTime.ticks;
520                 Time copyOfMyTime = Time(ticks);
521                 ---------
522 
523 
524                 Returns: A long represented by the time of this
525                          instance.
526 
527         **********************************************************************/
528 
529         long ticks ()
530         {
531                 return ticks_;
532         }
533 
534         /**********************************************************************
535 
536                 Determines whether two Time values are equal.
537 
538                 Params:  t = A Time _value.
539                 Returns: true if both instances are equal; otherwise, false
540 
541         **********************************************************************/
542 
543         int opEquals (Time t)
544         {
545                 return ticks_ is t.ticks_;
546         }
547 
548         /**********************************************************************
549 
550                 Compares two Time values.
551 
552         **********************************************************************/
553 
554         int opCmp (Time t)
555         {
556                 if (ticks_ < t.ticks_)
557                     return -1;
558 
559                 if (ticks_ > t.ticks_)
560                     return 1;
561 
562                 return 0;
563         }
564 
565         /**********************************************************************
566 
567                 Adds the specified time span to the time, returning a new
568                 time.
569 
570                 Params:  t = A TimeSpan value.
571                 Returns: A Time that is the sum of this instance and t.
572 
573         **********************************************************************/
574 
575         Time opAdd (TimeSpan t)
576         {
577                 return Time (ticks_ + t.ticks_);
578         }
579 
580         /**********************************************************************
581 
582                 Adds the specified time span to the time, assigning
583                 the result to this instance.
584 
585                 Params:  t = A TimeSpan value.
586                 Returns: The current Time instance, with t added to the
587                          time.
588 
589         **********************************************************************/
590 
591         Time opAddAssign (TimeSpan t)
592         {
593                 ticks_ += t.ticks_;
594                 return this;
595         }
596 
597         /**********************************************************************
598 
599                 Subtracts the specified time span from the time,
600                 returning a new time.
601 
602                 Params:  t = A TimeSpan value.
603                 Returns: A Time whose value is the value of this instance
604                          minus the value of t.
605 
606         **********************************************************************/
607 
608         Time opSub (TimeSpan t)
609         {
610                 return Time (ticks_ - t.ticks_);
611         }
612 
613         /**********************************************************************
614 
615                 Returns a time span which represents the difference in time
616                 between this and the given Time.
617 
618                 Params:  t = A Time value.
619                 Returns: A TimeSpan which represents the difference between
620                          this and t.
621 
622         **********************************************************************/
623 
624         TimeSpan opSub (Time t)
625         {
626                 return TimeSpan(ticks_ - t.ticks_);
627         }
628 
629         /**********************************************************************
630 
631                 Subtracts the specified time span from the time,
632 
633                 Params:  t = A TimeSpan value.
634                 Returns: The current Time instance, with t subtracted
635                          from the time.
636 
637         **********************************************************************/
638 
639         Time opSubAssign (TimeSpan t)
640         {
641                 ticks_ -= t.ticks_;
642                 return this;
643         }
644 
645         /**********************************************************************
646 
647                 $(I Property.) Retrieves the date component.
648 
649                 Returns: A new Time instance with the same date as
650                          this instance, but with the time truncated.
651 
652         **********************************************************************/
653 
654         Time date ()
655         {
656                 return *(&this) - TimeOfDay.modulo24(ticks_);
657         }
658 
659         /**********************************************************************
660 
661                 $(I Property.) Retrieves the time of day.
662 
663                 Returns: A TimeOfDay representing the fraction of the day
664                          elapsed since midnight.
665 
666         **********************************************************************/
667 
668         TimeOfDay time ()
669         {
670                 return TimeOfDay (ticks_);
671         }
672 
673         /**********************************************************************
674 
675                 $(I Property.) Retrieves the equivalent TimeSpan.
676 
677                 Returns: A TimeSpan representing this Time.
678 
679         **********************************************************************/
680 
681         TimeSpan span ()
682         {
683                 return TimeSpan (ticks_);
684         }
685 
686         /**********************************************************************
687 
688                 $(I Property.) Retrieves a TimeSpan that corresponds to Unix
689                 time (time since 1/1/1970).  Use the TimeSpan accessors to get
690                 the time in seconds, milliseconds, etc.
691 
692                 Returns: A TimeSpan representing this Time as Unix time.
693 
694                 -------------------------------------
695                 auto unixTime = Clock.now.unix.seconds;
696                 auto javaTime = Clock.now.unix.millis;
697                 -------------------------------------
698 
699         **********************************************************************/
700 
701         TimeSpan unix()
702         {
703                 return TimeSpan(ticks_ - epoch1970.ticks_);
704         }
705 
706         /**********************************************************************
707 
708             Constructs a Time instance from the Unix time (time since 1/1/1970).
709 
710             Params:
711                 unix_time = number of seconds since 1/1/1970
712 
713             Returns:
714                 Time instance corresponding the given unix time.
715 
716         ***********************************************************************/
717 
718         static Time fromUnixTime (time_t unix_time)
719         {
720             return Time(epoch1970.ticks_ + unix_time * TimeSpan.TicksPerSecond);
721         }
722 }
723 
724 
725 /******************************************************************************
726 
727         Represents a time of day. This is different from TimeSpan in that
728         each component is represented within the limits of everyday time,
729         rather than from the start of the Epoch. Effectively, the TimeOfDay
730         epoch is the first second of each day.
731 
732         This is handy for dealing strictly with a 24-hour clock instead of
733         potentially thousands of years. For example:
734         ---
735         auto time = Clock.now.time;
736         assert (time.millis < 1000);
737         assert (time.seconds < 60);
738         assert (time.minutes < 60);
739         assert (time.hours < 24);
740         ---
741 
742         You can create a TimeOfDay from an existing Time or TimeSpan instance
743         via the respective time() method. To convert back to a TimeSpan, use
744         the span() method
745 
746 ******************************************************************************/
747 
748 struct TimeOfDay
749 {
750         /**
751          * hours component of the time of day.  This should be between 0 and
752          * 23, inclusive.
753          */
754         public uint     hours;
755 
756         /**
757          * minutes component of the time of day.  This should be between 0 and
758          * 59, inclusive.
759          */
760         public uint     minutes;
761 
762         /**
763          * seconds component of the time of day.  This should be between 0 and
764          * 59, inclusive.
765          */
766         public uint     seconds;
767 
768         /**
769          * milliseconds component of the time of day.  This should be between
770          * 0 and 999, inclusive.
771          */
772         public uint     millis;
773 
774         /**
775          * constructor.
776          * Params: hours = number of hours since midnight
777          *         minutes = number of minutes into the hour
778          *         seconds = number of seconds into the minute
779          *         millis = number of milliseconds into the second
780          *
781          * Returns: a TimeOfDay representing the given time fields.
782          *
783          * Note: There is no verification of the range of values, or
784          * normalization made.  So if you pass in larger values than the
785          * maximum value for that field, they will be stored as that value.
786          *
787          * example:
788          * --------------
789          * auto tod = TimeOfDay(100, 100, 100, 10000);
790          * assert(tod.hours == 100);
791          * assert(tod.minutes == 100);
792          * assert(tod.seconds == 100);
793          * assert(tod.millis == 10000);
794          * --------------
795          */
796         static TimeOfDay opCall (uint hours, uint minutes, uint seconds, uint millis=0)
797         {
798                 TimeOfDay t = void;
799                 t.hours   = hours;
800                 t.minutes = minutes;
801                 t.seconds = seconds;
802                 t.millis  = millis;
803                 return t;
804         }
805 
806         /**
807          * constructor.
808          * Params: ticks = ticks representing a Time value.  This is normalized
809          * so that it represent a time of day (modulo-24 etc)
810          *
811          * Returns: a TimeOfDay value that corresponds to the time of day of
812          * the given number of ticks.
813          */
814         static TimeOfDay opCall (long ticks)
815         {
816                 TimeOfDay t = void;
817                 ticks = modulo24(ticks).ticks_;
818                 t.millis  = cast(uint) (ticks / TimeSpan.TicksPerMillisecond);
819                 t.seconds = (t.millis / 1_000) % 60;
820                 t.minutes = (t.millis / 60_000) % 60;
821                 t.hours   = (t.millis / 3_600_000) % 24;
822                 t.millis %= 1000;
823                 return t;
824         }
825 
826         /**
827          * construct a TimeSpan from the current fields
828          *
829          * Returns: a TimeOfDay representing the field values.
830          *
831          * Note: that fields are not checked against a valid range, so
832          * setting 60 for minutes is allowed, and will just add 1 to the hour
833          * component, and set the minute component to 0.  The result is
834          * normalized, so the hours wrap.  If you pass in 25 hours, the
835          * resulting TimeOfDay will have a hour component of 1.
836          */
837         TimeSpan span ()
838         {
839                 return TimeSpan.fromHours(hours) +
840                        TimeSpan.fromMinutes(minutes) +
841                        TimeSpan.fromSeconds(seconds) +
842                        TimeSpan.fromMillis(millis);
843         }
844 
845         /**
846          * internal routine to adjust ticks by one day. Also adjusts for
847          * offsets in the BC era
848          */
849         package static TimeSpan modulo24 (long ticks)
850         {
851                 ticks %= TimeSpan.TicksPerDay;
852                 if (ticks < 0)
853                     ticks += TimeSpan.TicksPerDay;
854                 return TimeSpan (ticks);
855         }
856 }
857 
858 /******************************************************************************
859 
860     Generic Date representation
861 
862 ******************************************************************************/
863 
864 struct Date
865 {
866         public uint         era,            /// AD, BC
867                             day,            /// 1 .. 31
868                             year,           /// 0 to 9999
869                             month,          /// 1 .. 12
870                             dow,            /// 0 .. 6
871                             doy;            /// 1 .. 366
872 }
873 
874 
875 /******************************************************************************
876 
877     Combination of a Date and a TimeOfDay
878 
879 ******************************************************************************/
880 
881 struct DateTime
882 {
883         public Date         date;       /// date representation
884         public TimeOfDay    time;       /// time representation
885 }
886 
887 unittest
888 {
889     auto unix = time(null);
890 
891     test!("==")((Time.fromUnixTime(unix) - Time.epoch1970).seconds, unix);
892 }