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