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
)) ;