comparison lphobos/std/date.d @ 473:373489eeaf90

Applied downs' lphobos update
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Mon, 04 Aug 2008 19:28:49 +0200
parents
children
comparison
equal deleted inserted replaced
472:15c804b6ce77 473:373489eeaf90
1
2 // Written in the D programming language.
3
4 /**
5 * Dates are represented in several formats. The date implementation revolves
6 * around a central type, d_time, from which other formats are converted to and
7 * from.
8 * Dates are calculated using the Gregorian calendar.
9 * References:
10 * $(LINK2 http://en.wikipedia.org/wiki/Gregorian_calendar, Gregorian calendar (Wikipedia))
11 * Macros:
12 * WIKI = Phobos/StdDate
13 */
14
15 // Copyright (c) 1999-2007 by Digital Mars
16 // All Rights Reserved
17 // written by Walter Bright
18 // www.digitalmars.com
19
20 /* NOTE: This file has been patched from the original DMD distribution to
21 work with the GDC compiler.
22
23 Modified by David Friedman, May 2005
24 */
25
26 module std.date;
27
28 private import std.stdio;
29 private import std.dateparse;
30
31 /**
32 * d_time is a signed arithmetic type giving the time elapsed since January 1,
33 * 1970.
34 * Negative values are for dates preceding 1970. The time unit used is Ticks.
35 * Ticks are milliseconds or smaller intervals.
36 *
37 * The usual arithmetic operations can be performed on d_time, such as adding,
38 * subtracting, etc. Elapsed time in Ticks can be computed by subtracting a
39 * starting d_time from an ending d_time.
40 */
41 alias long d_time;
42
43 /**
44 * A value for d_time that does not represent a valid time.
45 */
46 const d_time d_time_nan = long.min;
47
48 /**
49 * Time broken down into its components.
50 */
51 struct Date
52 {
53 int year = int.min; /// use int.min as "nan" year value
54 int month; /// 1..12
55 int day; /// 1..31
56 int hour; /// 0..23
57 int minute; /// 0..59
58 int second; /// 0..59
59 int ms; /// 0..999
60 int weekday; /// 0: not specified, 1..7: Sunday..Saturday
61 int tzcorrection = int.min; /// -1200..1200 correction in hours
62
63 /// Parse date out of string s[] and store it in this Date instance.
64 void parse(string s)
65 {
66 DateParse dp;
67
68 dp.parse(s, *this);
69 }
70 }
71
72 enum
73 {
74 HoursPerDay = 24,
75 MinutesPerHour = 60,
76 msPerMinute = 60 * 1000,
77 msPerHour = 60 * msPerMinute,
78 msPerDay = 86400000,
79 TicksPerMs = 1,
80 TicksPerSecond = 1000, /// Will be at least 1000
81 TicksPerMinute = TicksPerSecond * 60,
82 TicksPerHour = TicksPerMinute * 60,
83 TicksPerDay = TicksPerHour * 24,
84 }
85
86 d_time LocalTZA = 0;
87
88
89 const char[] daystr = "SunMonTueWedThuFriSat";
90 const char[] monstr = "JanFebMarAprMayJunJulAugSepOctNovDec";
91
92 const int[12] mdays = [ 0,31,59,90,120,151,181,212,243,273,304,334 ];
93
94 /********************************
95 * Compute year and week [1..53] from t. The ISO 8601 week 1 is the first week
96 * of the year that includes January 4. Monday is the first day of the week.
97 * References:
98 * $(LINK2 http://en.wikipedia.org/wiki/ISO_8601, ISO 8601 (Wikipedia))
99 */
100
101 void toISO8601YearWeek(d_time t, out int year, out int week)
102 {
103 year = YearFromTime(t);
104
105 int yday = Day(t) - DayFromYear(year);
106 int d;
107 int w;
108 int ydaybeg;
109
110 /* Determine day of week Jan 4 falls on.
111 * Weeks begin on a Monday.
112 */
113
114 d = DayFromYear(year);
115 w = (d + 3/*Jan4*/ + 3) % 7;
116 if (w < 0)
117 w += 7;
118
119 /* Find yday of beginning of ISO 8601 year
120 */
121 ydaybeg = 3/*Jan4*/ - w;
122
123 /* Check if yday is actually the last week of the previous year
124 */
125 if (yday < ydaybeg)
126 {
127 year -= 1;
128 week = 53;
129 return;
130 }
131
132 /* Check if yday is actually the first week of the next year
133 */
134 if (yday >= 362) // possible
135 { int d2;
136 int ydaybeg2;
137
138 d2 = DayFromYear(year + 1);
139 w = (d2 + 3/*Jan4*/ + 3) % 7;
140 if (w < 0)
141 w += 7;
142 //printf("w = %d\n", w);
143 ydaybeg2 = 3/*Jan4*/ - w;
144 if (d + yday >= d2 + ydaybeg2)
145 {
146 year += 1;
147 week = 1;
148 return;
149 }
150 }
151
152 week = (yday - ydaybeg) / 7 + 1;
153 }
154
155 /* ***********************************
156 * Divide time by divisor. Always round down, even if d is negative.
157 */
158
159 d_time floor(d_time d, int divisor)
160 {
161 if (d < 0)
162 d -= divisor - 1;
163 return d / divisor;
164 }
165
166 int dmod(d_time n, d_time d)
167 { d_time r;
168
169 r = n % d;
170 if (r < 0)
171 r += d;
172 assert(cast(int)r == r);
173 return cast(int)r;
174 }
175
176 int HourFromTime(d_time t)
177 {
178 return dmod(floor(t, msPerHour), HoursPerDay);
179 }
180
181 int MinFromTime(d_time t)
182 {
183 return dmod(floor(t, msPerMinute), MinutesPerHour);
184 }
185
186 int SecFromTime(d_time t)
187 {
188 return dmod(floor(t, TicksPerSecond), 60);
189 }
190
191 int msFromTime(d_time t)
192 {
193 return dmod(t / (TicksPerSecond / 1000), 1000);
194 }
195
196 int TimeWithinDay(d_time t)
197 {
198 return dmod(t, msPerDay);
199 }
200
201 d_time toInteger(d_time n)
202 {
203 return n;
204 }
205
206 int Day(d_time t)
207 {
208 return cast(int)floor(t, msPerDay);
209 }
210
211 int LeapYear(int y)
212 {
213 return ((y & 3) == 0 &&
214 (y % 100 || (y % 400) == 0));
215 }
216
217 int DaysInYear(int y)
218 {
219 return 365 + LeapYear(y);
220 }
221
222 int DayFromYear(int y)
223 {
224 return cast(int) (365 * (y - 1970) +
225 floor((y - 1969), 4) -
226 floor((y - 1901), 100) +
227 floor((y - 1601), 400));
228 }
229
230 d_time TimeFromYear(int y)
231 {
232 return cast(d_time)msPerDay * DayFromYear(y);
233 }
234
235 /*****************************
236 * Calculates the year from the d_time t.
237 */
238
239 int YearFromTime(d_time t)
240 { int y;
241
242 if (t == d_time_nan)
243 return 0;
244
245 // Hazard a guess
246 //y = 1970 + cast(int) (t / (365.2425 * msPerDay));
247 // Use integer only math
248 y = 1970 + cast(int) (t / (3652425 * (msPerDay / 10000)));
249
250 if (TimeFromYear(y) <= t)
251 {
252 while (TimeFromYear(y + 1) <= t)
253 y++;
254 }
255 else
256 {
257 do
258 {
259 y--;
260 }
261 while (TimeFromYear(y) > t);
262 }
263 return y;
264 }
265
266 /*******************************
267 * Determines if d_time t is a leap year.
268 *
269 * A leap year is every 4 years except years ending in 00 that are not
270 * divsible by 400.
271 *
272 * Returns: !=0 if it is a leap year.
273 *
274 * References:
275 * $(LINK2 http://en.wikipedia.org/wiki/Leap_year, Wikipedia)
276 */
277
278 int inLeapYear(d_time t)
279 {
280 return LeapYear(YearFromTime(t));
281 }
282
283 /*****************************
284 * Calculates the month from the d_time t.
285 *
286 * Returns: Integer in the range 0..11, where
287 * 0 represents January and 11 represents December.
288 */
289
290 int MonthFromTime(d_time t)
291 {
292 int day;
293 int month;
294 int year;
295
296 year = YearFromTime(t);
297 day = Day(t) - DayFromYear(year);
298
299 if (day < 59)
300 {
301 if (day < 31)
302 { assert(day >= 0);
303 month = 0;
304 }
305 else
306 month = 1;
307 }
308 else
309 {
310 day -= LeapYear(year);
311 if (day < 212)
312 {
313 if (day < 59)
314 month = 1;
315 else if (day < 90)
316 month = 2;
317 else if (day < 120)
318 month = 3;
319 else if (day < 151)
320 month = 4;
321 else if (day < 181)
322 month = 5;
323 else
324 month = 6;
325 }
326 else
327 {
328 if (day < 243)
329 month = 7;
330 else if (day < 273)
331 month = 8;
332 else if (day < 304)
333 month = 9;
334 else if (day < 334)
335 month = 10;
336 else if (day < 365)
337 month = 11;
338 else
339 assert(0);
340 }
341 }
342 return month;
343 }
344
345 /*******************************
346 * Compute which day in a month a d_time t is.
347 * Returns:
348 * Integer in the range 1..31
349 */
350 int DateFromTime(d_time t)
351 {
352 int day;
353 int leap;
354 int month;
355 int year;
356 int date;
357
358 year = YearFromTime(t);
359 day = Day(t) - DayFromYear(year);
360 leap = LeapYear(year);
361 month = MonthFromTime(t);
362 switch (month)
363 {
364 case 0: date = day + 1; break;
365 case 1: date = day - 30; break;
366 case 2: date = day - 58 - leap; break;
367 case 3: date = day - 89 - leap; break;
368 case 4: date = day - 119 - leap; break;
369 case 5: date = day - 150 - leap; break;
370 case 6: date = day - 180 - leap; break;
371 case 7: date = day - 211 - leap; break;
372 case 8: date = day - 242 - leap; break;
373 case 9: date = day - 272 - leap; break;
374 case 10: date = day - 303 - leap; break;
375 case 11: date = day - 333 - leap; break;
376 default:
377 assert(0);
378 }
379 return date;
380 }
381
382 /*******************************
383 * Compute which day of the week a d_time t is.
384 * Returns:
385 * Integer in the range 0..6, where 0 represents Sunday
386 * and 6 represents Saturday.
387 */
388 int WeekDay(d_time t)
389 { int w;
390
391 w = (cast(int)Day(t) + 4) % 7;
392 if (w < 0)
393 w += 7;
394 return w;
395 }
396
397 /***********************************
398 * Convert from UTC to local time.
399 */
400
401 d_time UTCtoLocalTime(d_time t)
402 {
403 return (t == d_time_nan)
404 ? d_time_nan
405 : t + LocalTZA + DaylightSavingTA(t);
406 }
407
408 /***********************************
409 * Convert from local time to UTC.
410 */
411
412 d_time LocalTimetoUTC(d_time t)
413 {
414 return (t == d_time_nan)
415 ? d_time_nan
416 : t - LocalTZA - DaylightSavingTA(t - LocalTZA);
417 }
418
419
420 d_time MakeTime(d_time hour, d_time min, d_time sec, d_time ms)
421 {
422 return hour * TicksPerHour +
423 min * TicksPerMinute +
424 sec * TicksPerSecond +
425 ms * TicksPerMs;
426 }
427
428
429 d_time MakeDay(d_time year, d_time month, d_time date)
430 { d_time t;
431 int y;
432 int m;
433 int leap;
434
435 y = cast(int)(year + floor(month, 12));
436 m = dmod(month, 12);
437
438 leap = LeapYear(y);
439 t = TimeFromYear(y) + cast(d_time)mdays[m] * msPerDay;
440 if (leap && month >= 2)
441 t += msPerDay;
442
443 if (YearFromTime(t) != y ||
444 MonthFromTime(t) != m ||
445 DateFromTime(t) != 1)
446 {
447 return d_time_nan;
448 }
449
450 return Day(t) + date - 1;
451 }
452
453 d_time MakeDate(d_time day, d_time time)
454 {
455 if (day == d_time_nan || time == d_time_nan)
456 return d_time_nan;
457
458 return day * TicksPerDay + time;
459 }
460
461 d_time TimeClip(d_time time)
462 {
463 //printf("TimeClip(%g) = %g\n", time, toInteger(time));
464
465 return toInteger(time);
466 }
467
468 /*************************************
469 * Converts UTC time into a text string of the form:
470 * "Www Mmm dd hh:mm:ss GMT+-TZ yyyy".
471 * For example, "Tue Apr 02 02:04:57 GMT-0800 1996".
472 * If time is invalid, i.e. is d_time_nan,
473 * the string "Invalid date" is returned.
474 *
475 * Example:
476 * ------------------------------------
477 d_time lNow;
478 char[] lNowString;
479
480 // Grab the date and time relative to UTC
481 lNow = std.date.getUTCtime();
482 // Convert this into the local date and time for display.
483 lNowString = std.date.toString(lNow);
484 * ------------------------------------
485 */
486
487 string toString(d_time time)
488 {
489 d_time t;
490 char sign;
491 int hr;
492 int mn;
493 int len;
494 d_time offset;
495 d_time dst;
496
497 // Years are supposed to be -285616 .. 285616, or 7 digits
498 // "Tue Apr 02 02:04:57 GMT-0800 1996"
499 char[] buffer = new char[29 + 7 + 1];
500
501 if (time == d_time_nan)
502 return "Invalid Date";
503
504 dst = DaylightSavingTA(time);
505 offset = LocalTZA + dst;
506 t = time + offset;
507 sign = '+';
508 if (offset < 0)
509 { sign = '-';
510 // offset = -offset;
511 offset = -(LocalTZA + dst);
512 }
513
514 mn = cast(int)(offset / msPerMinute);
515 hr = mn / 60;
516 mn %= 60;
517
518 //printf("hr = %d, offset = %g, LocalTZA = %g, dst = %g, + = %g\n", hr, offset, LocalTZA, dst, LocalTZA + dst);
519
520 len = sprintf(buffer.ptr, "%.3s %.3s %02d %02d:%02d:%02d GMT%c%02d%02d %d",
521 &daystr[WeekDay(t) * 3],
522 &monstr[MonthFromTime(t) * 3],
523 DateFromTime(t),
524 HourFromTime(t), MinFromTime(t), SecFromTime(t),
525 sign, hr, mn,
526 /*cast(long)*/YearFromTime(t));
527
528 // Ensure no buggy buffer overflows
529 //printf("len = %d, buffer.length = %d\n", len, buffer.length);
530 assert(len < buffer.length);
531
532 return buffer[0 .. len];
533 }
534
535 /***********************************
536 * Converts t into a text string of the form: "Www, dd Mmm yyyy hh:mm:ss UTC".
537 * If t is invalid, "Invalid date" is returned.
538 */
539
540 string toUTCString(d_time t)
541 {
542 // Years are supposed to be -285616 .. 285616, or 7 digits
543 // "Tue, 02 Apr 1996 02:04:57 GMT"
544 char[] buffer = new char[25 + 7 + 1];
545 int len;
546
547 if (t == d_time_nan)
548 return "Invalid Date";
549
550 len = sprintf(buffer.ptr, "%.3s, %02d %.3s %d %02d:%02d:%02d UTC",
551 &daystr[WeekDay(t) * 3], DateFromTime(t),
552 &monstr[MonthFromTime(t) * 3],
553 YearFromTime(t),
554 HourFromTime(t), MinFromTime(t), SecFromTime(t));
555
556 // Ensure no buggy buffer overflows
557 assert(len < buffer.length);
558
559 return buffer[0 .. len];
560 }
561
562 /************************************
563 * Converts the date portion of time into a text string of the form: "Www Mmm dd
564 * yyyy", for example, "Tue Apr 02 1996".
565 * If time is invalid, "Invalid date" is returned.
566 */
567
568 string toDateString(d_time time)
569 {
570 d_time t;
571 d_time offset;
572 d_time dst;
573 int len;
574
575 // Years are supposed to be -285616 .. 285616, or 7 digits
576 // "Tue Apr 02 1996"
577 char[] buffer = new char[29 + 7 + 1];
578
579 if (time == d_time_nan)
580 return "Invalid Date";
581
582 dst = DaylightSavingTA(time);
583 offset = LocalTZA + dst;
584 t = time + offset;
585
586 len = sprintf(buffer.ptr, "%.3s %.3s %02d %d",
587 &daystr[WeekDay(t) * 3],
588 &monstr[MonthFromTime(t) * 3],
589 DateFromTime(t),
590 /*cast(long)*/YearFromTime(t));
591
592 // Ensure no buggy buffer overflows
593 assert(len < buffer.length);
594
595 return buffer[0 .. len];
596 }
597
598 /******************************************
599 * Converts the time portion of t into a text string of the form: "hh:mm:ss
600 * GMT+-TZ", for example, "02:04:57 GMT-0800".
601 * If t is invalid, "Invalid date" is returned.
602 * The input must be in UTC, and the output is in local time.
603 */
604
605 string toTimeString(d_time time)
606 {
607 d_time t;
608 char sign;
609 int hr;
610 int mn;
611 int len;
612 d_time offset;
613 d_time dst;
614
615 // "02:04:57 GMT-0800"
616 char[] buffer = new char[17 + 1];
617
618 if (time == d_time_nan)
619 return "Invalid Date";
620
621 dst = DaylightSavingTA(time);
622 offset = LocalTZA + dst;
623 t = time + offset;
624 sign = '+';
625 if (offset < 0)
626 { sign = '-';
627 // offset = -offset;
628 offset = -(LocalTZA + dst);
629 }
630
631 mn = cast(int)(offset / msPerMinute);
632 hr = mn / 60;
633 mn %= 60;
634
635 //printf("hr = %d, offset = %g, LocalTZA = %g, dst = %g, + = %g\n", hr, offset, LocalTZA, dst, LocalTZA + dst);
636
637 len = sprintf(buffer.ptr, "%02d:%02d:%02d GMT%c%02d%02d",
638 HourFromTime(t), MinFromTime(t), SecFromTime(t),
639 sign, hr, mn);
640
641 // Ensure no buggy buffer overflows
642 assert(len < buffer.length);
643
644 // Lop off terminating 0
645 return buffer[0 .. len];
646 }
647
648
649 /******************************************
650 * Parses s as a textual date string, and returns it as a d_time.
651 * If the string is not a valid date, d_time_nan is returned.
652 */
653
654 d_time parse(string s)
655 {
656 Date dp;
657 d_time n;
658 d_time day;
659 d_time time;
660
661 try
662 {
663 dp.parse(s);
664
665 //writefln("year = %d, month = %d, day = %d", dp.year, dp.month, dp.day);
666 //writefln("%02d:%02d:%02d.%03d", dp.hour, dp.minute, dp.second, dp.ms);
667 //writefln("weekday = %d, ampm = %d, tzcorrection = %d", dp.weekday, 1, dp.tzcorrection);
668
669 time = MakeTime(dp.hour, dp.minute, dp.second, dp.ms);
670 if (dp.tzcorrection == int.min)
671 time -= LocalTZA;
672 else
673 {
674 time += cast(d_time)(dp.tzcorrection / 100) * msPerHour +
675 cast(d_time)(dp.tzcorrection % 100) * msPerMinute;
676 }
677 day = MakeDay(dp.year, dp.month - 1, dp.day);
678 n = MakeDate(day,time);
679 n = TimeClip(n);
680 }
681 catch
682 {
683 n = d_time_nan; // erroneous date string
684 }
685 return n;
686 }
687
688 static this()
689 {
690 LocalTZA = getLocalTZA();
691 //printf("LocalTZA = %g, %g\n", LocalTZA, LocalTZA / msPerHour);
692 }
693
694 version (Win32)
695 {
696
697 private import std.c.windows.windows;
698 //import c.time;
699
700 /******
701 * Get current UTC time.
702 */
703 d_time getUTCtime()
704 {
705 SYSTEMTIME st;
706 d_time n;
707
708 GetSystemTime(&st); // get time in UTC
709 n = SYSTEMTIME2d_time(&st, 0);
710 return n;
711 //return c.time.time(null) * TicksPerSecond;
712 }
713
714 static d_time FILETIME2d_time(FILETIME *ft)
715 { SYSTEMTIME st;
716
717 if (!FileTimeToSystemTime(ft, &st))
718 return d_time_nan;
719 return SYSTEMTIME2d_time(&st, 0);
720 }
721
722 static d_time SYSTEMTIME2d_time(SYSTEMTIME *st, d_time t)
723 {
724 d_time n;
725 d_time day;
726 d_time time;
727
728 if (st.wYear)
729 {
730 time = MakeTime(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
731 day = MakeDay(st.wYear, st.wMonth - 1, st.wDay);
732 }
733 else
734 { // wDayOfWeek is weekday, wDay is which week in the month
735 int year;
736 int wd;
737 int mday;
738 int month;
739 d_time x;
740
741 year = YearFromTime(t);
742 month = st.wMonth - 1;
743 x = MakeDay(year, month, 1);
744 wd = WeekDay(MakeDate(x, 0));
745
746 mday = (7 - wd + st.wDayOfWeek);
747 if (mday >= 7)
748 mday -= 7;
749 mday += (st.wDay - 1) * 7 + 1;
750 //printf("month = %d, wDayOfWeek = %d, wDay = %d, mday = %d\n", st.wMonth, st.wDayOfWeek, st.wDay, mday);
751
752 day = MakeDay(year, month, mday);
753 time = 0;
754 }
755 n = MakeDate(day,time);
756 n = TimeClip(n);
757 return n;
758 }
759
760 d_time getLocalTZA()
761 {
762 d_time t;
763 DWORD r;
764 TIME_ZONE_INFORMATION tzi;
765
766 /* http://msdn.microsoft.com/library/en-us/sysinfo/base/gettimezoneinformation.asp
767 * http://msdn2.microsoft.com/en-us/library/ms725481.aspx
768 */
769 r = GetTimeZoneInformation(&tzi);
770 //printf("bias = %d\n", tzi.Bias);
771 //printf("standardbias = %d\n", tzi.StandardBias);
772 //printf("daylightbias = %d\n", tzi.DaylightBias);
773 switch (r)
774 {
775 case TIME_ZONE_ID_STANDARD:
776 t = -(tzi.Bias + tzi.StandardBias) * cast(d_time)(60 * TicksPerSecond);
777 break;
778 case TIME_ZONE_ID_DAYLIGHT:
779 //t = -(tzi.Bias + tzi.DaylightBias) * cast(d_time)(60 * TicksPerSecond);
780 //break;
781 case TIME_ZONE_ID_UNKNOWN:
782 t = -(tzi.Bias) * cast(d_time)(60 * TicksPerSecond);
783 break;
784
785 default:
786 t = 0;
787 break;
788 }
789
790 return t;
791 }
792
793 /*
794 * Get daylight savings time adjust for time dt.
795 */
796
797 int DaylightSavingTA(d_time dt)
798 {
799 int t;
800 DWORD r;
801 TIME_ZONE_INFORMATION tzi;
802 d_time ts;
803 d_time td;
804
805 /* http://msdn.microsoft.com/library/en-us/sysinfo/base/gettimezoneinformation.asp
806 */
807 r = GetTimeZoneInformation(&tzi);
808 t = 0;
809 switch (r)
810 {
811 case TIME_ZONE_ID_STANDARD:
812 case TIME_ZONE_ID_DAYLIGHT:
813 if (tzi.StandardDate.wMonth == 0 ||
814 tzi.DaylightDate.wMonth == 0)
815 break;
816
817 ts = SYSTEMTIME2d_time(&tzi.StandardDate, dt);
818 td = SYSTEMTIME2d_time(&tzi.DaylightDate, dt);
819
820 if (td <= dt && dt <= ts)
821 {
822 t = -tzi.DaylightBias * (60 * TicksPerSecond);
823 //printf("DST is in effect, %d\n", t);
824 }
825 else
826 {
827 //printf("no DST\n");
828 }
829 break;
830
831 case TIME_ZONE_ID_UNKNOWN:
832 // Daylight savings time not used in this time zone
833 break;
834
835 default:
836 assert(0);
837 }
838 return t;
839 }
840 }
841 else version (linux)
842 {
843
844 private import std.c.linux.linux;
845
846 d_time getUTCtime()
847 { timeval tv;
848
849 //printf("getUTCtime()\n");
850 if (gettimeofday(&tv, null))
851 { // Some error happened - try time() instead
852 return time(null) * TicksPerSecond;
853 }
854
855 return tv.tv_sec * cast(d_time)TicksPerSecond +
856 (tv.tv_usec / (1000000 / cast(d_time)TicksPerSecond));
857 }
858
859 d_time getLocalTZA()
860 {
861 __time_t t;
862
863 time(&t);
864 localtime(&t); // this will set timezone
865 return -(timezone * TicksPerSecond);
866 }
867
868 /*
869 * Get daylight savings time adjust for time dt.
870 */
871
872 int DaylightSavingTA(d_time dt)
873 {
874 tm *tmp;
875 int dst = 0;
876
877 if (dt != d_time_nan)
878 {
879 d_time seconds = dt / TicksPerSecond;
880 int t;
881 t = cast(int) seconds;
882 if (t == seconds) // if in range
883 {
884 tmp = localtime(cast(__time_t*)&t);
885 if (tmp.tm_isdst > 0)
886 dst = TicksPerHour; // BUG: Assume daylight savings time is plus one hour.
887 }
888 else // out of range for system time, use our own calculation
889 { // Daylight savings time goes from 2 AM the first Sunday
890 // in April through 2 AM the last Sunday in October
891
892 dt -= LocalTZA;
893
894 int year = YearFromTime(dt);
895 int leap = LeapYear(dt);
896 //writefln("year = %s, leap = %s, month = %s", year, leap, MonthFromTime(dt));
897
898 d_time start = TimeFromYear(year); // Jan 1
899 d_time end = start;
900 // Move fwd to Apr 1
901 start += cast(d_time)(mdays[3] + leap) * TicksPerDay;
902 // Advance a day at a time until we find Sunday (0)
903 while (WeekDay(start) != 0)
904 start += TicksPerDay;
905
906 // Move fwd to Oct 30
907 end += cast(d_time)(mdays[9] + leap + 30) * TicksPerDay;
908 // Back up a day at a time until we find Sunday (0)
909 while (WeekDay(end) != 0) // 0 is Sunday
910 end -= TicksPerDay;
911
912 dt -= 2 * TicksPerHour; // 2 AM
913 if (dt >= start && dt <= end)
914 dst = TicksPerHour;
915 //writefln("start = %s, dt = %s, end = %s, dst = %s", start, dt, end, dst);
916 }
917 }
918 return dst;
919 }
920
921 }
922 else version (Unix)
923 {
924 // for now, just copy linux
925 private import std.c.unix.unix;
926
927 d_time getUTCtime()
928 { timeval tv;
929
930 if (gettimeofday(&tv, null))
931 { // Some error happened - try time() instead
932 return time(null) * TicksPerSecond;
933 }
934
935 return tv.tv_sec * cast(d_time)TicksPerSecond +
936 (tv.tv_usec / (1000000 / cast(d_time)TicksPerSecond));
937 }
938
939 private extern (C) time_t _d_gnu_cbridge_tza();
940
941 d_time getLocalTZA()
942 {
943 return _d_gnu_cbridge_tza() * TicksPerSecond;
944 }
945
946 /*
947 * Get daylight savings time adjust for time dt.
948 */
949
950 int DaylightSavingTA(d_time dt)
951 {
952 tm *tmp;
953 time_t t;
954 int dst = 0;
955
956 if (dt != d_time_nan)
957 {
958 d_time seconds = dt / TicksPerSecond;
959 t = cast(time_t) seconds;
960 if (t == seconds) // if in range
961 {
962 tmp = localtime(&t);
963 if (tmp.tm_isdst > 0)
964 dst = TicksPerHour; // BUG: Assume daylight savings time is plus one hour.
965 }
966 else // out of range for system time, use our own calculation
967 { // Daylight savings time goes from 2 AM the first Sunday
968 // in April through 2 AM the last Sunday in October
969
970 dt -= LocalTZA;
971
972 int year = YearFromTime(dt);
973 int leap = LeapYear(cast(int)dt);
974 //writefln("year = %s, leap = %s, month = %s", year, leap, MonthFromTime(dt));
975
976 d_time start = TimeFromYear(year); // Jan 1
977 d_time end = start;
978 // Move fwd to Apr 1
979 start += cast(d_time)(mdays[3] + leap) * TicksPerDay;
980 // Advance a day at a time until we find Sunday (0)
981 while (WeekDay(start) != 0)
982 start += TicksPerDay;
983
984 // Move fwd to Oct 30
985 end += cast(d_time)(mdays[9] + leap + 30) * TicksPerDay;
986 // Back up a day at a time until we find Sunday (0)
987 while (WeekDay(end) != 0) // 0 is Sunday
988 end -= TicksPerDay;
989
990 dt -= 2 * TicksPerHour; // 2 AM
991 if (dt >= start && dt <= end)
992 dst = TicksPerHour;
993 //writefln("start = %s, dt = %s, end = %s, dst = %s", start, dt, end, dst);
994 }
995 }
996 return dst;
997 }
998 }
999 else version (NoSystem)
1000 {
1001 d_time getLocalTZA() { return 0; }
1002 int DaylightSavingTA(d_time dt) { return 0; }
1003 }
1004
1005 /+ ====================== DOS File Time =============================== +/
1006
1007 /***
1008 * Type representing the DOS file date/time format.
1009 */
1010 typedef uint DosFileTime;
1011
1012 /************************************
1013 * Convert from DOS file date/time to d_time.
1014 */
1015
1016 d_time toDtime(DosFileTime time)
1017 {
1018 uint dt = cast(uint)time;
1019
1020 if (dt == 0)
1021 return d_time_nan;
1022
1023 int year = ((dt >> 25) & 0x7F) + 1980;
1024 int month = ((dt >> 21) & 0x0F) - 1; // 0..12
1025 int dayofmonth = ((dt >> 16) & 0x1F); // 0..31
1026 int hour = (dt >> 11) & 0x1F; // 0..23
1027 int minute = (dt >> 5) & 0x3F; // 0..59
1028 int second = (dt << 1) & 0x3E; // 0..58 (in 2 second increments)
1029
1030 d_time t;
1031
1032 t = std.date.MakeDate(std.date.MakeDay(year, month, dayofmonth),
1033 std.date.MakeTime(hour, minute, second, 0));
1034
1035 assert(YearFromTime(t) == year);
1036 assert(MonthFromTime(t) == month);
1037 assert(DateFromTime(t) == dayofmonth);
1038 assert(HourFromTime(t) == hour);
1039 assert(MinFromTime(t) == minute);
1040 assert(SecFromTime(t) == second);
1041
1042 t -= LocalTZA + DaylightSavingTA(t);
1043
1044 return t;
1045 }
1046
1047 /****************************************
1048 * Convert from d_time to DOS file date/time.
1049 */
1050
1051 DosFileTime toDosFileTime(d_time t)
1052 { uint dt;
1053
1054 if (t == d_time_nan)
1055 return cast(DosFileTime)0;
1056
1057 t += LocalTZA + DaylightSavingTA(t);
1058
1059 uint year = YearFromTime(t);
1060 uint month = MonthFromTime(t);
1061 uint dayofmonth = DateFromTime(t);
1062 uint hour = HourFromTime(t);
1063 uint minute = MinFromTime(t);
1064 uint second = SecFromTime(t);
1065
1066 dt = (year - 1980) << 25;
1067 dt |= ((month + 1) & 0x0F) << 21;
1068 dt |= (dayofmonth & 0x1F) << 16;
1069 dt |= (hour & 0x1F) << 11;
1070 dt |= (minute & 0x3F) << 5;
1071 dt |= (second >> 1) & 0x1F;
1072
1073 return cast(DosFileTime)dt;
1074 }