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 
 458                                 pt 
= _add(sign
, pt
, ptlim
); 
 460                                 pt 
= _conv((diff
/60)*100 + diff%60
, 
 465                                 pt 
= _fmt(Locale
->date_fmt
, t
, pt
, ptlim
, 
 481 strftime(char * const s
, const size_t maxsize
, const char *format
, const struct tm 
* const t
) 
 489         p 
= _fmt(((format 
== NULL
) ? "%c" : format
), t
, s
, s 
+ maxsize
, &warn
); 
 491         if (p 
== s 
+ maxsize
) { 
 493                         s
[maxsize 
- 1] = '\0'; 
 503 size_t wcsftime(wchar_t *s
, 
 504                 const size_t maxsize
, 
 505                 const wchar_t *format
, 
 508     wxCharBuffer 
sBuf(maxsize
/sizeof(wchar_t)); 
 510     wxString 
formatStr(format
); 
 511     wxCharBuffer 
bufFormatStr(formatStr
.mb_str()); 
 513     size_t sz 
= strftime(sBuf
.data(), maxsize
/sizeof(wchar_t), bufFormatStr
, t
); 
 515     wxMB2WC(s
, sBuf
, maxsize
); 
 522 #define is_leap(y)   (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) 
 523 #define SECONDS_IN_ONE_MINUTE      60 
 524 #define DAYS_IN_ONE_YEAR          365 
 525 #define SECONDS_IN_ONE_MIN         60 
 526 #define SECONDS_IN_ONE_HOUR      3600 
 527 #define SECONDS_IN_ONE_DAY      86400 
 528 #define DEFAULT_TIMEZONE        28800 
 530 #define DO_LOCALTIME                1 
 533 long timezone 
; // global variable 
 536 //////////////////////////////////////////////////////////////////////// 
 537 // Common code for localtime and gmtime (static) 
 538 //////////////////////////////////////////////////////////////////////// 
 540 static struct tm 
* __cdecl 
common_localtime(const time_t *t
, BOOL bLocal
) 
 545     SYSTEMTIME SystemTime
; 
 546     TIME_ZONE_INFORMATION pTz
; 
 547     static struct tm st_res 
;             // data holder 
 548     static struct tm 
* res 
= &st_res 
;    // data pointer 
 550     const unsigned short int __mon_yday
[2][13] = 
 553         { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, 
 555         { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } 
 559         ::GetLocalTime(&SystemTime
); 
 563         i64 
= i64 
* 10000000 + 116444736000000000; 
 565         ft
.dwLowDateTime  
= i64
.GetLo(); 
 566         ft
.dwHighDateTime 
= i64
.GetHi(); 
 568         ::FileTimeToSystemTime(&ft
, &SystemTime
); 
 571     ::GetTimeZoneInformation(&pTz
); 
 573     /////////////////////////////////////////////// 
 575     timezone 
= pTz
.Bias 
* SECONDS_IN_ONE_MINUTE 
; 
 576     /////////////////////////////////////////////// 
 578     iLeap 
= is_leap(SystemTime
.wYear
) ; 
 580     res
->tm_hour 
= SystemTime
.wHour
; 
 581     res
->tm_min  
= SystemTime
.wMinute
; 
 582     res
->tm_sec  
= SystemTime
.wSecond
; 
 584     res
->tm_mday 
= SystemTime
.wDay
; 
 585     res
->tm_mon 
= SystemTime
.wMonth 
- 1; // this the correct month but localtime returns month aligned to zero 
 586     res
->tm_year 
= SystemTime
.wYear
;     // this the correct year 
 587     res
->tm_year 
= res
->tm_year 
- 1900;  // but localtime returns the value starting at the 1900 
 589     res
->tm_wday 
= SystemTime
.wDayOfWeek
; 
 590     res
->tm_yday 
= __mon_yday
[iLeap
][res
->tm_mon
] + SystemTime
.wDay 
- 1; // localtime returns year-day aligned to zero 
 592     // if localtime behavior and daylight saving 
 593     if (bLocal 
&& pTz
.DaylightBias 
!= 0) 
 596         res
->tm_isdst 
= 0; // without daylight saving or gmtime 
 604 //////////////////////////////////////////////////////////////////////// 
 605 // Receive the number of seconds elapsed since midnight(00:00:00) 
 606 // and convert a time value and corrects for the local time zone 
 607 //////////////////////////////////////////////////////////////////////// 
 608 struct tm 
* __cdecl 
localtime(const time_t * t
) 
 610     return common_localtime(t
, DO_LOCALTIME
) ; 
 613 //////////////////////////////////////////////////////////////////////// 
 614 // Receives the number of seconds elapsed since midnight(00:00:00) 
 615 // and converts a time value WITHOUT correcting for the local time zone 
 616 //////////////////////////////////////////////////////////////////////// 
 617 struct tm 
* __cdecl 
gmtime(const time_t *t
) 
 619     return common_localtime(t
, DO_GMTIME
) ; 
 624 //////////////////////////////////////////////////////////////////////// 
 625 // Common code for conversion of struct tm into time_t   (static) 
 626 //////////////////////////////////////////////////////////////////////// 
 627 static time_t __cdecl 
common_tm_to_time(int day
, int month
, int year
, int hour
, int minute
, int second
) 
 630     // Use mktime since it seems less broken 
 640     t
.tm_year 
= year 
- 1900; 
 644     static int mdays
[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 } ; 
 648         prog 
+= mdays
[month 
- 1] ; 
 649         if (month 
== 2 && is_leap(year
)) 
 653     // Calculate seconds in elapsed days 
 654     prog 
= day 
- 1 ;        // align first day of the year to zero 
 655     prog 
+= (DAYS_IN_ONE_YEAR 
* (year 
- 1970) + (year 
- 1901) / 4 - 19) ; 
 656     prog 
*= SECONDS_IN_ONE_DAY 
; 
 658     // Add Calculated elapsed seconds in the current day 
 659     prog 
+= (hour 
* SECONDS_IN_ONE_HOUR 
+ minute 
* 
 660                                SECONDS_IN_ONE_MIN 
+ second
) ; 
 669 //////////////////////////////////////////////////////////////////////// 
 670 // Returns the number of seconds elapsed since 
 671 // midnight(00:00:00) of 1 January 1970 
 672 //////////////////////////////////////////////////////////////////////// 
 673 time_t __cdecl 
time(time_t *t
) 
 679         SYSTEMTIME SystemTime
; 
 681         ::GetLocalTime(&SystemTime
) ; 
 682         prog 
= common_tm_to_time(SystemTime
.wDay
, SystemTime
.wMonth
, SystemTime
.wYear
, 
 683                                  SystemTime
.wHour
, SystemTime
.wMinute
, SystemTime
.wSecond
) ; 
 690 //////////////////////////////////////////////////////////////////////// 
 691 // Converts the local time provided by struct tm 
 692 // into a time_t calendar value 
 693 // Implementation from OpenBSD 
 694 //////////////////////////////////////////////////////////////////////// 
 697 int month_to_day
[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; 
 699 time_t mktime(struct tm 
*t
) 
 705         year 
= t
->tm_year 
+ month 
/ 12 + 1900; 
 712         result 
= (year 
- 1970) * 365 + (year 
- 1969) / 4 + month_to_day
[month
]; 
 713         result 
= (year 
- 1970) * 365 + month_to_day
[month
]; 
 716         result 
+= (year 
- 1968) / 4; 
 717         result 
-= (year 
- 1900) / 100; 
 718         result 
+= (year 
- 1600) / 400; 
 719         result 
+= t
->tm_mday
; 
 722         result 
+= t
->tm_hour
; 
 731 time_t __cdecl 
mktime(struct tm 
*t
) 
 733     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
)) ;