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