Mercurial > projects > ldc
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 } |