1 // Written in the D programming language.
2 
3 /**
4  * $(RED Deprecated. It will be removed in February 2012.
5  *       Please use std.datetime instead.)
6  *
7  * Dates are represented in several formats. The date implementation
8  * revolves around a central type, $(D d_time), from which other
9  * formats are converted to and from.  Dates are calculated using the
10  * Gregorian calendar.
11  *
12  * References: $(WEB wikipedia.org/wiki/Gregorian_calendar, Gregorian
13  * calendar (Wikipedia))
14  *
15  * Macros: WIKI = Phobos/StdDate
16  *
17  * Copyright: Copyright Digital Mars 2000 - 2009.
18  * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
19  * Authors:   $(WEB digitalmars.com, Walter Bright)
20  * Source:    $(PHOBOSSRC std/_date.d)
21  */
22 /*          Copyright Digital Mars 2000 - 2009.
23  * Distributed under the Boost Software License, Version 1.0.
24  *    (See accompanying file LICENSE_1_0.txt or copy at
25  *          http://www.boost.org/LICENSE_1_0.txt)
26  */
27 module undead.date;
28 
29 import std.conv, std.exception, std.stdio;
30 import core.stdc.stdlib;
31 
32 import undead.datebase;
33 import undead.dateparse;
34 
35 /+
36 pragma(msg, "Notice: As of Phobos 2.055, std.date and std.dateparse have been " ~
37             "deprecated. They will be removed in February 2012. " ~
38             "Please use std.datetime instead.");
39 
40 deprecated:
41 +/
42 
43 /**
44  * $(D d_time) is a signed arithmetic type giving the time elapsed
45  * since January 1, 1970.  Negative values are for dates preceding
46  * 1970. The time unit used is Ticks.  Ticks are milliseconds or
47  * smaller intervals.
48  *
49  * The usual arithmetic operations can be performed on d_time, such as adding,
50  * subtracting, etc. Elapsed time in Ticks can be computed by subtracting a
51  * starting d_time from an ending d_time.
52  */
53 alias long d_time;
54 
55 /**
56  * A value for d_time that does not represent a valid time.
57  */
58 enum d_time d_time_nan = long.min;
59 
60 /**
61  * Time broken down into its components.
62  */
63 struct Date
64 {
65     int year = int.min;        /// use int.min as "nan" year value
66     int month;                /// 1..12
67     int day;                /// 1..31
68     int hour;                /// 0..23
69     int minute;                /// 0..59
70     int second;                /// 0..59
71     int ms;                /// 0..999
72     int weekday;        /// 0: not specified, 1..7: Sunday..Saturday
73     int tzcorrection = int.min;        /// -1200..1200 correction in hours
74 
75     /// Parse date out of string s[] and store it in this Date instance.
76     void parse(string s)
77     {
78         DateParse dp;
79         dp.parse(s, this);
80     }
81 }
82 
83 enum
84 {
85     hoursPerDay    = 24,
86     minutesPerHour = 60,
87     msPerMinute    = 60 * 1000,
88     msPerHour      = 60 * msPerMinute,
89     msPerDay       = 86_400_000,
90     ticksPerMs     = 1,
91     ticksPerSecond = 1000,                        /// Will be at least 1000
92     ticksPerMinute = ticksPerSecond * 60,
93     ticksPerHour   = ticksPerMinute * 60,
94     ticksPerDay    = ticksPerHour   * 24,
95 }
96 
97 deprecated alias ticksPerSecond TicksPerSecond;
98 deprecated alias ticksPerMs TicksPerMs;
99 deprecated alias ticksPerMinute TicksPerMinute;
100 deprecated alias ticksPerHour TicksPerHour;
101 deprecated alias ticksPerDay TicksPerDay;
102 
103 deprecated
104 unittest
105 {
106     assert(ticksPerSecond == TicksPerSecond);
107 }
108 
109 __gshared d_time localTZA = 0;
110 
111 private immutable char[] daystr = "SunMonTueWedThuFriSat";
112 private immutable char[] monstr = "JanFebMarAprMayJunJulAugSepOctNovDec";
113 
114 private immutable int[12] mdays =
115     [ 0,31,59,90,120,151,181,212,243,273,304,334 ];
116 
117 /********************************
118  * Compute year and week [1..53] from t. The ISO 8601 week 1 is the first week
119  * of the year that includes January 4. Monday is the first day of the week.
120  * References:
121  *        $(LINK2 http://en.wikipedia.org/wiki/ISO_8601, ISO 8601 (Wikipedia))
122  */
123 
124 void toISO8601YearWeek(d_time t, out int year, out int week)
125 {
126     year = yearFromTime(t);
127 
128     auto yday = day(t) - dayFromYear(year);
129 
130     /* Determine day of week Jan 4 falls on.
131      * Weeks begin on a Monday.
132      */
133 
134     auto d = dayFromYear(year);
135     auto w = (d + 3/*Jan4*/ + 3) % 7;
136     if (w < 0)
137         w += 7;
138 
139     /* Find yday of beginning of ISO 8601 year
140      */
141     auto ydaybeg = 3/*Jan4*/ - w;
142 
143     /* Check if yday is actually the last week of the previous year
144      */
145     if (yday < ydaybeg)
146     {
147         year -= 1;
148         week = 53;
149         return;
150     }
151 
152     /* Check if yday is actually the first week of the next year
153      */
154     if (yday >= 362)                            // possible
155     {   int d2;
156         int ydaybeg2;
157 
158         d2 = dayFromYear(year + 1);
159         w = (d2 + 3/*Jan4*/ + 3) % 7;
160         if (w < 0)
161             w += 7;
162         //printf("w = %d\n", w);
163         ydaybeg2 = 3/*Jan4*/ - w;
164         if (d + yday >= d2 + ydaybeg2)
165         {
166             year += 1;
167             week = 1;
168             return;
169         }
170     }
171 
172     week = (yday - ydaybeg) / 7 + 1;
173 }
174 
175 /* ***********************************
176  * Divide time by divisor. Always round down, even if d is negative.
177  */
178 
179 pure d_time floor(d_time d, int divisor)
180 {
181     return (d < 0 ? d - divisor - 1 : d) / divisor;
182 }
183 
184 int dmod(d_time n, d_time d)
185 {   d_time r;
186 
187     r = n % d;
188     if (r < 0)
189         r += d;
190     assert(cast(int)r == r);
191     return cast(int)r;
192 }
193 
194 /********************************
195  * Calculates the hour from time.
196  *
197  * Params:
198  *      time = The time to compute the hour from.
199  * Returns:
200  *      The calculated hour, 0..23.
201  */
202 int hourFromTime(d_time time)
203 {
204     return dmod(floor(time, msPerHour), hoursPerDay);
205 }
206 
207 /********************************
208  * Calculates the minute from time.
209  *
210  * Params:
211  *      time = The time to compute the minute from.
212  * Returns:
213  *      The calculated minute, 0..59.
214  */
215 int minFromTime(d_time time)
216 {
217     return dmod(floor(time, msPerMinute), minutesPerHour);
218 }
219 
220 /********************************
221  * Calculates the second from time.
222  *
223  * Params:
224  *      time = The time to compute the second from.
225  * Returns:
226  *      The calculated second, 0..59.
227  */
228 int secFromTime(d_time time)
229 {
230     return dmod(floor(time, ticksPerSecond), 60);
231 }
232 
233 /********************************
234  * Calculates the milisecond from time.
235  *
236  * Params:
237  *      time = The time to compute the milisecond from.
238  * Returns:
239  *      The calculated milisecond, 0..999.
240  */
241 int msFromTime(d_time time)
242 {
243     return dmod(time / (ticksPerSecond / 1000), 1000);
244 }
245 
246 int timeWithinDay(d_time t)
247 {
248     return dmod(t, msPerDay);
249 }
250 
251 d_time toInteger(d_time n)
252 {
253     return n;
254 }
255 
256 int day(d_time t)
257 {
258     return cast(int)floor(t, msPerDay);
259 }
260 
261 pure bool leapYear(uint y)
262 {
263     return (y % 4) == 0 && (y % 100 || (y % 400) == 0);
264 }
265 
266 unittest {
267     assert(!leapYear(1970));
268     assert(leapYear(1984));
269     assert(leapYear(2000));
270     assert(!leapYear(2100));
271 }
272 
273 /********************************
274  * Calculates the number of days that exists in a year.
275  *
276  * Leap years have 366 days, while other years have 365.
277  *
278  * Params:
279  *      year = The year to compute the number of days from.
280  * Returns:
281  *      The number of days in the year, 365 or 366.
282  */
283 pure uint daysInYear(uint year)
284 {
285     return (leapYear(year) ? 366 : 365);
286 }
287 
288 
289 /********************************
290  * Calculates the number of days elapsed since 1 January 1970
291  * until 1 January of the given year.
292  *
293  * Params:
294  *      year = The year to compute the number of days from.
295  * Returns:
296  *      The number of days elapsed.
297  *
298  * Example:
299  * ----------
300  * writeln(dayFromYear(1970)); // writes '0'
301  * writeln(dayFromYear(1971)); // writes '365'
302  * writeln(dayFromYear(1972)); // writes '730'
303  * ----------
304  */
305 pure int dayFromYear(int year)
306 {
307     return cast(int) (365 * (year - 1970) +
308                 floor((year - 1969), 4) -
309                 floor((year - 1901), 100) +
310                 floor((year - 1601), 400));
311 }
312 
313 pure d_time timeFromYear(int y)
314 {
315     return cast(d_time)msPerDay * dayFromYear(y);
316 }
317 
318 /*****************************
319  * Calculates the year from the d_time t.
320  */
321 
322 pure int yearFromTime(d_time t)
323 {
324 
325     if (t == d_time_nan)
326         return 0;
327 
328     // Hazard a guess
329     //y = 1970 + cast(int) (t / (365.2425 * msPerDay));
330     // Use integer only math
331     int y = 1970 + cast(int) (t / (3652425 * (msPerDay / 10000)));
332 
333     if (timeFromYear(y) <= t)
334     {
335         while (timeFromYear(y + 1) <= t)
336             y++;
337     }
338     else
339     {
340         do
341         {
342             y--;
343         }
344         while (timeFromYear(y) > t);
345     }
346     return y;
347 }
348 
349 /*******************************
350  * Determines if d_time t is a leap year.
351  *
352  * A leap year is every 4 years except years ending in 00 that are not
353  * divsible by 400.
354  *
355  * Returns: !=0 if it is a leap year.
356  *
357  * References:
358  *        $(LINK2 http://en.wikipedia.org/wiki/Leap_year, Wikipedia)
359  */
360 
361 pure bool inLeapYear(d_time t)
362 {
363     return leapYear(yearFromTime(t));
364 }
365 
366 /*****************************
367  * Calculates the month from the d_time t.
368  *
369  * Returns: Integer in the range 0..11, where
370  *        0 represents January and 11 represents December.
371  */
372 
373 int monthFromTime(d_time t)
374 {
375     auto year = yearFromTime(t);
376     auto day = day(t) - dayFromYear(year);
377 
378     int month;
379     if (day < 59)
380     {
381         if (day < 31)
382         {   assert(day >= 0);
383             month = 0;
384         }
385         else
386             month = 1;
387     }
388     else
389     {
390         day -= leapYear(year);
391         if (day < 212)
392         {
393             if (day < 59)
394                 month = 1;
395             else if (day < 90)
396                 month = 2;
397             else if (day < 120)
398                 month = 3;
399             else if (day < 151)
400                 month = 4;
401             else if (day < 181)
402                 month = 5;
403             else
404                 month = 6;
405         }
406         else
407         {
408             if (day < 243)
409                 month = 7;
410             else if (day < 273)
411                 month = 8;
412             else if (day < 304)
413                 month = 9;
414             else if (day < 334)
415                 month = 10;
416             else if (day < 365)
417                 month = 11;
418             else
419                 assert(0);
420         }
421     }
422     return month;
423 }
424 
425 /*******************************
426  * Compute which day in a month a d_time t is.
427  * Returns:
428  *        Integer in the range 1..31
429  */
430 int dateFromTime(d_time t)
431 {
432     auto year = yearFromTime(t);
433     auto day = day(t) - dayFromYear(year);
434     auto leap = leapYear(year);
435     auto month = monthFromTime(t);
436     int date;
437     switch (month)
438     {
439         case 0:         date = day +   1;                break;
440         case 1:         date = day -  30;                break;
441         case 2:         date = day -  58 - leap;        break;
442         case 3:         date = day -  89 - leap;        break;
443         case 4:         date = day - 119 - leap;        break;
444         case 5:         date = day - 150 - leap;        break;
445         case 6:         date = day - 180 - leap;        break;
446         case 7:         date = day - 211 - leap;        break;
447         case 8:         date = day - 242 - leap;        break;
448         case 9:         date = day - 272 - leap;        break;
449         case 10: date = day - 303 - leap;        break;
450         case 11: date = day - 333 - leap;        break;
451         default:
452             assert(0);
453     }
454     return date;
455 }
456 
457 /*******************************
458  * Compute which day of the week a d_time t is.
459  * Returns:
460  *        Integer in the range 0..6, where 0 represents Sunday
461  *        and 6 represents Saturday.
462  */
463 int weekDay(d_time t)
464 {
465     auto w = (cast(int)day(t) + 4) % 7;
466     if (w < 0)
467         w += 7;
468     return w;
469 }
470 
471 /***********************************
472  * Convert from UTC to local time.
473  */
474 
475 d_time UTCtoLocalTime(d_time t)
476 {
477     return (t == d_time_nan)
478         ? d_time_nan
479         : t + localTZA + daylightSavingTA(t);
480 }
481 
482 /***********************************
483  * Convert from local time to UTC.
484  */
485 
486 d_time localTimetoUTC(d_time t)
487 {
488     return (t == d_time_nan)
489         ? d_time_nan
490 /* BUGZILLA 1752 says this line should be:
491  *        : t - localTZA - daylightSavingTA(t);
492  */
493         : t - localTZA - daylightSavingTA(t - localTZA);
494 }
495 
496 
497 d_time makeTime(d_time hour, d_time min, d_time sec, d_time ms)
498 {
499     return hour * ticksPerHour +
500            min * ticksPerMinute +
501            sec * ticksPerSecond +
502            ms * ticksPerMs;
503 }
504 
505 /* *****************************
506  * Params:
507  *        month = 0..11
508  *        date = day of month, 1..31
509  * Returns:
510  *        number of days since start of epoch
511  */
512 
513 d_time makeDay(d_time year, d_time month, d_time date)
514 {
515     const y = cast(int)(year + floor(month, 12));
516     const m = dmod(month, 12);
517 
518     const leap = leapYear(y);
519     auto t = timeFromYear(y) + cast(d_time) mdays[m] * msPerDay;
520     if (leap && month >= 2)
521         t += msPerDay;
522 
523     if (yearFromTime(t) != y ||
524         monthFromTime(t) != m ||
525         dateFromTime(t) != 1)
526     {
527         return  d_time_nan;
528     }
529 
530     return day(t) + date - 1;
531 }
532 
533 d_time makeDate(d_time day, d_time time)
534 {
535     if (day == d_time_nan || time == d_time_nan)
536         return d_time_nan;
537 
538     return day * ticksPerDay + time;
539 }
540 
541 d_time timeClip(d_time time)
542 {
543     //printf("TimeClip(%g) = %g\n", time, toInteger(time));
544 
545     return toInteger(time);
546 }
547 
548 /***************************************
549  * Determine the date in the month, 1..31, of the nth
550  * weekday.
551  * Params:
552  *        year = year
553  *        month = month, 1..12
554  *        weekday = day of week 0..6 representing Sunday..Saturday
555  *        n = nth occurrence of that weekday in the month, 1..5, where
556  *            5 also means "the last occurrence in the month"
557  * Returns:
558  *        the date in the month, 1..31, of the nth weekday
559  */
560 
561 int dateFromNthWeekdayOfMonth(int year, int month, int weekday, int n)
562 in
563 {
564     assert(1 <= month && month <= 12);
565     assert(0 <= weekday && weekday <= 6);
566     assert(1 <= n && n <= 5);
567 }
568 do
569 {
570     // Get day of the first of the month
571     auto x = makeDay(year, month - 1, 1);
572 
573     // Get the week day 0..6 of the first of this month
574     auto wd = weekDay(makeDate(x, 0));
575 
576     // Get monthday of first occurrence of weekday in this month
577     auto mday = weekday - wd + 1;
578     if (mday < 1)
579         mday += 7;
580 
581     // Add in number of weeks
582     mday += (n - 1) * 7;
583 
584     // If monthday is more than the number of days in the month,
585     // back up to 'last' occurrence
586     if (mday > 28 && mday > daysInMonth(year, month))
587     {        assert(n == 5);
588         mday -= 7;
589     }
590 
591     return mday;
592 }
593 
594 unittest
595 {
596     assert(dateFromNthWeekdayOfMonth(2003,  3, 0, 5) == 30);
597     assert(dateFromNthWeekdayOfMonth(2003, 10, 0, 5) == 26);
598     assert(dateFromNthWeekdayOfMonth(2004,  3, 0, 5) == 28);
599     assert(dateFromNthWeekdayOfMonth(2004, 10, 0, 5) == 31);
600 }
601 
602 /**************************************
603  * Determine the number of days in a month, 1..31.
604  * Params:
605  *        year = Gregorian year that contains the month in question
606  *        month = 1..12
607  */
608 
609 int daysInMonth(int year, int month)
610 {
611     switch (month)
612     {
613         case 1:
614         case 3:
615         case 5:
616         case 7:
617         case 8:
618         case 10:
619         case 12:
620             return 31;
621         case 2:
622             return 28 + leapYear(year);
623         case 4:
624         case 6:
625         case 9:
626         case 11:
627             return 30;
628     default:
629         break;
630     }
631     return enforce(false, "Invalid month passed to daysInMonth");
632 }
633 
634 unittest
635 {
636     assert(daysInMonth(2003, 2) == 28);
637     assert(daysInMonth(2004, 2) == 29);
638 }
639 
640 /*************************************
641  * Converts UTC time into a text string of the form:
642  * "Www Mmm dd hh:mm:ss GMT+-TZ yyyy".
643  * For example, "Tue Apr 02 02:04:57 GMT-0800 1996".
644  * If time is invalid, i.e. is d_time_nan,
645  * the string "Invalid date" is returned.
646  *
647  * Example:
648  * ------------------------------------
649   d_time lNow;
650   char[] lNowString;
651 
652   // Grab the date and time relative to UTC
653   lNow = std.date.getUTCtime();
654   // Convert this into the local date and time for display.
655   lNowString = std.date.UTCtoString(lNow);
656  * ------------------------------------
657  */
658 
659 string UTCtoString(d_time time)
660 {
661     // Years are supposed to be -285616 .. 285616, or 7 digits
662     // "Tue Apr 02 02:04:57 GMT-0800 1996"
663     auto buffer = new char[29 + 7 + 1];
664 
665     if (time == d_time_nan)
666         return "Invalid Date";
667 
668     auto dst = daylightSavingTA(time);
669     auto offset = localTZA + dst;
670     auto t = time + offset;
671     auto sign = '+';
672     if (offset < 0)
673     {        sign = '-';
674 //        offset = -offset;
675         offset = -(localTZA + dst);
676     }
677 
678     auto mn = cast(int)(offset / msPerMinute);
679     auto hr = mn / 60;
680     mn %= 60;
681 
682     //printf("hr = %d, offset = %g, localTZA = %g, dst = %g, + = %g\n", hr, offset, localTZA, dst, localTZA + dst);
683 
684     auto len = sprintf(buffer.ptr,
685             "%.3s %.3s %02d %02d:%02d:%02d GMT%c%02d%02d %d",
686             &daystr[weekDay(t) * 3],
687             &monstr[monthFromTime(t) * 3],
688             dateFromTime(t),
689             hourFromTime(t), minFromTime(t), secFromTime(t),
690             sign, hr, mn,
691             cast(int)yearFromTime(t));
692 
693     // Ensure no buggy buffer overflows
694     //printf("len = %d, buffer.length = %d\n", len, buffer.length);
695     assert(len < buffer.length);
696     buffer = buffer[0 .. len];
697     return assumeUnique(buffer);
698 }
699 
700 /// Alias for UTCtoString (deprecated).
701 deprecated alias UTCtoString toString;
702 
703 /***********************************
704  * Converts t into a text string of the form: "Www, dd Mmm yyyy hh:mm:ss UTC".
705  * If t is invalid, "Invalid date" is returned.
706  */
707 
708 string toUTCString(d_time t)
709 {
710     // Years are supposed to be -285616 .. 285616, or 7 digits
711     // "Tue, 02 Apr 1996 02:04:57 GMT"
712     auto buffer = new char[25 + 7 + 1];
713 
714     if (t == d_time_nan)
715         return "Invalid Date";
716 
717     auto len = sprintf(buffer.ptr, "%.3s, %02d %.3s %d %02d:%02d:%02d UTC",
718             &daystr[weekDay(t) * 3], dateFromTime(t),
719             &monstr[monthFromTime(t) * 3],
720             yearFromTime(t),
721             hourFromTime(t), minFromTime(t), secFromTime(t));
722 
723     // Ensure no buggy buffer overflows
724     assert(len < buffer.length);
725 
726     return cast(string) buffer[0 .. len];
727 }
728 
729 /************************************
730  * Converts the date portion of time into a text string of the form: "Www Mmm dd
731  * yyyy", for example, "Tue Apr 02 1996".
732  * If time is invalid, "Invalid date" is returned.
733  */
734 
735 string toDateString(d_time time)
736 {
737     // Years are supposed to be -285616 .. 285616, or 7 digits
738     // "Tue Apr 02 1996"
739     auto buffer = new char[29 + 7 + 1];
740 
741     if (time == d_time_nan)
742         return "Invalid Date";
743 
744     auto dst = daylightSavingTA(time);
745     auto offset = localTZA + dst;
746     auto t = time + offset;
747 
748     auto len = sprintf(buffer.ptr, "%.3s %.3s %02d %d",
749         &daystr[weekDay(t) * 3],
750         &monstr[monthFromTime(t) * 3],
751         dateFromTime(t),
752         cast(int)yearFromTime(t));
753 
754     // Ensure no buggy buffer overflows
755     assert(len < buffer.length);
756 
757     return cast(string) buffer[0 .. len];
758 }
759 
760 /******************************************
761  * Converts the time portion of t into a text string of the form: "hh:mm:ss
762  * GMT+-TZ", for example, "02:04:57 GMT-0800".
763  * If t is invalid, "Invalid date" is returned.
764  * The input must be in UTC, and the output is in local time.
765  */
766 
767 string toTimeString(d_time time)
768 {
769     // "02:04:57 GMT-0800"
770     auto buffer = new char[17 + 1];
771 
772     if (time == d_time_nan)
773         return "Invalid Date";
774 
775     auto dst = daylightSavingTA(time);
776     auto offset = localTZA + dst;
777     auto t = time + offset;
778     auto sign = '+';
779     if (offset < 0)
780     {        sign = '-';
781 //        offset = -offset;
782         offset = -(localTZA + dst);
783     }
784 
785     auto mn = cast(int)(offset / msPerMinute);
786     auto hr = mn / 60;
787     mn %= 60;
788 
789     //printf("hr = %d, offset = %g, localTZA = %g, dst = %g, + = %g\n", hr, offset, localTZA, dst, localTZA + dst);
790 
791     auto len = sprintf(buffer.ptr, "%02d:%02d:%02d GMT%c%02d%02d",
792         hourFromTime(t), minFromTime(t), secFromTime(t),
793         sign, hr, mn);
794 
795     // Ensure no buggy buffer overflows
796     assert(len < buffer.length);
797 
798     // Lop off terminating 0
799     return cast(string) buffer[0 .. len];
800 }
801 
802 
803 /******************************************
804  * Parses s as a textual date string, and returns it as a d_time.  If
805  * the string is not a valid date, $(D d_time_nan) is returned.
806  */
807 
808 d_time parse(string s)
809 {
810     try
811     {
812         Date dp;
813         dp.parse(s);
814         auto time = makeTime(dp.hour, dp.minute, dp.second, dp.ms);
815         // Assume UTC if no tzcorrection is set (runnable/testdate).
816         if (dp.tzcorrection != int.min)
817         {
818             time += cast(d_time)(dp.tzcorrection / 100) * msPerHour +
819                     cast(d_time)(dp.tzcorrection % 100) * msPerMinute;
820         }
821         auto day = makeDay(dp.year, dp.month - 1, dp.day);
822         auto result = makeDate(day,time);
823         return timeClip(result);
824     }
825     catch (Exception e)
826     {
827         return d_time_nan;                // erroneous date string
828     }
829 }
830 
831 extern(C) void std_date_static_this()
832 {
833     localTZA = getLocalTZA();
834 }
835 
836 version (Windows)
837 {
838     private import core.sys.windows.windows;
839     //import c.time;
840 
841     /******
842      * Get current UTC time.
843      */
844     d_time getUTCtime()
845     {
846         SYSTEMTIME st;
847         GetSystemTime(&st);                // get time in UTC
848         return SYSTEMTIME2d_time(&st, 0);
849         //return c.time.time(null) * ticksPerSecond;
850     }
851 
852     static d_time FILETIME2d_time(const FILETIME *ft)
853     {
854         SYSTEMTIME st = void;
855         if (!FileTimeToSystemTime(ft, &st))
856             return d_time_nan;
857         return SYSTEMTIME2d_time(&st, 0);
858     }
859 
860     FILETIME d_time2FILETIME(d_time dt)
861     {
862         static assert(10_000_000 >= ticksPerSecond);
863         static assert(10_000_000 % ticksPerSecond == 0);
864         enum ulong ticksFrom1601To1970 = 11_644_473_600UL * ticksPerSecond;
865         ulong t = (dt + ticksFrom1601To1970) * (10_000_000 / ticksPerSecond);
866         FILETIME result = void;
867         result.dwLowDateTime = cast(uint) (t & uint.max);
868         result.dwHighDateTime = cast(uint) (t >> 32);
869         return result;
870     }
871 
872     unittest
873     {
874         auto dt = getUTCtime();
875         auto ft = d_time2FILETIME(dt);
876         auto dt1 = FILETIME2d_time(&ft);
877         assert(dt == dt1, text(dt, " != ", dt1));
878     }
879 
880     static d_time SYSTEMTIME2d_time(const SYSTEMTIME *st, d_time t)
881     {
882         /* More info: http://delphicikk.atw.hu/listaz.php?id=2667&oldal=52
883          */
884         d_time day = void;
885         d_time time = void;
886 
887         if (st.wYear)
888         {
889             time = makeTime(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
890             day = makeDay(st.wYear, st.wMonth - 1, st.wDay);
891         }
892         else
893         {   /* wYear being 0 is a flag to indicate relative time:
894              * wMonth is the month 1..12
895              * wDayOfWeek is weekday 0..6 corresponding to Sunday..Saturday
896              * wDay is the nth time, 1..5, that wDayOfWeek occurs
897              */
898 
899             auto year = yearFromTime(t);
900             auto mday = dateFromNthWeekdayOfMonth(year,
901                     st.wMonth, st.wDay, st.wDayOfWeek);
902             day = makeDay(year, st.wMonth - 1, mday);
903             time = makeTime(st.wHour, st.wMinute, 0, 0);
904         }
905         auto n = makeDate(day,time);
906         return timeClip(n);
907     }
908 
909     d_time getLocalTZA()
910     {
911         TIME_ZONE_INFORMATION tzi = void;
912 
913         /* http://msdn.microsoft.com/library/en-us/sysinfo/base/gettimezoneinformation.asp
914          * http://msdn2.microsoft.com/en-us/library/ms725481.aspx
915          */
916         auto r = GetTimeZoneInformation(&tzi);
917         //printf("bias = %d\n", tzi.Bias);
918         //printf("standardbias = %d\n", tzi.StandardBias);
919         //printf("daylightbias = %d\n", tzi.DaylightBias);
920         switch (r)
921         {
922             case TIME_ZONE_ID_STANDARD:
923                 return -(tzi.Bias + tzi.StandardBias)
924                     * cast(d_time)(60 * ticksPerSecond);
925             case TIME_ZONE_ID_DAYLIGHT:
926                 // falthrough
927                 //t = -(tzi.Bias + tzi.DaylightBias) * cast(d_time)(60 * ticksPerSecond);
928                 //break;
929             case TIME_ZONE_ID_UNKNOWN:
930                 return -(tzi.Bias) * cast(d_time)(60 * ticksPerSecond);
931             default:
932                 return 0;
933         }
934     }
935 
936     /*
937      * Get daylight savings time adjust for time dt.
938      */
939 
940     int daylightSavingTA(d_time dt)
941     {
942         TIME_ZONE_INFORMATION tzi = void;
943         d_time ts;
944         d_time td;
945 
946         /* http://msdn.microsoft.com/library/en-us/sysinfo/base/gettimezoneinformation.asp
947          */
948         auto r = GetTimeZoneInformation(&tzi);
949         auto t = 0;
950         switch (r)
951         {
952             case TIME_ZONE_ID_STANDARD:
953             case TIME_ZONE_ID_DAYLIGHT:
954                 if (tzi.StandardDate.wMonth == 0 ||
955                     tzi.DaylightDate.wMonth == 0)
956                     break;
957 
958                 ts = SYSTEMTIME2d_time(&tzi.StandardDate, dt);
959                 td = SYSTEMTIME2d_time(&tzi.DaylightDate, dt);
960 
961                 if (td <= dt && dt < ts)
962                 {
963                     t = -tzi.DaylightBias * (60 * ticksPerSecond);
964                     //printf("DST is in effect, %d\n", t);
965                 }
966                 else
967                 {
968                     //printf("no DST\n");
969                 }
970                 break;
971 
972             case TIME_ZONE_ID_UNKNOWN:
973                 // Daylight savings time not used in this time zone
974                 break;
975 
976             default:
977                 assert(0);
978         }
979         return t;
980     }
981 }
982 
983 version (Posix)
984 {
985     private import core.sys.posix.time;
986     private import core.sys.posix.sys.time;
987 
988     /******
989      * Get current UTC time.
990      */
991     d_time getUTCtime()
992     {   timeval tv;
993 
994         //printf("getUTCtime()\n");
995         if (gettimeofday(&tv, null))
996         {   // Some error happened - try time() instead
997             return time(null) * ticksPerSecond;
998         }
999 
1000         return tv.tv_sec * cast(d_time)ticksPerSecond +
1001                 (tv.tv_usec / (1000000 / cast(d_time)ticksPerSecond));
1002     }
1003 
1004     d_time getLocalTZA()
1005     {
1006         time_t t;
1007 
1008         time(&t);
1009         version (OSX)
1010         {
1011             tm result;
1012             localtime_r(&t, &result);
1013             return result.tm_gmtoff * ticksPerSecond;
1014         }
1015         else version (FreeBSD)
1016         {
1017             tm result;
1018             localtime_r(&t, &result);
1019             return result.tm_gmtoff * ticksPerSecond;
1020         }
1021         else version (OpenBSD)
1022         {
1023             tm result;
1024             localtime_r(&t, &result);
1025             return result.tm_gmtoff * ticksPerSecond;
1026         }
1027         else
1028         {
1029             localtime(&t);        // this will set timezone
1030             return -(timezone * ticksPerSecond);
1031         }
1032     }
1033 
1034     /*
1035      * Get daylight savings time adjust for time dt.
1036      */
1037 
1038     int daylightSavingTA(d_time dt)
1039     {
1040         tm *tmp;
1041         time_t t;
1042         int dst = 0;
1043 
1044         if (dt != d_time_nan)
1045         {
1046             d_time seconds = dt / ticksPerSecond;
1047             t = cast(time_t) seconds;
1048             if (t == seconds)        // if in range
1049             {
1050                 tmp = localtime(&t);
1051                 if (tmp.tm_isdst > 0)
1052                     dst = ticksPerHour;        // BUG: Assume daylight savings time is plus one hour.
1053             }
1054             else // out of range for system time, use our own calculation
1055             {
1056                 /* BUG: this works for the US, but not other timezones.
1057                  */
1058 
1059                 dt -= localTZA;
1060 
1061                 int year = yearFromTime(dt);
1062 
1063                 /* Compute time given year, month 1..12,
1064                  * week in month, weekday, hour
1065                  */
1066                 d_time dstt(int year, int month, int week, int weekday, int hour)
1067                 {
1068                     auto mday = dateFromNthWeekdayOfMonth(year,  month, weekday, week);
1069                     return timeClip(makeDate(
1070                         makeDay(year, month - 1, mday),
1071                         makeTime(hour, 0, 0, 0)));
1072                 }
1073 
1074                 d_time start;
1075                 d_time end;
1076                 if (year < 2007)
1077                 {   // Daylight savings time goes from 2 AM the first Sunday
1078                     // in April through 2 AM the last Sunday in October
1079                     start = dstt(year,  4, 1, 0, 2);
1080                     end   = dstt(year, 10, 5, 0, 2);
1081                 }
1082                 else
1083                 {
1084                     // the second Sunday of March to
1085                     // the first Sunday in November
1086                     start = dstt(year,  3, 2, 0, 2);
1087                     end   = dstt(year, 11, 1, 0, 2);
1088                 }
1089 
1090                 if (start <= dt && dt < end)
1091                     dst = ticksPerHour;
1092                 //writefln("start = %s, dt = %s, end = %s, dst = %s", start, dt, end, dst);
1093             }
1094         }
1095         return dst;
1096     }
1097 
1098 }
1099 
1100 
1101 /+ DOS File Time +/
1102 
1103 /***
1104  * Type representing the DOS file date/time format.
1105  */
1106 alias uint DosFileTime;
1107 
1108 /************************************
1109  * Convert from DOS file date/time to d_time.
1110  */
1111 
1112 d_time toDtime(DosFileTime time)
1113 {
1114     uint dt = cast(uint)time;
1115 
1116     if (dt == 0)
1117         return d_time_nan;
1118 
1119     int year = ((dt >> 25) & 0x7F) + 1980;
1120     int month = ((dt >> 21) & 0x0F) - 1;        // 0..12
1121     int dayofmonth = ((dt >> 16) & 0x1F);        // 0..31
1122     int hour = (dt >> 11) & 0x1F;                // 0..23
1123     int minute = (dt >> 5) & 0x3F;                // 0..59
1124     int second = (dt << 1) & 0x3E;                // 0..58 (in 2 second increments)
1125 
1126     d_time t;
1127 
1128     t = undead.date.makeDate(undead.date.makeDay(year, month, dayofmonth),
1129             undead.date.makeTime(hour, minute, second, 0));
1130 
1131     assert(yearFromTime(t) == year);
1132     assert(monthFromTime(t) == month);
1133     assert(dateFromTime(t) == dayofmonth);
1134     assert(hourFromTime(t) == hour);
1135     assert(minFromTime(t) == minute);
1136     assert(secFromTime(t) == second);
1137 
1138     t -= localTZA + daylightSavingTA(t);
1139 
1140     return t;
1141 }
1142 
1143 /****************************************
1144  * Convert from d_time to DOS file date/time.
1145  */
1146 
1147 DosFileTime toDosFileTime(d_time t)
1148 {   uint dt;
1149 
1150     if (t == d_time_nan)
1151         return cast(DosFileTime)0;
1152 
1153     t += localTZA + daylightSavingTA(t);
1154 
1155     uint year = yearFromTime(t);
1156     uint month = monthFromTime(t);
1157     uint dayofmonth = dateFromTime(t);
1158     uint hour = hourFromTime(t);
1159     uint minute = minFromTime(t);
1160     uint second = secFromTime(t);
1161 
1162     dt = (year - 1980) << 25;
1163     dt |= ((month + 1) & 0x0F) << 21;
1164     dt |= (dayofmonth & 0x1F) << 16;
1165     dt |= (hour & 0x1F) << 11;
1166     dt |= (minute & 0x3F) << 5;
1167     dt |= (second >> 1) & 0x1F;
1168 
1169     return cast(DosFileTime)dt;
1170 }
1171 
1172 /**
1173 Benchmarks code for speed assessment and comparison.
1174 
1175 Params:
1176 
1177 fun = aliases of callable objects (e.g. function names). Each should
1178 take no arguments.
1179 
1180 times = The number of times each function is to be executed.
1181 
1182 result = The optional store for the return value. If $(D null) is
1183 passed in, new store is allocated appropriately.
1184 
1185 Returns:
1186 
1187 An array of $(D n) $(D uint)s. Element at slot $(D i) contains the
1188 number of milliseconds spent in calling the $(D i)th function $(D
1189 times) times.
1190 
1191 Example:
1192 ----
1193 int a;
1194 void f0() { }
1195 void f1() { auto b = a; }
1196 void f2() { auto b = to!(string)(a); }
1197 auto r = benchmark!(f0, f1, f2)(10_000_000);
1198 ----
1199  */
1200 ulong[] benchmark(fun...)(uint times, ulong[] result = null)
1201 {
1202     result.length = fun.length;
1203     result.length = 0;
1204     foreach (i, Unused; fun)
1205     {
1206         immutable t = getUTCtime();
1207         foreach (j; 0 .. times)
1208         {
1209             fun[i]();
1210         }
1211         immutable delta = getUTCtime() - t;
1212         result ~= cast(uint)delta;
1213     }
1214     foreach (ref e; result)
1215     {
1216         e *= 1000;
1217         e /= ticksPerSecond;
1218     }
1219     return result;
1220 }
1221 
1222 unittest
1223 {
1224     int a;
1225     void f0() { }
1226     //void f1() { auto b = to!(string)(a); }
1227     void f2() { auto b = (a); }
1228     auto r = benchmark!(f0, f2)(100);
1229     //writeln(r);
1230 }