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
7 // Copyright: (c) Marco Cavallini
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ===========================================================================
13 // ===========================================================================
15 // ---------------------------------------------------------------------------
17 // ---------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
27 #include "wx/msw/wrapwin.h"
30 #include "wx/msw/wince/time.h"
32 #if defined(__VISUALC__) && (__VISUALC__ >= 1400)
34 // VC8 does provide the time functions but not the standard ones
37 time_t __cdecl
time(time_t *t
)
49 time_t __cdecl
mktime(struct tm
*t
)
51 return (time_t)_mktime64(t
);
56 /////////////////////////////////////////////////////////////////////////////////////////////
58 // strftime() - taken from OpenBSD //
60 /////////////////////////////////////////////////////////////////////////////////////////////
68 #define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
69 #define TYPE_SIGNED(type) (((type) -1) < 0)
71 #define INT_STRLEN_MAXIMUM(type) \
72 ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type))
74 #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
76 #define MONSPERYEAR 12
78 #define TM_YEAR_BASE 1900
79 #define HOURSPERDAY 24
80 #define DAYSPERNYEAR 365
81 #define DAYSPERLYEAR 366
83 static char wildabbr
[] = "WILDABBR";
91 #define Locale (&C_time_locale)
94 const char * mon
[MONSPERYEAR
];
95 const char * month
[MONSPERYEAR
];
96 const char * wday
[DAYSPERWEEK
];
97 const char * weekday
[DAYSPERWEEK
];
103 const char * date_fmt
;
106 static const struct lc_time_T C_time_locale
= {
108 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
109 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
111 "January", "February", "March", "April", "May", "June",
112 "July", "August", "September", "October", "November", "December"
114 "Sun", "Mon", "Tue", "Wed",
117 "Sunday", "Monday", "Tuesday", "Wednesday",
118 "Thursday", "Friday", "Saturday"
126 ** C99 requires this format.
127 ** Using just numbers (as here) makes Quakers happier;
128 ** it's also compatible with SVR4.
134 ** C99 requires this format.
135 ** Previously this code used "%D %X", but we now conform to C99.
137 ** "%a %b %d %H:%M:%S %Y"
138 ** is used by Solaris 2.3.
149 "%a %b %e %H:%M:%S %Z %Y"
154 _add(const char * str
, char * pt
, const char * const ptlim
)
156 while (pt
< ptlim
&& (*pt
= *str
++) != '\0')
163 _conv(const int n
, const char * const format
, char * const pt
, const char * const ptlim
)
165 char buf
[INT_STRLEN_MAXIMUM(int) + 1];
167 (void) _snprintf(buf
, sizeof buf
, format
, n
);
168 return _add(buf
, pt
, ptlim
);
173 _fmt(const char * format
, const struct tm
* const t
, char * pt
, const char * const ptlim
, int * warnp
)
175 for ( ; *format
; ++format
) {
176 if (*format
== '%') {
183 pt
= _add((t
->tm_wday
< 0 ||
184 t
->tm_wday
>= DAYSPERWEEK
) ?
185 "?" : Locale
->weekday
[t
->tm_wday
],
189 pt
= _add((t
->tm_wday
< 0 ||
190 t
->tm_wday
>= DAYSPERWEEK
) ?
191 "?" : Locale
->wday
[t
->tm_wday
],
195 pt
= _add((t
->tm_mon
< 0 ||
196 t
->tm_mon
>= MONSPERYEAR
) ?
197 "?" : Locale
->month
[t
->tm_mon
],
202 pt
= _add((t
->tm_mon
< 0 ||
203 t
->tm_mon
>= MONSPERYEAR
) ?
204 "?" : Locale
->mon
[t
->tm_mon
],
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.
215 pt
= _conv((t
->tm_year
+ TM_YEAR_BASE
) / 100,
222 pt
= _fmt(Locale
->c_fmt
, t
, pt
, ptlim
, warnp
);
230 pt
= _fmt("%m/%d/%y", t
, pt
, ptlim
, warnp
);
233 pt
= _conv(t
->tm_mday
, "%02d", pt
, ptlim
);
238 ** C99 locale modifiers.
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
248 pt
= _conv(t
->tm_mday
, "%2d", pt
, ptlim
);
251 pt
= _fmt("%Y-%m-%d", t
, pt
, ptlim
, warnp
);
254 pt
= _conv(t
->tm_hour
, "%02d", pt
, ptlim
);
257 pt
= _conv((t
->tm_hour
% 12) ?
258 (t
->tm_hour
% 12) : 12,
262 pt
= _conv(t
->tm_yday
+ 1, "%03d", pt
, ptlim
);
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.
275 pt
= _conv(t
->tm_hour
, "%2d", pt
, ptlim
);
280 ** After all this time, still unclaimed!
282 pt
= _add("kitchen sink", pt
, ptlim
);
284 #endif /* defined KITCHEN_SINK */
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.
295 pt
= _conv((t
->tm_hour
% 12) ?
296 (t
->tm_hour
% 12) : 12,
300 pt
= _conv(t
->tm_min
, "%02d", pt
, ptlim
);
303 pt
= _conv(t
->tm_mon
+ 1, "%02d", pt
, ptlim
);
306 pt
= _add("\n", pt
, ptlim
);
309 pt
= _add((t
->tm_hour
>= (HOURSPERDAY
/ 2)) ?
315 pt
= _fmt("%H:%M", t
, pt
, ptlim
, warnp
);
318 pt
= _fmt("%I:%M:%S %p", t
, pt
, ptlim
, warnp
);
321 pt
= _conv(t
->tm_sec
, "%02d", pt
, ptlim
);
326 char buf
[INT_STRLEN_MAXIMUM(
332 if (TYPE_SIGNED(time_t))
333 (void) _snprintf(buf
, sizeof buf
,
335 else (void) _snprintf(buf
, sizeof buf
,
336 "%lu", (unsigned long) mkt
);
337 pt
= _add(buf
, pt
, ptlim
);
341 pt
= _fmt("%H:%M:%S", t
, pt
, ptlim
, warnp
);
344 pt
= _add("\t", pt
, ptlim
);
347 pt
= _conv((t
->tm_yday
+ DAYSPERWEEK
-
348 t
->tm_wday
) / DAYSPERWEEK
,
353 ** From Arnold Robbins' strftime version 3.0:
354 ** "ISO 8601: Weekday as a decimal number
358 pt
= _conv((t
->tm_wday
== 0) ?
359 DAYSPERWEEK
: t
->tm_wday
,
362 case 'V': /* ISO 8601 week number */
363 case 'G': /* ISO 8601 year (four digits) */
364 case 'g': /* ISO 8601 year (two digits) */
371 year
= t
->tm_year
+ TM_YEAR_BASE
;
383 ** What yday (-3 ... 3) does
384 ** the ISO year begin on?
386 bot
= ((yday
+ 11 - wday
) %
389 ** What yday does the NEXT
390 ** ISO year begin on?
403 w
= 1 + ((yday
- bot
) /
408 yday
+= isleap(year
) ?
413 pt
= _conv(w
, "%02d",
415 else if (*format
== 'g') {
417 pt
= _conv(year
% 100, "%02d",
419 } else pt
= _conv(year
, "%04d",
424 pt
= _fmt("%e-%b-%Y", t
, pt
, ptlim
, warnp
);
427 pt
= _conv((t
->tm_yday
+ DAYSPERWEEK
-
430 (DAYSPERWEEK
- 1))) / DAYSPERWEEK
,
434 pt
= _conv(t
->tm_wday
, "%d", pt
, ptlim
);
437 pt
= _fmt(Locale
->X_fmt
, t
, pt
, ptlim
, warnp
);
443 pt
= _fmt(Locale
->x_fmt
, t
, pt
, ptlim
, &warn2
);
452 pt
= _conv((t
->tm_year
+ TM_YEAR_BASE
) % 100,
456 pt
= _conv(t
->tm_year
+ TM_YEAR_BASE
, "%04d",
460 if (t
->tm_isdst
>= 0)
461 pt
= _add(tzname
[t
->tm_isdst
!= 0],
464 ** C99 says that %Z must be replaced by the
465 ** empty string if the time zone is not
471 int diff
= -timezone
;
478 pt
= _add(sign
, pt
, ptlim
);
480 pt
= _conv((diff
/60)*100 + diff%60
,
485 pt
= _fmt(Locale
->date_fmt
, t
, pt
, ptlim
,
501 strftime(char * const s
, const size_t maxsize
, const char *format
, const struct tm
* const t
)
509 p
= _fmt(((format
== NULL
) ? "%c" : format
), t
, s
, s
+ maxsize
, &warn
);
511 if (p
== s
+ maxsize
) {
513 s
[maxsize
- 1] = '\0';
523 /* Not needed in VS Studio 2005 */
525 size_t wcsftime(wchar_t *s
,
526 const size_t maxsize
,
527 const wchar_t *format
,
530 wxCharBuffer
sBuf(maxsize
/sizeof(wchar_t));
532 wxString
formatStr(format
);
533 wxCharBuffer
bufFormatStr(formatStr
.mb_str());
535 size_t sz
= strftime(sBuf
.data(), maxsize
/sizeof(wchar_t), bufFormatStr
, t
);
537 wxMB2WC(s
, sBuf
, maxsize
);
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
552 #define DO_LOCALTIME 1
555 long timezone
; // global variable
558 ////////////////////////////////////////////////////////////////////////
559 // Common code for localtime and gmtime (static)
560 ////////////////////////////////////////////////////////////////////////
562 static struct tm
* __cdecl
common_localtime(const time_t *t
, BOOL bLocal
)
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
572 const unsigned short int __mon_yday
[2][13] =
575 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
577 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
581 ::GetLocalTime(&SystemTime
);
585 i64
= i64
* 10000000 + 116444736000000000;
587 ft
.dwLowDateTime
= i64
.GetLo();
588 ft
.dwHighDateTime
= i64
.GetHi();
590 ::FileTimeToSystemTime(&ft
, &SystemTime
);
593 ::GetTimeZoneInformation(&pTz
);
595 ///////////////////////////////////////////////
597 timezone
= pTz
.Bias
* SECONDS_IN_ONE_MINUTE
;
598 ///////////////////////////////////////////////
600 iLeap
= is_leap(SystemTime
.wYear
) ;
602 res
->tm_hour
= SystemTime
.wHour
;
603 res
->tm_min
= SystemTime
.wMinute
;
604 res
->tm_sec
= SystemTime
.wSecond
;
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
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
614 // if localtime behaviour and daylight saving
615 if (bLocal
&& pTz
.DaylightBias
!= 0)
618 res
->tm_isdst
= 0; // without daylight saving or gmtime
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
)
632 return common_localtime(t
, DO_LOCALTIME
) ;
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
)
641 return common_localtime(t
, DO_GMTIME
) ;
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
)
652 // Use mktime since it seems less broken
662 t
.tm_year
= year
- 1900;
666 static int mdays
[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 } ;
670 prog
+= mdays
[month
- 1] ;
671 if (month
== 2 && is_leap(year
))
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
;
680 // Add Calculated elapsed seconds in the current day
681 prog
+= (hour
* SECONDS_IN_ONE_HOUR
+ minute
*
682 SECONDS_IN_ONE_MIN
+ second
) ;
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
)
701 SYSTEMTIME SystemTime
;
703 ::GetLocalTime(&SystemTime
) ;
704 prog
= common_tm_to_time(SystemTime
.wDay
, SystemTime
.wMonth
, SystemTime
.wYear
,
705 SystemTime
.wHour
, SystemTime
.wMinute
, SystemTime
.wSecond
) ;
712 ////////////////////////////////////////////////////////////////////////
713 // Converts the local time provided by struct tm
714 // into a time_t calendar value
715 // Implementation from OpenBSD
716 ////////////////////////////////////////////////////////////////////////
719 int month_to_day
[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
721 time_t mktime(struct tm
*t
)
727 year
= t
->tm_year
+ month
/ 12 + 1900;
734 result
= (year
- 1970) * 365 + (year
- 1969) / 4 + month_to_day
[month
];
735 result
= (year
- 1970) * 365 + month_to_day
[month
];
738 result
+= (year
- 1968) / 4;
739 result
-= (year
- 1900) / 100;
740 result
+= (year
- 1600) / 400;
741 result
+= t
->tm_mday
;
744 result
+= t
->tm_hour
;
753 time_t __cdecl
mktime(struct tm
*t
)
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
)) ;