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
8 // Copyright: (c) Marco Cavallini
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
28 #include "wx/msw/wrapwin.h"
31 #include "wx/msw/wince/time.h"
33 #if defined(__VISUALC__) && (__VISUALC__ >= 1400)
35 // VC8 does provide the time functions but not the standard ones
38 time_t __cdecl
time(time_t *t
)
50 time_t __cdecl
mktime(struct tm
*t
)
52 return (time_t)_mktime64(t
);
57 /////////////////////////////////////////////////////////////////////////////////////////////
59 // strftime() - taken from OpenBSD //
61 /////////////////////////////////////////////////////////////////////////////////////////////
69 #define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
70 #define TYPE_SIGNED(type) (((type) -1) < 0)
72 #define INT_STRLEN_MAXIMUM(type) \
73 ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type))
75 #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
77 #define MONSPERYEAR 12
79 #define TM_YEAR_BASE 1900
80 #define HOURSPERDAY 24
81 #define DAYSPERNYEAR 365
82 #define DAYSPERLYEAR 366
84 static char wildabbr
[] = "WILDABBR";
92 #define Locale (&C_time_locale)
95 const char * mon
[MONSPERYEAR
];
96 const char * month
[MONSPERYEAR
];
97 const char * wday
[DAYSPERWEEK
];
98 const char * weekday
[DAYSPERWEEK
];
104 const char * date_fmt
;
107 static const struct lc_time_T C_time_locale
= {
109 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
110 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
112 "January", "February", "March", "April", "May", "June",
113 "July", "August", "September", "October", "November", "December"
115 "Sun", "Mon", "Tue", "Wed",
118 "Sunday", "Monday", "Tuesday", "Wednesday",
119 "Thursday", "Friday", "Saturday"
127 ** C99 requires this format.
128 ** Using just numbers (as here) makes Quakers happier;
129 ** it's also compatible with SVR4.
135 ** C99 requires this format.
136 ** Previously this code used "%D %X", but we now conform to C99.
138 ** "%a %b %d %H:%M:%S %Y"
139 ** is used by Solaris 2.3.
150 "%a %b %e %H:%M:%S %Z %Y"
155 _add(const char * str
, char * pt
, const char * const ptlim
)
157 while (pt
< ptlim
&& (*pt
= *str
++) != '\0')
164 _conv(const int n
, const char * const format
, char * const pt
, const char * const ptlim
)
166 char buf
[INT_STRLEN_MAXIMUM(int) + 1];
168 (void) _snprintf(buf
, sizeof buf
, format
, n
);
169 return _add(buf
, pt
, ptlim
);
174 _fmt(const char * format
, const struct tm
* const t
, char * pt
, const char * const ptlim
, int * warnp
)
176 for ( ; *format
; ++format
) {
177 if (*format
== '%') {
184 pt
= _add((t
->tm_wday
< 0 ||
185 t
->tm_wday
>= DAYSPERWEEK
) ?
186 "?" : Locale
->weekday
[t
->tm_wday
],
190 pt
= _add((t
->tm_wday
< 0 ||
191 t
->tm_wday
>= DAYSPERWEEK
) ?
192 "?" : Locale
->wday
[t
->tm_wday
],
196 pt
= _add((t
->tm_mon
< 0 ||
197 t
->tm_mon
>= MONSPERYEAR
) ?
198 "?" : Locale
->month
[t
->tm_mon
],
203 pt
= _add((t
->tm_mon
< 0 ||
204 t
->tm_mon
>= MONSPERYEAR
) ?
205 "?" : Locale
->mon
[t
->tm_mon
],
210 ** %C used to do a...
211 ** _fmt("%a %b %e %X %Y", t);
212 ** ...whereas now POSIX 1003.2 calls for
213 ** something completely different.
216 pt
= _conv((t
->tm_year
+ TM_YEAR_BASE
) / 100,
223 pt
= _fmt(Locale
->c_fmt
, t
, pt
, ptlim
, warnp
);
231 pt
= _fmt("%m/%d/%y", t
, pt
, ptlim
, warnp
);
234 pt
= _conv(t
->tm_mday
, "%02d", pt
, ptlim
);
239 ** C99 locale modifiers.
241 ** %Ec %EC %Ex %EX %Ey %EY
242 ** %Od %oe %OH %OI %Om %OM
243 ** %OS %Ou %OU %OV %Ow %OW %Oy
244 ** are supposed to provide alternate
249 pt
= _conv(t
->tm_mday
, "%2d", pt
, ptlim
);
252 pt
= _fmt("%Y-%m-%d", t
, pt
, ptlim
, warnp
);
255 pt
= _conv(t
->tm_hour
, "%02d", pt
, ptlim
);
258 pt
= _conv((t
->tm_hour
% 12) ?
259 (t
->tm_hour
% 12) : 12,
263 pt
= _conv(t
->tm_yday
+ 1, "%03d", pt
, ptlim
);
267 ** This used to be...
268 ** _conv(t->tm_hour % 12 ?
269 ** t->tm_hour % 12 : 12, 2, ' ');
270 ** ...and has been changed to the below to
271 ** match SunOS 4.1.1 and Arnold Robbins'
272 ** strftime version 3.0. That is, "%k" and
273 ** "%l" have been swapped.
276 pt
= _conv(t
->tm_hour
, "%2d", pt
, ptlim
);
281 ** After all this time, still unclaimed!
283 pt
= _add("kitchen sink", pt
, ptlim
);
285 #endif /* defined KITCHEN_SINK */
288 ** This used to be...
289 ** _conv(t->tm_hour, 2, ' ');
290 ** ...and has been changed to the below to
291 ** match SunOS 4.1.1 and Arnold Robbin's
292 ** strftime version 3.0. That is, "%k" and
293 ** "%l" have been swapped.
296 pt
= _conv((t
->tm_hour
% 12) ?
297 (t
->tm_hour
% 12) : 12,
301 pt
= _conv(t
->tm_min
, "%02d", pt
, ptlim
);
304 pt
= _conv(t
->tm_mon
+ 1, "%02d", pt
, ptlim
);
307 pt
= _add("\n", pt
, ptlim
);
310 pt
= _add((t
->tm_hour
>= (HOURSPERDAY
/ 2)) ?
316 pt
= _fmt("%H:%M", t
, pt
, ptlim
, warnp
);
319 pt
= _fmt("%I:%M:%S %p", t
, pt
, ptlim
, warnp
);
322 pt
= _conv(t
->tm_sec
, "%02d", pt
, ptlim
);
327 char buf
[INT_STRLEN_MAXIMUM(
333 if (TYPE_SIGNED(time_t))
334 (void) _snprintf(buf
, sizeof buf
,
336 else (void) _snprintf(buf
, sizeof buf
,
337 "%lu", (unsigned long) mkt
);
338 pt
= _add(buf
, pt
, ptlim
);
342 pt
= _fmt("%H:%M:%S", t
, pt
, ptlim
, warnp
);
345 pt
= _add("\t", pt
, ptlim
);
348 pt
= _conv((t
->tm_yday
+ DAYSPERWEEK
-
349 t
->tm_wday
) / DAYSPERWEEK
,
354 ** From Arnold Robbins' strftime version 3.0:
355 ** "ISO 8601: Weekday as a decimal number
359 pt
= _conv((t
->tm_wday
== 0) ?
360 DAYSPERWEEK
: t
->tm_wday
,
363 case 'V': /* ISO 8601 week number */
364 case 'G': /* ISO 8601 year (four digits) */
365 case 'g': /* ISO 8601 year (two digits) */
372 year
= t
->tm_year
+ TM_YEAR_BASE
;
384 ** What yday (-3 ... 3) does
385 ** the ISO year begin on?
387 bot
= ((yday
+ 11 - wday
) %
390 ** What yday does the NEXT
391 ** ISO year begin on?
404 w
= 1 + ((yday
- bot
) /
409 yday
+= isleap(year
) ?
414 pt
= _conv(w
, "%02d",
416 else if (*format
== 'g') {
418 pt
= _conv(year
% 100, "%02d",
420 } else pt
= _conv(year
, "%04d",
425 pt
= _fmt("%e-%b-%Y", t
, pt
, ptlim
, warnp
);
428 pt
= _conv((t
->tm_yday
+ DAYSPERWEEK
-
431 (DAYSPERWEEK
- 1))) / DAYSPERWEEK
,
435 pt
= _conv(t
->tm_wday
, "%d", pt
, ptlim
);
438 pt
= _fmt(Locale
->X_fmt
, t
, pt
, ptlim
, warnp
);
444 pt
= _fmt(Locale
->x_fmt
, t
, pt
, ptlim
, &warn2
);
453 pt
= _conv((t
->tm_year
+ TM_YEAR_BASE
) % 100,
457 pt
= _conv(t
->tm_year
+ TM_YEAR_BASE
, "%04d",
461 if (t
->tm_isdst
>= 0)
462 pt
= _add(tzname
[t
->tm_isdst
!= 0],
465 ** C99 says that %Z must be replaced by the
466 ** empty string if the time zone is not
472 int diff
= -timezone
;
479 pt
= _add(sign
, pt
, ptlim
);
481 pt
= _conv((diff
/60)*100 + diff%60
,
486 pt
= _fmt(Locale
->date_fmt
, t
, pt
, ptlim
,
502 strftime(char * const s
, const size_t maxsize
, const char *format
, const struct tm
* const t
)
510 p
= _fmt(((format
== NULL
) ? "%c" : format
), t
, s
, s
+ maxsize
, &warn
);
512 if (p
== s
+ maxsize
) {
514 s
[maxsize
- 1] = '\0';
524 /* Not needed in VS Studio 2005 */
526 size_t wcsftime(wchar_t *s
,
527 const size_t maxsize
,
528 const wchar_t *format
,
531 wxCharBuffer
sBuf(maxsize
/sizeof(wchar_t));
533 wxString
formatStr(format
);
534 wxCharBuffer
bufFormatStr(formatStr
.mb_str());
536 size_t sz
= strftime(sBuf
.data(), maxsize
/sizeof(wchar_t), bufFormatStr
, t
);
538 wxMB2WC(s
, sBuf
, maxsize
);
545 #define is_leap(y) (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
546 #define SECONDS_IN_ONE_MINUTE 60
547 #define DAYS_IN_ONE_YEAR 365
548 #define SECONDS_IN_ONE_MIN 60
549 #define SECONDS_IN_ONE_HOUR 3600
550 #define SECONDS_IN_ONE_DAY 86400
551 #define DEFAULT_TIMEZONE 28800
553 #define DO_LOCALTIME 1
556 long timezone
; // global variable
559 ////////////////////////////////////////////////////////////////////////
560 // Common code for localtime and gmtime (static)
561 ////////////////////////////////////////////////////////////////////////
563 static struct tm
* __cdecl
common_localtime(const time_t *t
, BOOL bLocal
)
568 SYSTEMTIME SystemTime
;
569 TIME_ZONE_INFORMATION pTz
;
570 static struct tm st_res
; // data holder
571 static struct tm
* res
= &st_res
; // data pointer
573 const unsigned short int __mon_yday
[2][13] =
576 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
578 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
582 ::GetLocalTime(&SystemTime
);
586 i64
= i64
* 10000000 + 116444736000000000;
588 ft
.dwLowDateTime
= i64
.GetLo();
589 ft
.dwHighDateTime
= i64
.GetHi();
591 ::FileTimeToSystemTime(&ft
, &SystemTime
);
594 ::GetTimeZoneInformation(&pTz
);
596 ///////////////////////////////////////////////
598 timezone
= pTz
.Bias
* SECONDS_IN_ONE_MINUTE
;
599 ///////////////////////////////////////////////
601 iLeap
= is_leap(SystemTime
.wYear
) ;
603 res
->tm_hour
= SystemTime
.wHour
;
604 res
->tm_min
= SystemTime
.wMinute
;
605 res
->tm_sec
= SystemTime
.wSecond
;
607 res
->tm_mday
= SystemTime
.wDay
;
608 res
->tm_mon
= SystemTime
.wMonth
- 1; // this the correct month but localtime returns month aligned to zero
609 res
->tm_year
= SystemTime
.wYear
; // this the correct year
610 res
->tm_year
= res
->tm_year
- 1900; // but localtime returns the value starting at the 1900
612 res
->tm_wday
= SystemTime
.wDayOfWeek
;
613 res
->tm_yday
= __mon_yday
[iLeap
][res
->tm_mon
] + SystemTime
.wDay
- 1; // localtime returns year-day aligned to zero
615 // if localtime behavior and daylight saving
616 if (bLocal
&& pTz
.DaylightBias
!= 0)
619 res
->tm_isdst
= 0; // without daylight saving or gmtime
627 ////////////////////////////////////////////////////////////////////////
628 // Receive the number of seconds elapsed since midnight(00:00:00)
629 // and convert a time value and corrects for the local time zone
630 ////////////////////////////////////////////////////////////////////////
631 struct tm
* __cdecl
localtime(const time_t * t
)
633 return common_localtime(t
, DO_LOCALTIME
) ;
636 ////////////////////////////////////////////////////////////////////////
637 // Receives the number of seconds elapsed since midnight(00:00:00)
638 // and converts a time value WITHOUT correcting for the local time zone
639 ////////////////////////////////////////////////////////////////////////
640 struct tm
* __cdecl
gmtime(const time_t *t
)
642 return common_localtime(t
, DO_GMTIME
) ;
647 ////////////////////////////////////////////////////////////////////////
648 // Common code for conversion of struct tm into time_t (static)
649 ////////////////////////////////////////////////////////////////////////
650 static time_t __cdecl
common_tm_to_time(int day
, int month
, int year
, int hour
, int minute
, int second
)
653 // Use mktime since it seems less broken
663 t
.tm_year
= year
- 1900;
667 static int mdays
[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 } ;
671 prog
+= mdays
[month
- 1] ;
672 if (month
== 2 && is_leap(year
))
676 // Calculate seconds in elapsed days
677 prog
= day
- 1 ; // align first day of the year to zero
678 prog
+= (DAYS_IN_ONE_YEAR
* (year
- 1970) + (year
- 1901) / 4 - 19) ;
679 prog
*= SECONDS_IN_ONE_DAY
;
681 // Add Calculated elapsed seconds in the current day
682 prog
+= (hour
* SECONDS_IN_ONE_HOUR
+ minute
*
683 SECONDS_IN_ONE_MIN
+ second
) ;
692 ////////////////////////////////////////////////////////////////////////
693 // Returns the number of seconds elapsed since
694 // midnight(00:00:00) of 1 January 1970
695 ////////////////////////////////////////////////////////////////////////
696 time_t __cdecl
time(time_t *t
)
702 SYSTEMTIME SystemTime
;
704 ::GetLocalTime(&SystemTime
) ;
705 prog
= common_tm_to_time(SystemTime
.wDay
, SystemTime
.wMonth
, SystemTime
.wYear
,
706 SystemTime
.wHour
, SystemTime
.wMinute
, SystemTime
.wSecond
) ;
713 ////////////////////////////////////////////////////////////////////////
714 // Converts the local time provided by struct tm
715 // into a time_t calendar value
716 // Implementation from OpenBSD
717 ////////////////////////////////////////////////////////////////////////
720 int month_to_day
[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
722 time_t mktime(struct tm
*t
)
728 year
= t
->tm_year
+ month
/ 12 + 1900;
735 result
= (year
- 1970) * 365 + (year
- 1969) / 4 + month_to_day
[month
];
736 result
= (year
- 1970) * 365 + month_to_day
[month
];
739 result
+= (year
- 1968) / 4;
740 result
-= (year
- 1900) / 100;
741 result
+= (year
- 1600) / 400;
742 result
+= t
->tm_mday
;
745 result
+= t
->tm_hour
;
754 time_t __cdecl
mktime(struct tm
*t
)
756 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
)) ;