1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/wince/time.cpp
3 // Purpose: Implements missing time functionality for WinCE
4 // Author: Marco Cavallini (MCK) - wx@koansoftware.com
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 /////////////////////////////////////////////////////////////////////////////////////////////
35 // strftime() - taken from OpenBSD //
37 /////////////////////////////////////////////////////////////////////////////////////////////
45 #define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
46 #define TYPE_SIGNED(type) (((type) -1) < 0)
48 #define INT_STRLEN_MAXIMUM(type) \
49 ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type))
51 #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
53 #define MONSPERYEAR 12
55 #define TM_YEAR_BASE 1900
56 #define HOURSPERDAY 24
57 #define DAYSPERNYEAR 365
58 #define DAYSPERLYEAR 366
60 static char wildabbr
[] = "WILDABBR";
68 #define Locale (&C_time_locale)
71 const char * mon
[MONSPERYEAR
];
72 const char * month
[MONSPERYEAR
];
73 const char * wday
[DAYSPERWEEK
];
74 const char * weekday
[DAYSPERWEEK
];
80 const char * date_fmt
;
83 static const struct lc_time_T C_time_locale
= {
85 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
86 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
88 "January", "February", "March", "April", "May", "June",
89 "July", "August", "September", "October", "November", "December"
91 "Sun", "Mon", "Tue", "Wed",
94 "Sunday", "Monday", "Tuesday", "Wednesday",
95 "Thursday", "Friday", "Saturday"
103 ** C99 requires this format.
104 ** Using just numbers (as here) makes Quakers happier;
105 ** it's also compatible with SVR4.
111 ** C99 requires this format.
112 ** Previously this code used "%D %X", but we now conform to C99.
114 ** "%a %b %d %H:%M:%S %Y"
115 ** is used by Solaris 2.3.
126 "%a %b %e %H:%M:%S %Z %Y"
131 _add(const char * str
, char * pt
, const char * const ptlim
)
133 while (pt
< ptlim
&& (*pt
= *str
++) != '\0')
140 _conv(const int n
, const char * const format
, char * const pt
, const char * const ptlim
)
142 char buf
[INT_STRLEN_MAXIMUM(int) + 1];
144 (void) _snprintf(buf
, sizeof buf
, format
, n
);
145 return _add(buf
, pt
, ptlim
);
150 _fmt(const char * format
, const struct tm
* const t
, char * pt
, const char * const ptlim
, int * warnp
)
152 for ( ; *format
; ++format
) {
153 if (*format
== '%') {
160 pt
= _add((t
->tm_wday
< 0 ||
161 t
->tm_wday
>= DAYSPERWEEK
) ?
162 "?" : Locale
->weekday
[t
->tm_wday
],
166 pt
= _add((t
->tm_wday
< 0 ||
167 t
->tm_wday
>= DAYSPERWEEK
) ?
168 "?" : Locale
->wday
[t
->tm_wday
],
172 pt
= _add((t
->tm_mon
< 0 ||
173 t
->tm_mon
>= MONSPERYEAR
) ?
174 "?" : Locale
->month
[t
->tm_mon
],
179 pt
= _add((t
->tm_mon
< 0 ||
180 t
->tm_mon
>= MONSPERYEAR
) ?
181 "?" : Locale
->mon
[t
->tm_mon
],
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.
192 pt
= _conv((t
->tm_year
+ TM_YEAR_BASE
) / 100,
199 pt
= _fmt(Locale
->c_fmt
, t
, pt
, ptlim
, warnp
);
207 pt
= _fmt("%m/%d/%y", t
, pt
, ptlim
, warnp
);
210 pt
= _conv(t
->tm_mday
, "%02d", pt
, ptlim
);
215 ** C99 locale modifiers.
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
225 pt
= _conv(t
->tm_mday
, "%2d", pt
, ptlim
);
228 pt
= _fmt("%Y-%m-%d", t
, pt
, ptlim
, warnp
);
231 pt
= _conv(t
->tm_hour
, "%02d", pt
, ptlim
);
234 pt
= _conv((t
->tm_hour
% 12) ?
235 (t
->tm_hour
% 12) : 12,
239 pt
= _conv(t
->tm_yday
+ 1, "%03d", pt
, ptlim
);
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.
252 pt
= _conv(t
->tm_hour
, "%2d", pt
, ptlim
);
257 ** After all this time, still unclaimed!
259 pt
= _add("kitchen sink", pt
, ptlim
);
261 #endif /* defined KITCHEN_SINK */
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.
272 pt
= _conv((t
->tm_hour
% 12) ?
273 (t
->tm_hour
% 12) : 12,
277 pt
= _conv(t
->tm_min
, "%02d", pt
, ptlim
);
280 pt
= _conv(t
->tm_mon
+ 1, "%02d", pt
, ptlim
);
283 pt
= _add("\n", pt
, ptlim
);
286 pt
= _add((t
->tm_hour
>= (HOURSPERDAY
/ 2)) ?
292 pt
= _fmt("%H:%M", t
, pt
, ptlim
, warnp
);
295 pt
= _fmt("%I:%M:%S %p", t
, pt
, ptlim
, warnp
);
298 pt
= _conv(t
->tm_sec
, "%02d", pt
, ptlim
);
303 char buf
[INT_STRLEN_MAXIMUM(
309 if (TYPE_SIGNED(time_t))
310 (void) _snprintf(buf
, sizeof buf
,
312 else (void) _snprintf(buf
, sizeof buf
,
313 "%lu", (unsigned long) mkt
);
314 pt
= _add(buf
, pt
, ptlim
);
318 pt
= _fmt("%H:%M:%S", t
, pt
, ptlim
, warnp
);
321 pt
= _add("\t", pt
, ptlim
);
324 pt
= _conv((t
->tm_yday
+ DAYSPERWEEK
-
325 t
->tm_wday
) / DAYSPERWEEK
,
330 ** From Arnold Robbins' strftime version 3.0:
331 ** "ISO 8601: Weekday as a decimal number
335 pt
= _conv((t
->tm_wday
== 0) ?
336 DAYSPERWEEK
: t
->tm_wday
,
339 case 'V': /* ISO 8601 week number */
340 case 'G': /* ISO 8601 year (four digits) */
341 case 'g': /* ISO 8601 year (two digits) */
348 year
= t
->tm_year
+ TM_YEAR_BASE
;
360 ** What yday (-3 ... 3) does
361 ** the ISO year begin on?
363 bot
= ((yday
+ 11 - wday
) %
366 ** What yday does the NEXT
367 ** ISO year begin on?
380 w
= 1 + ((yday
- bot
) /
385 yday
+= isleap(year
) ?
390 pt
= _conv(w
, "%02d",
392 else if (*format
== 'g') {
394 pt
= _conv(year
% 100, "%02d",
396 } else pt
= _conv(year
, "%04d",
401 pt
= _fmt("%e-%b-%Y", t
, pt
, ptlim
, warnp
);
404 pt
= _conv((t
->tm_yday
+ DAYSPERWEEK
-
407 (DAYSPERWEEK
- 1))) / DAYSPERWEEK
,
411 pt
= _conv(t
->tm_wday
, "%d", pt
, ptlim
);
414 pt
= _fmt(Locale
->X_fmt
, t
, pt
, ptlim
, warnp
);
420 pt
= _fmt(Locale
->x_fmt
, t
, pt
, ptlim
, &warn2
);
429 pt
= _conv((t
->tm_year
+ TM_YEAR_BASE
) % 100,
433 pt
= _conv(t
->tm_year
+ TM_YEAR_BASE
, "%04d",
437 if (t
->tm_isdst
>= 0)
438 pt
= _add(tzname
[t
->tm_isdst
!= 0],
441 ** C99 says that %Z must be replaced by the
442 ** empty string if the time zone is not
457 pt
= _add(sign
, pt
, ptlim
);
459 pt
= _conv((diff
/60)*100 + diff%60
,
464 pt
= _fmt(Locale
->date_fmt
, t
, pt
, ptlim
,
480 strftime(char * const s
, const size_t maxsize
, const char *format
, const struct tm
* const t
)
488 p
= _fmt(((format
== NULL
) ? "%c" : format
), t
, s
, s
+ maxsize
, &warn
);
490 if (p
== s
+ maxsize
) {
492 s
[maxsize
- 1] = '\0';
502 size_t wcsftime(wchar_t* const s
, const size_t maxsize
, const wchar_t *format
, const struct tm
* const t
)
507 wxString
formatStr(format
);
508 wxCharBuffer
bufFormatStr(formatStr
.mb_str());
510 size_t sz
= strftime(sBuf
, maxsize
, bufFormatStr
, t
);
512 wxMB2WC(s
, sBuf
, strlen(sBuf
));
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
527 #define DO_LOCALTIME 1
530 long timezone
; // global variable
533 ////////////////////////////////////////////////////////////////////////
534 // Common code for localtime and gmtime (static)
535 ////////////////////////////////////////////////////////////////////////
537 static struct tm
* __cdecl
common_localtime(const time_t *t
, BOOL bLocal
)
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
547 const unsigned short int __mon_yday
[2][13] =
550 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
552 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
556 ::GetLocalTime(&SystemTime
);
560 i64
= i64
* 10000000 + 116444736000000000;
562 ft
.dwLowDateTime
= i64
.GetLo();
563 ft
.dwHighDateTime
= i64
.GetHi();
565 ::FileTimeToSystemTime(&ft
, &SystemTime
);
568 ::GetTimeZoneInformation(&pTz
);
570 ///////////////////////////////////////////////
572 timezone
= pTz
.Bias
* SECONDS_IN_ONE_MINUTE
;
573 ///////////////////////////////////////////////
575 iLeap
= is_leap(SystemTime
.wYear
) ;
577 res
->tm_hour
= SystemTime
.wHour
;
578 res
->tm_min
= SystemTime
.wMinute
;
579 res
->tm_sec
= SystemTime
.wSecond
;
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
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
589 // if localtime behavior and daylight saving
590 if (bLocal
&& pTz
.DaylightBias
!= 0)
593 res
->tm_isdst
= 0; // without daylight saving or gmtime
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
)
607 return common_localtime(t
, DO_LOCALTIME
) ;
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
)
616 return common_localtime(t
, DO_GMTIME
) ;
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
)
627 // Use mktime since it seems less broken
637 t
.tm_year
= year
- 1900;
641 static int mdays
[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 } ;
645 prog
+= mdays
[month
- 1] ;
646 if (month
== 2 && is_leap(year
))
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
;
655 // Add Calculated elapsed seconds in the current day
656 prog
+= (hour
* SECONDS_IN_ONE_HOUR
+ minute
*
657 SECONDS_IN_ONE_MIN
+ second
) ;
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
)
676 SYSTEMTIME SystemTime
;
678 ::GetLocalTime(&SystemTime
) ;
679 prog
= common_tm_to_time(SystemTime
.wDay
, SystemTime
.wMonth
, SystemTime
.wYear
,
680 SystemTime
.wHour
, SystemTime
.wMinute
, SystemTime
.wSecond
) ;
687 ////////////////////////////////////////////////////////////////////////
688 // Converts the local time provided by struct tm
689 // into a time_t calendar value
690 // Implementation from OpenBSD
691 ////////////////////////////////////////////////////////////////////////
694 int month_to_day
[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
696 time_t mktime(struct tm
*t
)
702 year
= t
->tm_year
+ month
/ 12 + 1900;
709 result
= (year
- 1970) * 365 + (year
- 1969) / 4 + month_to_day
[month
];
710 result
= (year
- 1970) * 365 + month_to_day
[month
];
713 result
+= (year
- 1968) / 4;
714 result
-= (year
- 1900) / 100;
715 result
+= (year
- 1600) / 400;
716 result
+= t
->tm_mday
;
719 result
+= t
->tm_hour
;
728 time_t __cdecl
mktime(struct tm
*t
)
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
)) ;