]> git.saurik.com Git - wxWidgets.git/blob - src/msw/wince/time.cpp
Don't document wxSortedArrayString as deriving from wxArrayString.
[wxWidgets.git] / src / msw / wince / time.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/wince/time.cpp
3 // Purpose: Implements missing time functionality for WinCE
4 // Author: Marco Cavallini (MCK) - wx@koansoftware.com
5 // Modified by: Vadim Zeitlin for VC8 support
6 // Created: 31-08-2003
7 // Copyright: (c) Marco Cavallini
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ===========================================================================
12 // declarations
13 // ===========================================================================
14
15 // ---------------------------------------------------------------------------
16 // headers
17 // ---------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #ifndef WX_PRECOMP
27 #include "wx/msw/wrapwin.h"
28 #endif
29
30 #include "wx/msw/wince/time.h"
31
32 #if defined(__VISUALC__) && (__VISUALC__ >= 1400)
33
34 // VC8 does provide the time functions but not the standard ones
35 #include <altcecrt.h>
36
37 time_t __cdecl time(time_t *t)
38 {
39 __time64_t t64;
40 if ( !_time64(&t64) )
41 return (time_t)-1;
42
43 if ( t )
44 *t = (time_t)t64;
45
46 return (time_t)t64;
47 }
48
49 time_t __cdecl mktime(struct tm *t)
50 {
51 return (time_t)_mktime64(t);
52 }
53
54 #else // !VC8
55
56 /////////////////////////////////////////////////////////////////////////////////////////////
57 // //
58 // strftime() - taken from OpenBSD //
59 // //
60 /////////////////////////////////////////////////////////////////////////////////////////////
61
62 #define IN_NONE 0
63 #define IN_SOME 1
64 #define IN_THIS 2
65 #define IN_ALL 3
66 #define CHAR_BIT 8
67
68 #define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
69 #define TYPE_SIGNED(type) (((type) -1) < 0)
70
71 #define INT_STRLEN_MAXIMUM(type) \
72 ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type))
73
74 #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
75
76 #define MONSPERYEAR 12
77 #define DAYSPERWEEK 7
78 #define TM_YEAR_BASE 1900
79 #define HOURSPERDAY 24
80 #define DAYSPERNYEAR 365
81 #define DAYSPERLYEAR 366
82
83 static char wildabbr[] = "WILDABBR";
84
85 char * tzname[2] = {
86 wildabbr,
87 wildabbr
88 };
89
90
91 #define Locale (&C_time_locale)
92
93 struct lc_time_T {
94 const char * mon[MONSPERYEAR];
95 const char * month[MONSPERYEAR];
96 const char * wday[DAYSPERWEEK];
97 const char * weekday[DAYSPERWEEK];
98 const char * X_fmt;
99 const char * x_fmt;
100 const char * c_fmt;
101 const char * am;
102 const char * pm;
103 const char * date_fmt;
104 };
105
106 static const struct lc_time_T C_time_locale = {
107 {
108 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
109 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
110 }, {
111 "January", "February", "March", "April", "May", "June",
112 "July", "August", "September", "October", "November", "December"
113 }, {
114 "Sun", "Mon", "Tue", "Wed",
115 "Thu", "Fri", "Sat"
116 }, {
117 "Sunday", "Monday", "Tuesday", "Wednesday",
118 "Thursday", "Friday", "Saturday"
119 },
120
121 /* X_fmt */
122 "%H:%M:%S",
123
124 /*
125 ** x_fmt
126 ** C99 requires this format.
127 ** Using just numbers (as here) makes Quakers happier;
128 ** it's also compatible with SVR4.
129 */
130 "%m/%d/%y",
131
132 /*
133 ** c_fmt
134 ** C99 requires this format.
135 ** Previously this code used "%D %X", but we now conform to C99.
136 ** Note that
137 ** "%a %b %d %H:%M:%S %Y"
138 ** is used by Solaris 2.3.
139 */
140 "%a %b %e %T %Y",
141
142 /* am */
143 "AM",
144
145 /* pm */
146 "PM",
147
148 /* date_fmt */
149 "%a %b %e %H:%M:%S %Z %Y"
150 };
151
152
153 static char *
154 _add(const char * str, char * pt, const char * const ptlim)
155 {
156 while (pt < ptlim && (*pt = *str++) != '\0')
157 ++pt;
158 return pt;
159 }
160
161
162 static char *
163 _conv(const int n, const char * const format, char * const pt, const char * const ptlim)
164 {
165 char buf[INT_STRLEN_MAXIMUM(int) + 1];
166
167 (void) _snprintf(buf, sizeof buf, format, n);
168 return _add(buf, pt, ptlim);
169 }
170
171
172 static char *
173 _fmt(const char * format, const struct tm * const t, char * pt, const char * const ptlim, int * warnp)
174 {
175 for ( ; *format; ++format) {
176 if (*format == '%') {
177 label:
178 switch (*++format) {
179 case '\0':
180 --format;
181 break;
182 case 'A':
183 pt = _add((t->tm_wday < 0 ||
184 t->tm_wday >= DAYSPERWEEK) ?
185 "?" : Locale->weekday[t->tm_wday],
186 pt, ptlim);
187 continue;
188 case 'a':
189 pt = _add((t->tm_wday < 0 ||
190 t->tm_wday >= DAYSPERWEEK) ?
191 "?" : Locale->wday[t->tm_wday],
192 pt, ptlim);
193 continue;
194 case 'B':
195 pt = _add((t->tm_mon < 0 ||
196 t->tm_mon >= MONSPERYEAR) ?
197 "?" : Locale->month[t->tm_mon],
198 pt, ptlim);
199 continue;
200 case 'b':
201 case 'h':
202 pt = _add((t->tm_mon < 0 ||
203 t->tm_mon >= MONSPERYEAR) ?
204 "?" : Locale->mon[t->tm_mon],
205 pt, ptlim);
206 continue;
207 case 'C':
208 /*
209 ** %C used to do a...
210 ** _fmt("%a %b %e %X %Y", t);
211 ** ...whereas now POSIX 1003.2 calls for
212 ** something completely different.
213 ** (ado, 1993-05-24)
214 */
215 pt = _conv((t->tm_year + TM_YEAR_BASE) / 100,
216 "%02d", pt, ptlim);
217 continue;
218 case 'c':
219 {
220 int warn2 = IN_SOME;
221
222 pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp);
223 if (warn2 == IN_ALL)
224 warn2 = IN_THIS;
225 if (warn2 > *warnp)
226 *warnp = warn2;
227 }
228 continue;
229 case 'D':
230 pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
231 continue;
232 case 'd':
233 pt = _conv(t->tm_mday, "%02d", pt, ptlim);
234 continue;
235 case 'E':
236 case 'O':
237 /*
238 ** C99 locale modifiers.
239 ** The sequences
240 ** %Ec %EC %Ex %EX %Ey %EY
241 ** %Od %oe %OH %OI %Om %OM
242 ** %OS %Ou %OU %OV %Ow %OW %Oy
243 ** are supposed to provide alternate
244 ** representations.
245 */
246 goto label;
247 case 'e':
248 pt = _conv(t->tm_mday, "%2d", pt, ptlim);
249 continue;
250 case 'F':
251 pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
252 continue;
253 case 'H':
254 pt = _conv(t->tm_hour, "%02d", pt, ptlim);
255 continue;
256 case 'I':
257 pt = _conv((t->tm_hour % 12) ?
258 (t->tm_hour % 12) : 12,
259 "%02d", pt, ptlim);
260 continue;
261 case 'j':
262 pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);
263 continue;
264 case 'k':
265 /*
266 ** This used to be...
267 ** _conv(t->tm_hour % 12 ?
268 ** t->tm_hour % 12 : 12, 2, ' ');
269 ** ...and has been changed to the below to
270 ** match SunOS 4.1.1 and Arnold Robbins'
271 ** strftime version 3.0. That is, "%k" and
272 ** "%l" have been swapped.
273 ** (ado, 1993-05-24)
274 */
275 pt = _conv(t->tm_hour, "%2d", pt, ptlim);
276 continue;
277 #ifdef KITCHEN_SINK
278 case 'K':
279 /*
280 ** After all this time, still unclaimed!
281 */
282 pt = _add("kitchen sink", pt, ptlim);
283 continue;
284 #endif /* defined KITCHEN_SINK */
285 case 'l':
286 /*
287 ** This used to be...
288 ** _conv(t->tm_hour, 2, ' ');
289 ** ...and has been changed to the below to
290 ** match SunOS 4.1.1 and Arnold Robbin's
291 ** strftime version 3.0. That is, "%k" and
292 ** "%l" have been swapped.
293 ** (ado, 1993-05-24)
294 */
295 pt = _conv((t->tm_hour % 12) ?
296 (t->tm_hour % 12) : 12,
297 "%2d", pt, ptlim);
298 continue;
299 case 'M':
300 pt = _conv(t->tm_min, "%02d", pt, ptlim);
301 continue;
302 case 'm':
303 pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);
304 continue;
305 case 'n':
306 pt = _add("\n", pt, ptlim);
307 continue;
308 case 'p':
309 pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
310 Locale->pm :
311 Locale->am,
312 pt, ptlim);
313 continue;
314 case 'R':
315 pt = _fmt("%H:%M", t, pt, ptlim, warnp);
316 continue;
317 case 'r':
318 pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp);
319 continue;
320 case 'S':
321 pt = _conv(t->tm_sec, "%02d", pt, ptlim);
322 continue;
323 case 's':
324 {
325 struct tm tm;
326 char buf[INT_STRLEN_MAXIMUM(
327 time_t) + 1];
328 time_t mkt;
329
330 tm = *t;
331 mkt = mktime(&tm);
332 if (TYPE_SIGNED(time_t))
333 (void) _snprintf(buf, sizeof buf,
334 "%ld", (long) mkt);
335 else (void) _snprintf(buf, sizeof buf,
336 "%lu", (unsigned long) mkt);
337 pt = _add(buf, pt, ptlim);
338 }
339 continue;
340 case 'T':
341 pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
342 continue;
343 case 't':
344 pt = _add("\t", pt, ptlim);
345 continue;
346 case 'U':
347 pt = _conv((t->tm_yday + DAYSPERWEEK -
348 t->tm_wday) / DAYSPERWEEK,
349 "%02d", pt, ptlim);
350 continue;
351 case 'u':
352 /*
353 ** From Arnold Robbins' strftime version 3.0:
354 ** "ISO 8601: Weekday as a decimal number
355 ** [1 (Monday) - 7]"
356 ** (ado, 1993-05-24)
357 */
358 pt = _conv((t->tm_wday == 0) ?
359 DAYSPERWEEK : t->tm_wday,
360 "%d", pt, ptlim);
361 continue;
362 case 'V': /* ISO 8601 week number */
363 case 'G': /* ISO 8601 year (four digits) */
364 case 'g': /* ISO 8601 year (two digits) */
365 {
366 int year;
367 int yday;
368 int wday;
369 int w;
370
371 year = t->tm_year + TM_YEAR_BASE;
372 yday = t->tm_yday;
373 wday = t->tm_wday;
374 for ( ; ; ) {
375 int len;
376 int bot;
377 int top;
378
379 len = isleap(year) ?
380 DAYSPERLYEAR :
381 DAYSPERNYEAR;
382 /*
383 ** What yday (-3 ... 3) does
384 ** the ISO year begin on?
385 */
386 bot = ((yday + 11 - wday) %
387 DAYSPERWEEK) - 3;
388 /*
389 ** What yday does the NEXT
390 ** ISO year begin on?
391 */
392 top = bot -
393 (len % DAYSPERWEEK);
394 if (top < -3)
395 top += DAYSPERWEEK;
396 top += len;
397 if (yday >= top) {
398 ++year;
399 w = 1;
400 break;
401 }
402 if (yday >= bot) {
403 w = 1 + ((yday - bot) /
404 DAYSPERWEEK);
405 break;
406 }
407 --year;
408 yday += isleap(year) ?
409 DAYSPERLYEAR :
410 DAYSPERNYEAR;
411 }
412 if (*format == 'V')
413 pt = _conv(w, "%02d",
414 pt, ptlim);
415 else if (*format == 'g') {
416 *warnp = IN_ALL;
417 pt = _conv(year % 100, "%02d",
418 pt, ptlim);
419 } else pt = _conv(year, "%04d",
420 pt, ptlim);
421 }
422 continue;
423 case 'v':
424 pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
425 continue;
426 case 'W':
427 pt = _conv((t->tm_yday + DAYSPERWEEK -
428 (t->tm_wday ?
429 (t->tm_wday - 1) :
430 (DAYSPERWEEK - 1))) / DAYSPERWEEK,
431 "%02d", pt, ptlim);
432 continue;
433 case 'w':
434 pt = _conv(t->tm_wday, "%d", pt, ptlim);
435 continue;
436 case 'X':
437 pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp);
438 continue;
439 case 'x':
440 {
441 int warn2 = IN_SOME;
442
443 pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2);
444 if (warn2 == IN_ALL)
445 warn2 = IN_THIS;
446 if (warn2 > *warnp)
447 *warnp = warn2;
448 }
449 continue;
450 case 'y':
451 *warnp = IN_ALL;
452 pt = _conv((t->tm_year + TM_YEAR_BASE) % 100,
453 "%02d", pt, ptlim);
454 continue;
455 case 'Y':
456 pt = _conv(t->tm_year + TM_YEAR_BASE, "%04d",
457 pt, ptlim);
458 continue;
459 case 'Z':
460 if (t->tm_isdst >= 0)
461 pt = _add(tzname[t->tm_isdst != 0],
462 pt, ptlim);
463 /*
464 ** C99 says that %Z must be replaced by the
465 ** empty string if the time zone is not
466 ** determinable.
467 */
468 continue;
469 case 'z':
470 {
471 int diff = -timezone;
472 char const * sign;
473
474 if (diff < 0) {
475 sign = "-";
476 diff = -diff;
477 } else sign = "+";
478 pt = _add(sign, pt, ptlim);
479 diff /= 60;
480 pt = _conv((diff/60)*100 + diff%60,
481 "%04d", pt, ptlim);
482 }
483 continue;
484 case '+':
485 pt = _fmt(Locale->date_fmt, t, pt, ptlim,
486 warnp);
487 continue;
488 case '%':
489 default:
490 break;
491 }
492 }
493 if (pt == ptlim)
494 break;
495 *pt++ = *format;
496 }
497 return pt;
498 }
499
500 size_t
501 strftime(char * const s, const size_t maxsize, const char *format, const struct tm * const t)
502 {
503 char *p;
504 int warn;
505
506 //tzset();
507
508 warn = IN_NONE;
509 p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn);
510
511 if (p == s + maxsize) {
512 if (maxsize > 0)
513 s[maxsize - 1] = '\0';
514 return 0;
515 }
516 *p = '\0';
517 return p - s;
518 }
519
520 extern "C"
521 {
522
523 /* Not needed in VS Studio 2005 */
524
525 size_t wcsftime(wchar_t *s,
526 const size_t maxsize,
527 const wchar_t *format,
528 const struct tm *t)
529 {
530 wxCharBuffer sBuf(maxsize/sizeof(wchar_t));
531
532 wxString formatStr(format);
533 wxCharBuffer bufFormatStr(formatStr.mb_str());
534
535 size_t sz = strftime(sBuf.data(), maxsize/sizeof(wchar_t), bufFormatStr, t);
536
537 wxMB2WC(s, sBuf, maxsize);
538
539 return sz;
540 }
541
542 } /* extern "C" */
543
544 #define is_leap(y) (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
545 #define SECONDS_IN_ONE_MINUTE 60
546 #define DAYS_IN_ONE_YEAR 365
547 #define SECONDS_IN_ONE_MIN 60
548 #define SECONDS_IN_ONE_HOUR 3600
549 #define SECONDS_IN_ONE_DAY 86400
550 #define DEFAULT_TIMEZONE 28800
551 #define DO_GMTIME 0
552 #define DO_LOCALTIME 1
553
554
555 long timezone ; // global variable
556
557
558 ////////////////////////////////////////////////////////////////////////
559 // Common code for localtime and gmtime (static)
560 ////////////////////////////////////////////////////////////////////////
561
562 static struct tm * __cdecl common_localtime(const time_t *t, BOOL bLocal)
563 {
564 wxLongLong i64;
565 FILETIME ft;
566 wxString str ;
567 SYSTEMTIME SystemTime;
568 TIME_ZONE_INFORMATION pTz;
569 static struct tm st_res ; // data holder
570 static struct tm * res = &st_res ; // data pointer
571 int iLeap;
572 const unsigned short int __mon_yday[2][13] =
573 {
574 // Normal years
575 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
576 // Leap years
577 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
578 };
579
580 if (!*t)
581 ::GetLocalTime(&SystemTime);
582 else
583 {
584 i64 = *t;
585 i64 = i64 * 10000000 + 116444736000000000;
586
587 ft.dwLowDateTime = i64.GetLo();
588 ft.dwHighDateTime = i64.GetHi();
589
590 ::FileTimeToSystemTime(&ft, &SystemTime);
591 }
592
593 ::GetTimeZoneInformation(&pTz);
594
595 ///////////////////////////////////////////////
596 // Set timezone
597 timezone = pTz.Bias * SECONDS_IN_ONE_MINUTE ;
598 ///////////////////////////////////////////////
599
600 iLeap = is_leap(SystemTime.wYear) ;
601
602 res->tm_hour = SystemTime.wHour;
603 res->tm_min = SystemTime.wMinute;
604 res->tm_sec = SystemTime.wSecond;
605
606 res->tm_mday = SystemTime.wDay;
607 res->tm_mon = SystemTime.wMonth - 1; // this the correct month but localtime returns month aligned to zero
608 res->tm_year = SystemTime.wYear; // this the correct year
609 res->tm_year = res->tm_year - 1900; // but localtime returns the value starting at the 1900
610
611 res->tm_wday = SystemTime.wDayOfWeek;
612 res->tm_yday = __mon_yday[iLeap][res->tm_mon] + SystemTime.wDay - 1; // localtime returns year-day aligned to zero
613
614 // if localtime behaviour and daylight saving
615 if (bLocal && pTz.DaylightBias != 0)
616 res->tm_isdst = 1;
617 else
618 res->tm_isdst = 0; // without daylight saving or gmtime
619
620 return res;
621 }
622
623 extern "C"
624 {
625
626 ////////////////////////////////////////////////////////////////////////
627 // Receive the number of seconds elapsed since midnight(00:00:00)
628 // and convert a time value and corrects for the local time zone
629 ////////////////////////////////////////////////////////////////////////
630 struct tm * __cdecl localtime(const time_t * t)
631 {
632 return common_localtime(t, DO_LOCALTIME) ;
633 }
634
635 ////////////////////////////////////////////////////////////////////////
636 // Receives the number of seconds elapsed since midnight(00:00:00)
637 // and converts a time value WITHOUT correcting for the local time zone
638 ////////////////////////////////////////////////////////////////////////
639 struct tm * __cdecl gmtime(const time_t *t)
640 {
641 return common_localtime(t, DO_GMTIME) ;
642 }
643
644 }
645
646 ////////////////////////////////////////////////////////////////////////
647 // Common code for conversion of struct tm into time_t (static)
648 ////////////////////////////////////////////////////////////////////////
649 static time_t __cdecl common_tm_to_time(int day, int month, int year, int hour, int minute, int second)
650 {
651 #if 1
652 // Use mktime since it seems less broken
653 tm t;
654 t.tm_isdst = -1;
655 t.tm_hour = hour;
656 t.tm_mday = day;
657 t.tm_min = minute;
658 t.tm_mon = month-1;
659 t.tm_sec = second;
660 t.tm_wday = -1;
661 t.tm_yday = -1;
662 t.tm_year = year - 1900;
663 return mktime(& t);
664 #else
665 time_t prog = 0 ;
666 static int mdays[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 } ;
667
668 while (--month)
669 {
670 prog += mdays[month - 1] ;
671 if (month == 2 && is_leap(year))
672 prog++ ;
673 }
674
675 // Calculate seconds in elapsed days
676 prog = day - 1 ; // align first day of the year to zero
677 prog += (DAYS_IN_ONE_YEAR * (year - 1970) + (year - 1901) / 4 - 19) ;
678 prog *= SECONDS_IN_ONE_DAY ;
679
680 // Add Calculated elapsed seconds in the current day
681 prog += (hour * SECONDS_IN_ONE_HOUR + minute *
682 SECONDS_IN_ONE_MIN + second) ;
683
684 return prog ;
685 #endif
686 }
687
688 extern "C"
689 {
690
691 ////////////////////////////////////////////////////////////////////////
692 // Returns the number of seconds elapsed since
693 // midnight(00:00:00) of 1 January 1970
694 ////////////////////////////////////////////////////////////////////////
695 time_t __cdecl time(time_t *t)
696 {
697 time_t prog = 0 ;
698
699 if (t != NULL)
700 {
701 SYSTEMTIME SystemTime;
702
703 ::GetLocalTime(&SystemTime) ;
704 prog = common_tm_to_time(SystemTime.wDay, SystemTime.wMonth, SystemTime.wYear,
705 SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond) ;
706 *t = prog ;
707 }
708
709 return prog ;
710 }
711
712 ////////////////////////////////////////////////////////////////////////
713 // Converts the local time provided by struct tm
714 // into a time_t calendar value
715 // Implementation from OpenBSD
716 ////////////////////////////////////////////////////////////////////////
717
718 #if 1
719 int month_to_day[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
720
721 time_t mktime(struct tm *t)
722 {
723 short month, year;
724 time_t result;
725
726 month = t->tm_mon;
727 year = t->tm_year + month / 12 + 1900;
728 month %= 12;
729 if (month < 0)
730 {
731 year -= 1;
732 month += 12;
733 }
734 result = (year - 1970) * 365 + (year - 1969) / 4 + month_to_day[month];
735 result = (year - 1970) * 365 + month_to_day[month];
736 if (month <= 1)
737 year -= 1;
738 result += (year - 1968) / 4;
739 result -= (year - 1900) / 100;
740 result += (year - 1600) / 400;
741 result += t->tm_mday;
742 result -= 1;
743 result *= 24;
744 result += t->tm_hour;
745 result *= 60;
746 result += t->tm_min;
747 result *= 60;
748 result += t->tm_sec;
749 return(result);
750 }
751
752 #else
753 time_t __cdecl mktime(struct tm *t)
754 {
755 return (common_tm_to_time(t->tm_mday, t->tm_mon+1, t->tm_year+1900, t->tm_hour, t->tm_min, t->tm_sec)) ;
756 }
757 #endif
758
759 } // extern "C"
760
761 #endif // VC8/!VC8