1 /////////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     implementation of time/date related classes 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 
   9 //              parts of code taken from sndcal library by Scott E. Lee: 
  11 //               Copyright 1993-1995, Scott E. Lee, all rights reserved. 
  12 //               Permission granted to use, copy, modify, distribute and sell 
  13 //               so long as the above copyright and this permission statement 
  14 //               are retained in all copies. 
  16 // Licence:     wxWindows licence 
  17 /////////////////////////////////////////////////////////////////////////////// 
  19 // TODO: for $DEITY sake, someone please fix the #ifdef __WXWINCE__ everywhere, 
  20 //       the proper way to do it is to implement (subset of) wxStrftime() for 
  21 //       CE instead of this horror!! 
  24  * Implementation notes: 
  26  * 1. the time is stored as a 64bit integer containing the signed number of 
  27  *    milliseconds since Jan 1. 1970 (the Unix Epoch) - so it is always 
  30  * 2. the range is thus something about 580 million years, but due to current 
  31  *    algorithms limitations, only dates from Nov 24, 4714BC are handled 
  33  * 3. standard ANSI C functions are used to do time calculations whenever 
  34  *    possible, i.e. when the date is in the range Jan 1, 1970 to 2038 
  36  * 4. otherwise, the calculations are done by converting the date to/from JDN 
  37  *    first (the range limitation mentioned above comes from here: the 
  38  *    algorithm used by Scott E. Lee's code only works for positive JDNs, more 
  41  * 5. the object constructed for the given DD-MM-YYYY HH:MM:SS corresponds to 
  42  *    this moment in local time and may be converted to the object 
  43  *    corresponding to the same date/time in another time zone by using 
  46  * 6. the conversions to the current (or any other) timezone are done when the 
  47  *    internal time representation is converted to the broken-down one in 
  51 // ============================================================================ 
  53 // ============================================================================ 
  55 // ---------------------------------------------------------------------------- 
  57 // ---------------------------------------------------------------------------- 
  59 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  60     #pragma implementation "datetime.h" 
  63 // For compilers that support precompilation, includes "wx.h". 
  64 #include "wx/wxprec.h" 
  70 #if !defined(wxUSE_DATETIME) || wxUSE_DATETIME 
  73     #include "wx/string.h" 
  78 #include "wx/thread.h" 
  79 #include "wx/tokenzr.h" 
  80 #include "wx/module.h" 
  85     #include "wx/msw/wrapwin.h" 
  90 #include "wx/datetime.h" 
  91 #include "wx/stopwatch.h"           // for wxGetLocalTimeMillis() 
  93 const long wxDateTime::TIME_T_FACTOR 
= 1000l; 
  95 #if wxUSE_EXTENDED_RTTI 
  97 template<> void wxStringReadValue(const wxString 
&s 
, wxDateTime 
&data 
) 
  99     data
.ParseFormat(s
,wxT("%Y-%m-%d %H:%M:%S")) ; 
 102 template<> void wxStringWriteValue(wxString 
&s 
, const wxDateTime 
&data 
) 
 104     s 
= data
.Format(wxT("%Y-%m-%d %H:%M:%S")) ; 
 107 wxCUSTOM_TYPE_INFO(wxDateTime
, wxToStringConverter
<wxDateTime
> , wxFromStringConverter
<wxDateTime
>) 
 112 // ---------------------------------------------------------------------------- 
 113 // conditional compilation 
 114 // ---------------------------------------------------------------------------- 
 116 #if defined(HAVE_STRPTIME) && defined(__GLIBC__) && \ 
 117         ((__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0)) 
 118     // glibc 2.0.7 strptime() is broken - the following snippet causes it to 
 119     // crash (instead of just failing): 
 121     //      strncpy(buf, "Tue Dec 21 20:25:40 1999", 128); 
 122     //      strptime(buf, "%x", &tm); 
 126 #endif // broken strptime() 
 128 #if defined(__MWERKS__) && wxUSE_UNICODE 
 132 #if !defined(WX_TIMEZONE) && !defined(WX_GMTOFF_IN_TM) 
 133     #if defined(__WXPALMOS__) 
 134         #define WX_GMTOFF_IN_TM 
 135     #elif defined(__BORLANDC__) || defined(__MINGW32__) || defined(__VISAGECPP__) 
 136         #define WX_TIMEZONE _timezone 
 137     #elif defined(__MWERKS__) 
 138         long wxmw_timezone 
= 28800; 
 139         #define WX_TIMEZONE wxmw_timezone 
 140     #elif defined(__DJGPP__) || defined(__WINE__) 
 141         #include <sys/timeb.h> 
 143         static long wxGetTimeZone() 
 145             static long timezone 
= MAXLONG
; // invalid timezone 
 146             if (timezone 
== MAXLONG
) 
 150                 timezone 
= tb
.timezone
; 
 154         #define WX_TIMEZONE wxGetTimeZone() 
 155     #elif defined(__DARWIN__) 
 156         #define WX_GMTOFF_IN_TM 
 157     #else // unknown platform - try timezone 
 158         #define WX_TIMEZONE timezone 
 160 #endif // !WX_TIMEZONE && !WX_GMTOFF_IN_TM 
 162 // ---------------------------------------------------------------------------- 
 164 // ---------------------------------------------------------------------------- 
 166 // debugging helper: just a convenient replacement of wxCHECK() 
 167 #define wxDATETIME_CHECK(expr, msg)     \ 
 171             *this = wxInvalidDateTime;  \ 
 175 // ---------------------------------------------------------------------------- 
 177 // ---------------------------------------------------------------------------- 
 179 class wxDateTimeHolidaysModule 
: public wxModule
 
 182     virtual bool OnInit() 
 184         wxDateTimeHolidayAuthority::AddAuthority(new wxDateTimeWorkDays
); 
 189     virtual void OnExit() 
 191         wxDateTimeHolidayAuthority::ClearAllAuthorities(); 
 192         wxDateTimeHolidayAuthority::ms_authorities
.clear(); 
 196     DECLARE_DYNAMIC_CLASS(wxDateTimeHolidaysModule
) 
 199 IMPLEMENT_DYNAMIC_CLASS(wxDateTimeHolidaysModule
, wxModule
) 
 201 // ---------------------------------------------------------------------------- 
 203 // ---------------------------------------------------------------------------- 
 206 static const int MONTHS_IN_YEAR 
= 12; 
 208 static const int SEC_PER_MIN 
= 60; 
 210 static const int MIN_PER_HOUR 
= 60; 
 212 static const int HOURS_PER_DAY 
= 24; 
 214 static const long SECONDS_PER_DAY 
= 86400l; 
 216 static const int DAYS_PER_WEEK 
= 7; 
 218 static const long MILLISECONDS_PER_DAY 
= 86400000l; 
 220 // this is the integral part of JDN of the midnight of Jan 1, 1970 
 221 // (i.e. JDN(Jan 1, 1970) = 2440587.5) 
 222 static const long EPOCH_JDN 
= 2440587l; 
 224 // the date of JDN -0.5 (as we don't work with fractional parts, this is the 
 225 // reference date for us) is Nov 24, 4714BC 
 226 static const int JDN_0_YEAR 
= -4713; 
 227 static const int JDN_0_MONTH 
= wxDateTime::Nov
; 
 228 static const int JDN_0_DAY 
= 24; 
 230 // the constants used for JDN calculations 
 231 static const long JDN_OFFSET         
= 32046l; 
 232 static const long DAYS_PER_5_MONTHS  
= 153l; 
 233 static const long DAYS_PER_4_YEARS   
= 1461l; 
 234 static const long DAYS_PER_400_YEARS 
= 146097l; 
 236 // this array contains the cumulated number of days in all previous months for 
 237 // normal and leap years 
 238 static const wxDateTime::wxDateTime_t gs_cumulatedDays
[2][MONTHS_IN_YEAR
] = 
 240     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }, 
 241     { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 } 
 244 // ---------------------------------------------------------------------------- 
 246 // ---------------------------------------------------------------------------- 
 248 const wxChar 
* wxDefaultDateTimeFormat 
= wxT("%c"); 
 249 const wxChar 
* wxDefaultTimeSpanFormat 
= wxT("%H:%M:%S"); 
 251 // in the fine tradition of ANSI C we use our equivalent of (time_t)-1 to 
 252 // indicate an invalid wxDateTime object 
 253 const wxDateTime wxDefaultDateTime
; 
 255 wxDateTime::Country 
wxDateTime::ms_country 
= wxDateTime::Country_Unknown
; 
 257 // ---------------------------------------------------------------------------- 
 259 // ---------------------------------------------------------------------------- 
 261 // debugger helper: shows what the date really is 
 263 extern const wxChar 
*wxDumpDate(const wxDateTime
* dt
) 
 265     static wxChar buf
[128]; 
 267     wxStrcpy(buf
, dt
->Format(_T("%Y-%m-%d (%a) %H:%M:%S"))); 
 273 // get the number of days in the given month of the given year 
 275 wxDateTime::wxDateTime_t 
GetNumOfDaysInMonth(int year
, wxDateTime::Month month
) 
 277     // the number of days in month in Julian/Gregorian calendar: the first line 
 278     // is for normal years, the second one is for the leap ones 
 279     static wxDateTime::wxDateTime_t daysInMonth
[2][MONTHS_IN_YEAR
] = 
 281         { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 
 282         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 
 285     return daysInMonth
[wxDateTime::IsLeapYear(year
)][month
]; 
 288 // returns the time zone in the C sense, i.e. the difference UTC - local 
 290 static int GetTimeZone() 
 292 #ifdef WX_GMTOFF_IN_TM 
 293     // set to true when the timezone is set 
 294     static bool s_timezoneSet 
= false; 
 295     static long gmtoffset 
= LONG_MAX
; // invalid timezone 
 297     // ensure that the timezone variable is set by calling localtime 
 298     if ( !s_timezoneSet 
) 
 300         // just call localtime() instead of figuring out whether this system 
 301         // supports tzset(), _tzset() or something else 
 306         s_timezoneSet 
= true; 
 308         // note that GMT offset is the opposite of time zone and so to return 
 309         // consistent results in both WX_GMTOFF_IN_TM and !WX_GMTOFF_IN_TM 
 310         // cases we have to negate it 
 311         gmtoffset 
= -tm
->tm_gmtoff
; 
 314     return (int)gmtoffset
; 
 315 #else // !WX_GMTOFF_IN_TM 
 316     return (int)WX_TIMEZONE
; 
 317 #endif // WX_GMTOFF_IN_TM/!WX_GMTOFF_IN_TM 
 320 // return the integral part of the JDN for the midnight of the given date (to 
 321 // get the real JDN you need to add 0.5, this is, in fact, JDN of the 
 322 // noon of the previous day) 
 323 static long GetTruncatedJDN(wxDateTime::wxDateTime_t day
, 
 324                             wxDateTime::Month mon
, 
 327     // CREDIT: code below is by Scott E. Lee (but bugs are mine) 
 329     // check the date validity 
 331       (year 
> JDN_0_YEAR
) || 
 332       ((year 
== JDN_0_YEAR
) && (mon 
> JDN_0_MONTH
)) || 
 333       ((year 
== JDN_0_YEAR
) && (mon 
== JDN_0_MONTH
) && (day 
>= JDN_0_DAY
)), 
 334       _T("date out of range - can't convert to JDN") 
 337     // make the year positive to avoid problems with negative numbers division 
 340     // months are counted from March here 
 342     if ( mon 
>= wxDateTime::Mar 
) 
 352     // now we can simply add all the contributions together 
 353     return ((year 
/ 100) * DAYS_PER_400_YEARS
) / 4 
 354             + ((year 
% 100) * DAYS_PER_4_YEARS
) / 4 
 355             + (month 
* DAYS_PER_5_MONTHS 
+ 2) / 5 
 360 // this function is a wrapper around strftime(3) adding error checking 
 361 static wxString 
CallStrftime(const wxChar 
*format
, const tm
* tm
) 
 364         if ( !wxStrftime(buf
, WXSIZEOF(buf
), format
, tm
) ) 
 366         // buffer is too small? 
 367         wxFAIL_MSG(_T("strftime() failed")); 
 370     return wxString(buf
); 
 375 // glibc2 doesn't define this in the headers unless _XOPEN_SOURCE is defined 
 376 // which, unfortunately, wreaks havoc elsewhere 
 377 #if defined(__GLIBC__) && (__GLIBC__ == 2) 
 378     extern "C" char *strptime(const char *, const char *, struct tm 
*); 
 381 // Unicode-friendly strptime() wrapper 
 382 static const wxChar 
* 
 383 CallStrptime(const wxChar 
*input
, const char *fmt
, tm 
*tm
) 
 385     // the problem here is that strptime() returns pointer into the string we 
 386     // passed to it while we're really interested in the pointer into the 
 387     // original, Unicode, string so we try to transform the pointer back 
 389     wxCharBuffer 
inputMB(wxConvertWX2MB(input
)); 
 391     const char * const inputMB 
= input
; 
 392 #endif // Unicode/Ascii 
 394     const char *result 
= strptime(inputMB
, fmt
, tm
); 
 399     // FIXME: this is wrong in presence of surrogates &c 
 400     return input 
+ (result 
- inputMB
.data()); 
 403 #endif // Unicode/Ascii 
 406 #endif // HAVE_STRPTIME 
 408 // if year and/or month have invalid values, replace them with the current ones 
 409 static void ReplaceDefaultYearMonthWithCurrent(int *year
, 
 410                                                wxDateTime::Month 
*month
) 
 412     struct tm 
*tmNow 
= NULL
; 
 414     if ( *year 
== wxDateTime::Inv_Year 
) 
 416         tmNow 
= wxDateTime::GetTmNow(); 
 418         *year 
= 1900 + tmNow
->tm_year
; 
 421     if ( *month 
== wxDateTime::Inv_Month 
) 
 424             tmNow 
= wxDateTime::GetTmNow(); 
 426         *month 
= (wxDateTime::Month
)tmNow
->tm_mon
; 
 430 // fll the struct tm with default values 
 431 static void InitTm(struct tm
& tm
) 
 433     // struct tm may have etxra fields (undocumented and with unportable 
 434     // names) which, nevertheless, must be set to 0 
 435     memset(&tm
, 0, sizeof(struct tm
)); 
 437     tm
.tm_mday 
= 1;   // mday 0 is invalid 
 438     tm
.tm_year 
= 76;  // any valid year 
 439     tm
.tm_isdst 
= -1; // auto determine 
 445 // return the month if the string is a month name or Inv_Month otherwise 
 446 static wxDateTime::Month 
GetMonthFromName(const wxString
& name
, int flags
) 
 448     wxDateTime::Month mon
; 
 449     for ( mon 
= wxDateTime::Jan
; mon 
< wxDateTime::Inv_Month
; wxNextMonth(mon
) ) 
 451         // case-insensitive comparison either one of or with both abbreviated 
 453         if ( flags 
& wxDateTime::Name_Full 
) 
 455             if ( name
.CmpNoCase(wxDateTime:: 
 456                         GetMonthName(mon
, wxDateTime::Name_Full
)) == 0 ) 
 462         if ( flags 
& wxDateTime::Name_Abbr 
) 
 464             if ( name
.CmpNoCase(wxDateTime:: 
 465                         GetMonthName(mon
, wxDateTime::Name_Abbr
)) == 0 ) 
 475 // return the weekday if the string is a weekday name or Inv_WeekDay otherwise 
 476 static wxDateTime::WeekDay 
GetWeekDayFromName(const wxString
& name
, int flags
) 
 478     wxDateTime::WeekDay wd
; 
 479     for ( wd 
= wxDateTime::Sun
; wd 
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) ) 
 481         // case-insensitive comparison either one of or with both abbreviated 
 483         if ( flags 
& wxDateTime::Name_Full 
) 
 485             if ( name
.CmpNoCase(wxDateTime:: 
 486                         GetWeekDayName(wd
, wxDateTime::Name_Full
)) == 0 ) 
 492         if ( flags 
& wxDateTime::Name_Abbr 
) 
 494             if ( name
.CmpNoCase(wxDateTime:: 
 495                         GetWeekDayName(wd
, wxDateTime::Name_Abbr
)) == 0 ) 
 505 // scans all digits (but no more than len) and returns the resulting number 
 506 static bool GetNumericToken(size_t len
, const wxChar
*& p
, unsigned long *number
) 
 510     while ( wxIsdigit(*p
) ) 
 514         if ( len 
&& ++n 
> len 
) 
 518     return !s
.empty() && s
.ToULong(number
); 
 521 // scans all alphabetic characters and returns the resulting string 
 522 static wxString 
GetAlphaToken(const wxChar
*& p
) 
 525     while ( wxIsalpha(*p
) ) 
 533 // ============================================================================ 
 534 // implementation of wxDateTime 
 535 // ============================================================================ 
 537 // ---------------------------------------------------------------------------- 
 539 // ---------------------------------------------------------------------------- 
 543     year 
= (wxDateTime_t
)wxDateTime::Inv_Year
; 
 544     mon 
= wxDateTime::Inv_Month
; 
 546     hour 
= min 
= sec 
= msec 
= 0; 
 547     wday 
= wxDateTime::Inv_WeekDay
; 
 550 wxDateTime::Tm::Tm(const struct tm
& tm
, const TimeZone
& tz
) 
 554     sec 
= (wxDateTime::wxDateTime_t
)tm
.tm_sec
; 
 555     min 
= (wxDateTime::wxDateTime_t
)tm
.tm_min
; 
 556     hour 
= (wxDateTime::wxDateTime_t
)tm
.tm_hour
; 
 557     mday 
= (wxDateTime::wxDateTime_t
)tm
.tm_mday
; 
 558     mon 
= (wxDateTime::Month
)tm
.tm_mon
; 
 559     year 
= 1900 + tm
.tm_year
; 
 560     wday 
= (wxDateTime::wxDateTime_t
)tm
.tm_wday
; 
 561     yday 
= (wxDateTime::wxDateTime_t
)tm
.tm_yday
; 
 564 bool wxDateTime::Tm::IsValid() const 
 566     // we allow for the leap seconds, although we don't use them (yet) 
 567     return (year 
!= wxDateTime::Inv_Year
) && (mon 
!= wxDateTime::Inv_Month
) && 
 568            (mday 
<= GetNumOfDaysInMonth(year
, mon
)) && 
 569            (hour 
< 24) && (min 
< 60) && (sec 
< 62) && (msec 
< 1000); 
 572 void wxDateTime::Tm::ComputeWeekDay() 
 574     // compute the week day from day/month/year: we use the dumbest algorithm 
 575     // possible: just compute our JDN and then use the (simple to derive) 
 576     // formula: weekday = (JDN + 1.5) % 7 
 577     wday 
= (wxDateTime::wxDateTime_t
)((wxDateTime::WeekDay
)(GetTruncatedJDN(mday
, mon
, year
) + 2) % 7); 
 580 void wxDateTime::Tm::AddMonths(int monDiff
) 
 582     // normalize the months field 
 583     while ( monDiff 
< -mon 
) 
 587         monDiff 
+= MONTHS_IN_YEAR
; 
 590     while ( monDiff 
+ mon 
>= MONTHS_IN_YEAR 
) 
 594         monDiff 
-= MONTHS_IN_YEAR
; 
 597     mon 
= (wxDateTime::Month
)(mon 
+ monDiff
); 
 599     wxASSERT_MSG( mon 
>= 0 && mon 
< MONTHS_IN_YEAR
, _T("logic error") ); 
 601     // NB: we don't check here that the resulting date is valid, this function 
 602     //     is private and the caller must check it if needed 
 605 void wxDateTime::Tm::AddDays(int dayDiff
) 
 607     // normalize the days field 
 608     while ( dayDiff 
+ mday 
< 1 ) 
 612         dayDiff 
+= GetNumOfDaysInMonth(year
, mon
); 
 615     mday 
= (wxDateTime::wxDateTime_t
)( mday 
+ dayDiff 
); 
 616     while ( mday 
> GetNumOfDaysInMonth(year
, mon
) ) 
 618         mday 
-= GetNumOfDaysInMonth(year
, mon
); 
 623     wxASSERT_MSG( mday 
> 0 && mday 
<= GetNumOfDaysInMonth(year
, mon
), 
 627 // ---------------------------------------------------------------------------- 
 629 // ---------------------------------------------------------------------------- 
 631 wxDateTime::TimeZone::TimeZone(wxDateTime::TZ tz
) 
 635         case wxDateTime::Local
: 
 636             // get the offset from C RTL: it returns the difference GMT-local 
 637             // while we want to have the offset _from_ GMT, hence the '-' 
 638             m_offset 
= -GetTimeZone(); 
 641         case wxDateTime::GMT_12
: 
 642         case wxDateTime::GMT_11
: 
 643         case wxDateTime::GMT_10
: 
 644         case wxDateTime::GMT_9
: 
 645         case wxDateTime::GMT_8
: 
 646         case wxDateTime::GMT_7
: 
 647         case wxDateTime::GMT_6
: 
 648         case wxDateTime::GMT_5
: 
 649         case wxDateTime::GMT_4
: 
 650         case wxDateTime::GMT_3
: 
 651         case wxDateTime::GMT_2
: 
 652         case wxDateTime::GMT_1
: 
 653             m_offset 
= -3600*(wxDateTime::GMT0 
- tz
); 
 656         case wxDateTime::GMT0
: 
 657         case wxDateTime::GMT1
: 
 658         case wxDateTime::GMT2
: 
 659         case wxDateTime::GMT3
: 
 660         case wxDateTime::GMT4
: 
 661         case wxDateTime::GMT5
: 
 662         case wxDateTime::GMT6
: 
 663         case wxDateTime::GMT7
: 
 664         case wxDateTime::GMT8
: 
 665         case wxDateTime::GMT9
: 
 666         case wxDateTime::GMT10
: 
 667         case wxDateTime::GMT11
: 
 668         case wxDateTime::GMT12
: 
 669             m_offset 
= 3600*(tz 
- wxDateTime::GMT0
); 
 672         case wxDateTime::A_CST
: 
 673             // Central Standard Time in use in Australia = UTC + 9.5 
 674             m_offset 
= 60l*(9*60 + 30); 
 678             wxFAIL_MSG( _T("unknown time zone") ); 
 682 // ---------------------------------------------------------------------------- 
 684 // ---------------------------------------------------------------------------- 
 687 bool wxDateTime::IsLeapYear(int year
, wxDateTime::Calendar cal
) 
 689     if ( year 
== Inv_Year 
) 
 690         year 
= GetCurrentYear(); 
 692     if ( cal 
== Gregorian 
) 
 694         // in Gregorian calendar leap years are those divisible by 4 except 
 695         // those divisible by 100 unless they're also divisible by 400 
 696         // (in some countries, like Russia and Greece, additional corrections 
 697         // exist, but they won't manifest themselves until 2700) 
 698         return (year 
% 4 == 0) && ((year 
% 100 != 0) || (year 
% 400 == 0)); 
 700     else if ( cal 
== Julian 
) 
 702         // in Julian calendar the rule is simpler 
 703         return year 
% 4 == 0; 
 707         wxFAIL_MSG(_T("unknown calendar")); 
 714 int wxDateTime::GetCentury(int year
) 
 716     return year 
> 0 ? year 
/ 100 : year 
/ 100 - 1; 
 720 int wxDateTime::ConvertYearToBC(int year
) 
 723     return year 
> 0 ? year 
: year 
- 1; 
 727 int wxDateTime::GetCurrentYear(wxDateTime::Calendar cal
) 
 732             return Now().GetYear(); 
 735             wxFAIL_MSG(_T("TODO")); 
 739             wxFAIL_MSG(_T("unsupported calendar")); 
 747 wxDateTime::Month 
wxDateTime::GetCurrentMonth(wxDateTime::Calendar cal
) 
 752             return Now().GetMonth(); 
 755             wxFAIL_MSG(_T("TODO")); 
 759             wxFAIL_MSG(_T("unsupported calendar")); 
 767 wxDateTime::wxDateTime_t 
wxDateTime::GetNumberOfDays(int year
, Calendar cal
) 
 769     if ( year 
== Inv_Year 
) 
 771         // take the current year if none given 
 772         year 
= GetCurrentYear(); 
 779             return IsLeapYear(year
) ? 366 : 365; 
 782             wxFAIL_MSG(_T("unsupported calendar")); 
 790 wxDateTime::wxDateTime_t 
wxDateTime::GetNumberOfDays(wxDateTime::Month month
, 
 792                                                      wxDateTime::Calendar cal
) 
 794     wxCHECK_MSG( month 
< MONTHS_IN_YEAR
, 0, _T("invalid month") ); 
 796     if ( cal 
== Gregorian 
|| cal 
== Julian 
) 
 798         if ( year 
== Inv_Year 
) 
 800             // take the current year if none given 
 801             year 
= GetCurrentYear(); 
 804         return GetNumOfDaysInMonth(year
, month
); 
 808         wxFAIL_MSG(_T("unsupported calendar")); 
 815 wxString 
wxDateTime::GetMonthName(wxDateTime::Month month
, 
 816                                   wxDateTime::NameFlags flags
) 
 818     wxCHECK_MSG( month 
!= Inv_Month
, wxEmptyString
, _T("invalid month") ); 
 820     // notice that we must set all the fields to avoid confusing libc (GNU one 
 821     // gets confused to a crash if we don't do this) 
 826     return CallStrftime(flags 
== Name_Abbr 
? _T("%b") : _T("%B"), &tm
); 
 832                         ret 
= (flags 
== Name_Abbr 
? wxT("Jan"): wxT("January")); 
 835                         ret 
= (flags 
== Name_Abbr 
? wxT("Feb"): wxT("Febuary")); 
 838                         ret 
= (flags 
== Name_Abbr 
? wxT("Mar"): wxT("March")); 
 841                         ret 
= (flags 
== Name_Abbr 
? wxT("Apr"): wxT("April")); 
 844                         ret 
= (flags 
== Name_Abbr 
? wxT("May"): wxT("May")); 
 847                         ret 
= (flags 
== Name_Abbr 
? wxT("Jun"): wxT("June")); 
 850                         ret 
= (flags 
== Name_Abbr 
? wxT("Jul"): wxT("July")); 
 853                         ret 
= (flags 
== Name_Abbr 
? wxT("Aug"): wxT("August")); 
 856                         ret 
= (flags 
== Name_Abbr 
? wxT("Sep"): wxT("September")); 
 859                         ret 
= (flags 
== Name_Abbr 
? wxT("Oct"): wxT("October")); 
 862                         ret 
= (flags 
== Name_Abbr 
? wxT("Nov"): wxT("November")); 
 865                         ret 
= (flags 
== Name_Abbr 
? wxT("Dec"): wxT("December")); 
 873 wxString 
wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday
, 
 874                                     wxDateTime::NameFlags flags
) 
 876     wxCHECK_MSG( wday 
!= Inv_WeekDay
, wxEmptyString
, _T("invalid weekday") ); 
 878     // take some arbitrary Sunday (but notice that the day should be such that 
 879     // after adding wday to it below we still have a valid date, e.g. don't 
 887     // and offset it by the number of days needed to get the correct wday 
 890     // call mktime() to normalize it... 
 893     // ... and call strftime() 
 894     return CallStrftime(flags 
== Name_Abbr 
? _T("%a") : _T("%A"), &tm
); 
 900                         ret 
= (flags 
== Name_Abbr 
? wxT("Sun") : wxT("Sunday")); 
 903                         ret 
= (flags 
== Name_Abbr 
? wxT("Mon") : wxT("Monday")); 
 906                         ret 
= (flags 
== Name_Abbr 
? wxT("Tue") : wxT("Tuesday")); 
 909                         ret 
= (flags 
== Name_Abbr 
? wxT("Wed") : wxT("Wednesday")); 
 912                         ret 
= (flags 
== Name_Abbr 
? wxT("Thu") : wxT("Thursday")); 
 915                         ret 
= (flags 
== Name_Abbr 
? wxT("Fri") : wxT("Friday")); 
 918                         ret 
= (flags 
== Name_Abbr 
? wxT("Sat") : wxT("Saturday")); 
 927 void wxDateTime::GetAmPmStrings(wxString 
*am
, wxString 
*pm
) 
 932     // @Note: Do not call 'CallStrftime' here! CallStrftime checks the return code 
 933     // and causes an assertion failed if the buffer is to small (which is good) - OR - 
 934     // if strftime does not return anything because the format string is invalid - OR - 
 935     // if there are no 'am' / 'pm' tokens defined for the current locale (which is not good). 
 936     // wxDateTime::ParseTime will try several different formats to parse the time. 
 937     // As a result, GetAmPmStrings might get called, even if the current locale 
 938     // does not define any 'am' / 'pm' tokens. In this case, wxStrftime would 
 939     // assert, even though it is a perfectly legal use. 
 942         if (wxStrftime(buffer
, sizeof(buffer
)/sizeof(wxChar
), _T("%p"), &tm
) > 0) 
 943             *am 
= wxString(buffer
); 
 950         if (wxStrftime(buffer
, sizeof(buffer
)/sizeof(wxChar
), _T("%p"), &tm
) > 0) 
 951             *pm 
= wxString(buffer
); 
 957 // ---------------------------------------------------------------------------- 
 958 // Country stuff: date calculations depend on the country (DST, work days, 
 959 // ...), so we need to know which rules to follow. 
 960 // ---------------------------------------------------------------------------- 
 963 wxDateTime::Country 
wxDateTime::GetCountry() 
 965     // TODO use LOCALE_ICOUNTRY setting under Win32 
 967     if ( ms_country 
== Country_Unknown 
) 
 969         // try to guess from the time zone name 
 970         time_t t 
= time(NULL
); 
 971         struct tm 
*tm 
= localtime(&t
); 
 973         wxString tz 
= CallStrftime(_T("%Z"), tm
); 
 974         if ( tz 
== _T("WET") || tz 
== _T("WEST") ) 
 978         else if ( tz 
== _T("CET") || tz 
== _T("CEST") ) 
 980             ms_country 
= Country_EEC
; 
 982         else if ( tz 
== _T("MSK") || tz 
== _T("MSD") ) 
 986         else if ( tz 
== _T("AST") || tz 
== _T("ADT") || 
 987                   tz 
== _T("EST") || tz 
== _T("EDT") || 
 988                   tz 
== _T("CST") || tz 
== _T("CDT") || 
 989                   tz 
== _T("MST") || tz 
== _T("MDT") || 
 990                   tz 
== _T("PST") || tz 
== _T("PDT") ) 
 996             // well, choose a default one 
1008 void wxDateTime::SetCountry(wxDateTime::Country country
) 
1010     ms_country 
= country
; 
1014 bool wxDateTime::IsWestEuropeanCountry(Country country
) 
1016     if ( country 
== Country_Default 
) 
1018         country 
= GetCountry(); 
1021     return (Country_WesternEurope_Start 
<= country
) && 
1022            (country 
<= Country_WesternEurope_End
); 
1025 // ---------------------------------------------------------------------------- 
1026 // DST calculations: we use 3 different rules for the West European countries, 
1027 // USA and for the rest of the world. This is undoubtedly false for many 
1028 // countries, but I lack the necessary info (and the time to gather it), 
1029 // please add the other rules here! 
1030 // ---------------------------------------------------------------------------- 
1033 bool wxDateTime::IsDSTApplicable(int year
, Country country
) 
1035     if ( year 
== Inv_Year 
) 
1037         // take the current year if none given 
1038         year 
= GetCurrentYear(); 
1041     if ( country 
== Country_Default 
) 
1043         country 
= GetCountry(); 
1050             // DST was first observed in the US and UK during WWI, reused 
1051             // during WWII and used again since 1966 
1052             return year 
>= 1966 || 
1053                    (year 
>= 1942 && year 
<= 1945) || 
1054                    (year 
== 1918 || year 
== 1919); 
1057             // assume that it started after WWII 
1063 wxDateTime 
wxDateTime::GetBeginDST(int year
, Country country
) 
1065     if ( year 
== Inv_Year 
) 
1067         // take the current year if none given 
1068         year 
= GetCurrentYear(); 
1071     if ( country 
== Country_Default 
) 
1073         country 
= GetCountry(); 
1076     if ( !IsDSTApplicable(year
, country
) ) 
1078         return wxInvalidDateTime
; 
1083     if ( IsWestEuropeanCountry(country
) || (country 
== Russia
) ) 
1085         // DST begins at 1 a.m. GMT on the last Sunday of March 
1086         if ( !dt
.SetToLastWeekDay(Sun
, Mar
, year
) ) 
1089             wxFAIL_MSG( _T("no last Sunday in March?") ); 
1092         dt 
+= wxTimeSpan::Hours(1); 
1094         // disable DST tests because it could result in an infinite recursion! 
1097     else switch ( country 
) 
1104                     // don't know for sure - assume it was in effect all year 
1109                     dt
.Set(1, Jan
, year
); 
1113                     // DST was installed Feb 2, 1942 by the Congress 
1114                     dt
.Set(2, Feb
, year
); 
1117                     // Oil embargo changed the DST period in the US 
1119                     dt
.Set(6, Jan
, 1974); 
1123                     dt
.Set(23, Feb
, 1975); 
1127                     // before 1986, DST begun on the last Sunday of April, but 
1128                     // in 1986 Reagan changed it to begin at 2 a.m. of the 
1129                     // first Sunday in April 
1132                         if ( !dt
.SetToLastWeekDay(Sun
, Apr
, year
) ) 
1135                             wxFAIL_MSG( _T("no first Sunday in April?") ); 
1140                         if ( !dt
.SetToWeekDay(Sun
, 1, Apr
, year
) ) 
1143                             wxFAIL_MSG( _T("no first Sunday in April?") ); 
1147                     dt 
+= wxTimeSpan::Hours(2); 
1149                     // TODO what about timezone?? 
1155             // assume Mar 30 as the start of the DST for the rest of the world 
1156             // - totally bogus, of course 
1157             dt
.Set(30, Mar
, year
); 
1164 wxDateTime 
wxDateTime::GetEndDST(int year
, Country country
) 
1166     if ( year 
== Inv_Year 
) 
1168         // take the current year if none given 
1169         year 
= GetCurrentYear(); 
1172     if ( country 
== Country_Default 
) 
1174         country 
= GetCountry(); 
1177     if ( !IsDSTApplicable(year
, country
) ) 
1179         return wxInvalidDateTime
; 
1184     if ( IsWestEuropeanCountry(country
) || (country 
== Russia
) ) 
1186         // DST ends at 1 a.m. GMT on the last Sunday of October 
1187         if ( !dt
.SetToLastWeekDay(Sun
, Oct
, year
) ) 
1189             // weirder and weirder... 
1190             wxFAIL_MSG( _T("no last Sunday in October?") ); 
1193         dt 
+= wxTimeSpan::Hours(1); 
1195         // disable DST tests because it could result in an infinite recursion! 
1198     else switch ( country 
) 
1205                     // don't know for sure - assume it was in effect all year 
1209                     dt
.Set(31, Dec
, year
); 
1213                     // the time was reset after the end of the WWII 
1214                     dt
.Set(30, Sep
, year
); 
1218                     // DST ends at 2 a.m. on the last Sunday of October 
1219                     if ( !dt
.SetToLastWeekDay(Sun
, Oct
, year
) ) 
1221                         // weirder and weirder... 
1222                         wxFAIL_MSG( _T("no last Sunday in October?") ); 
1225                     dt 
+= wxTimeSpan::Hours(2); 
1227                     // TODO what about timezone?? 
1232             // assume October 26th as the end of the DST - totally bogus too 
1233             dt
.Set(26, Oct
, year
); 
1239 // ---------------------------------------------------------------------------- 
1240 // constructors and assignment operators 
1241 // ---------------------------------------------------------------------------- 
1243 // return the current time with ms precision 
1244 /* static */ wxDateTime 
wxDateTime::UNow() 
1246     return wxDateTime(wxGetLocalTimeMillis()); 
1249 // the values in the tm structure contain the local time 
1250 wxDateTime
& wxDateTime::Set(const struct tm
& tm
) 
1253     time_t timet 
= mktime(&tm2
); 
1255     if ( timet 
== (time_t)-1 ) 
1257         // mktime() rather unintuitively fails for Jan 1, 1970 if the hour is 
1258         // less than timezone - try to make it work for this case 
1259         if ( tm2
.tm_year 
== 70 && tm2
.tm_mon 
== 0 && tm2
.tm_mday 
== 1 ) 
1261             return Set((time_t)( 
1263                        tm2
.tm_hour 
* MIN_PER_HOUR 
* SEC_PER_MIN 
+ 
1264                        tm2
.tm_min 
* SEC_PER_MIN 
+ 
1268         wxFAIL_MSG( _T("mktime() failed") ); 
1270         *this = wxInvalidDateTime
; 
1280 wxDateTime
& wxDateTime::Set(wxDateTime_t hour
, 
1281                             wxDateTime_t minute
, 
1282                             wxDateTime_t second
, 
1283                             wxDateTime_t millisec
) 
1285     // we allow seconds to be 61 to account for the leap seconds, even if we 
1286     // don't use them really 
1287     wxDATETIME_CHECK( hour 
< 24 && 
1291                       _T("Invalid time in wxDateTime::Set()") ); 
1293     // get the current date from system 
1294     struct tm 
*tm 
= GetTmNow(); 
1296     wxDATETIME_CHECK( tm
, _T("localtime() failed") ); 
1298     // make a copy so it isn't clobbered by the call to mktime() below 
1303     tm1
.tm_min 
= minute
; 
1304     tm1
.tm_sec 
= second
; 
1306     // and the DST in case it changes on this date 
1309     if ( tm2
.tm_isdst 
!= tm1
.tm_isdst 
) 
1310         tm1
.tm_isdst 
= tm2
.tm_isdst
; 
1314     // and finally adjust milliseconds 
1315     return SetMillisecond(millisec
); 
1318 wxDateTime
& wxDateTime::Set(wxDateTime_t day
, 
1322                             wxDateTime_t minute
, 
1323                             wxDateTime_t second
, 
1324                             wxDateTime_t millisec
) 
1326     wxDATETIME_CHECK( hour 
< 24 && 
1330                       _T("Invalid time in wxDateTime::Set()") ); 
1332     ReplaceDefaultYearMonthWithCurrent(&year
, &month
); 
1334     wxDATETIME_CHECK( (0 < day
) && (day 
<= GetNumberOfDays(month
, year
)), 
1335                       _T("Invalid date in wxDateTime::Set()") ); 
1337     // the range of time_t type (inclusive) 
1338     static const int yearMinInRange 
= 1970; 
1339     static const int yearMaxInRange 
= 2037; 
1341     // test only the year instead of testing for the exact end of the Unix 
1342     // time_t range - it doesn't bring anything to do more precise checks 
1343     if ( year 
>= yearMinInRange 
&& year 
<= yearMaxInRange 
) 
1345         // use the standard library version if the date is in range - this is 
1346         // probably more efficient than our code 
1348         tm
.tm_year 
= year 
- 1900; 
1354         tm
.tm_isdst 
= -1;       // mktime() will guess it 
1358         // and finally adjust milliseconds 
1360             SetMillisecond(millisec
); 
1366         // do time calculations ourselves: we want to calculate the number of 
1367         // milliseconds between the given date and the epoch 
1369         // get the JDN for the midnight of this day 
1370         m_time 
= GetTruncatedJDN(day
, month
, year
); 
1371         m_time 
-= EPOCH_JDN
; 
1372         m_time 
*= SECONDS_PER_DAY 
* TIME_T_FACTOR
; 
1374         // JDN corresponds to GMT, we take localtime 
1375         Add(wxTimeSpan(hour
, minute
, second 
+ GetTimeZone(), millisec
)); 
1381 wxDateTime
& wxDateTime::Set(double jdn
) 
1383     // so that m_time will be 0 for the midnight of Jan 1, 1970 which is jdn 
1385     jdn 
-= EPOCH_JDN 
+ 0.5; 
1387     jdn 
*= MILLISECONDS_PER_DAY
; 
1391     // JDNs always suppose an UTC date, so bring it back to local time zone 
1392     // (also see GetJulianDayNumber() implementation) 
1393     long tzDiff 
= GetTimeZone(); 
1396         // FIXME: again, we suppose that DST is always one hour 
1400     m_time 
+= tzDiff
*1000; // tzDiff is in seconds 
1405 wxDateTime
& wxDateTime::ResetTime() 
1409     if ( tm
.hour 
|| tm
.min 
|| tm
.sec 
|| tm
.msec 
) 
1422 // ---------------------------------------------------------------------------- 
1423 // DOS Date and Time Format functions 
1424 // ---------------------------------------------------------------------------- 
1425 // the dos date and time value is an unsigned 32 bit value in the format: 
1426 // YYYYYYYMMMMDDDDDhhhhhmmmmmmsssss 
1428 // Y = year offset from 1980 (0-127) 
1430 // D = day of month (1-31) 
1432 // m = minute (0-59) 
1433 // s = bisecond (0-29) each bisecond indicates two seconds 
1434 // ---------------------------------------------------------------------------- 
1436 wxDateTime
& wxDateTime::SetFromDOS(unsigned long ddt
) 
1441     long year 
= ddt 
& 0xFE000000; 
1446     long month 
= ddt 
& 0x1E00000; 
1451     long day 
= ddt 
& 0x1F0000; 
1455     long hour 
= ddt 
& 0xF800; 
1459     long minute 
= ddt 
& 0x7E0; 
1463     long second 
= ddt 
& 0x1F; 
1464     tm
.tm_sec 
= second 
* 2; 
1466     return Set(mktime(&tm
)); 
1469 unsigned long wxDateTime::GetAsDOS() const 
1472     time_t ticks 
= GetTicks(); 
1473     struct tm 
*tm 
= localtime(&ticks
); 
1475     long year 
= tm
->tm_year
; 
1479     long month 
= tm
->tm_mon
; 
1483     long day 
= tm
->tm_mday
; 
1486     long hour 
= tm
->tm_hour
; 
1489     long minute 
= tm
->tm_min
; 
1492     long second 
= tm
->tm_sec
; 
1495     ddt 
= year 
| month 
| day 
| hour 
| minute 
| second
; 
1499 // ---------------------------------------------------------------------------- 
1500 // time_t <-> broken down time conversions 
1501 // ---------------------------------------------------------------------------- 
1503 wxDateTime::Tm 
wxDateTime::GetTm(const TimeZone
& tz
) const 
1505     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1507     time_t time 
= GetTicks(); 
1508     if ( time 
!= (time_t)-1 ) 
1510         // use C RTL functions 
1512         if ( tz
.GetOffset() == -GetTimeZone() ) 
1514             // we are working with local time 
1515             tm 
= localtime(&time
); 
1517             // should never happen 
1518             wxCHECK_MSG( tm
, Tm(), _T("localtime() failed") ); 
1522             time 
+= (time_t)tz
.GetOffset(); 
1523 #if defined(__VMS__) || defined(__WATCOMC__) // time is unsigned so avoid warning 
1524             int time2 
= (int) time
; 
1532                 // should never happen 
1533                 wxCHECK_MSG( tm
, Tm(), _T("gmtime() failed") ); 
1537                 tm 
= (struct tm 
*)NULL
; 
1543             // adjust the milliseconds 
1545             long timeOnly 
= (m_time 
% MILLISECONDS_PER_DAY
).ToLong(); 
1546             tm2
.msec 
= (wxDateTime_t
)(timeOnly 
% 1000); 
1549         //else: use generic code below 
1552     // remember the time and do the calculations with the date only - this 
1553     // eliminates rounding errors of the floating point arithmetics 
1555     wxLongLong timeMidnight 
= m_time 
+ tz
.GetOffset() * 1000; 
1557     long timeOnly 
= (timeMidnight 
% MILLISECONDS_PER_DAY
).ToLong(); 
1559     // we want to always have positive time and timeMidnight to be really 
1560     // the midnight before it 
1563         timeOnly 
= MILLISECONDS_PER_DAY 
+ timeOnly
; 
1566     timeMidnight 
-= timeOnly
; 
1568     // calculate the Gregorian date from JDN for the midnight of our date: 
1569     // this will yield day, month (in 1..12 range) and year 
1571     // actually, this is the JDN for the noon of the previous day 
1572     long jdn 
= (timeMidnight 
/ MILLISECONDS_PER_DAY
).ToLong() + EPOCH_JDN
; 
1574     // CREDIT: code below is by Scott E. Lee (but bugs are mine) 
1576     wxASSERT_MSG( jdn 
> -2, _T("JDN out of range") ); 
1578     // calculate the century 
1579     long temp 
= (jdn 
+ JDN_OFFSET
) * 4 - 1; 
1580     long century 
= temp 
/ DAYS_PER_400_YEARS
; 
1582     // then the year and day of year (1 <= dayOfYear <= 366) 
1583     temp 
= ((temp 
% DAYS_PER_400_YEARS
) / 4) * 4 + 3; 
1584     long year 
= (century 
* 100) + (temp 
/ DAYS_PER_4_YEARS
); 
1585     long dayOfYear 
= (temp 
% DAYS_PER_4_YEARS
) / 4 + 1; 
1587     // and finally the month and day of the month 
1588     temp 
= dayOfYear 
* 5 - 3; 
1589     long month 
= temp 
/ DAYS_PER_5_MONTHS
; 
1590     long day 
= (temp 
% DAYS_PER_5_MONTHS
) / 5 + 1; 
1592     // month is counted from March - convert to normal 
1603     // year is offset by 4800 
1606     // check that the algorithm gave us something reasonable 
1607     wxASSERT_MSG( (0 < month
) && (month 
<= 12), _T("invalid month") ); 
1608     wxASSERT_MSG( (1 <= day
) && (day 
< 32), _T("invalid day") ); 
1610     // construct Tm from these values 
1612     tm
.year 
= (int)year
; 
1613     tm
.mon 
= (Month
)(month 
- 1); // algorithm yields 1 for January, not 0 
1614     tm
.mday 
= (wxDateTime_t
)day
; 
1615     tm
.msec 
= (wxDateTime_t
)(timeOnly 
% 1000); 
1616     timeOnly 
-= tm
.msec
; 
1617     timeOnly 
/= 1000;               // now we have time in seconds 
1619     tm
.sec 
= (wxDateTime_t
)(timeOnly 
% 60); 
1621     timeOnly 
/= 60;                 // now we have time in minutes 
1623     tm
.min 
= (wxDateTime_t
)(timeOnly 
% 60); 
1626     tm
.hour 
= (wxDateTime_t
)(timeOnly 
/ 60); 
1631 wxDateTime
& wxDateTime::SetYear(int year
) 
1633     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1642 wxDateTime
& wxDateTime::SetMonth(Month month
) 
1644     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1653 wxDateTime
& wxDateTime::SetDay(wxDateTime_t mday
) 
1655     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1664 wxDateTime
& wxDateTime::SetHour(wxDateTime_t hour
) 
1666     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1675 wxDateTime
& wxDateTime::SetMinute(wxDateTime_t min
) 
1677     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1686 wxDateTime
& wxDateTime::SetSecond(wxDateTime_t sec
) 
1688     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1697 wxDateTime
& wxDateTime::SetMillisecond(wxDateTime_t millisecond
) 
1699     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1701     // we don't need to use GetTm() for this one 
1702     m_time 
-= m_time 
% 1000l; 
1703     m_time 
+= millisecond
; 
1708 // ---------------------------------------------------------------------------- 
1709 // wxDateTime arithmetics 
1710 // ---------------------------------------------------------------------------- 
1712 wxDateTime
& wxDateTime::Add(const wxDateSpan
& diff
) 
1716     tm
.year 
+= diff
.GetYears(); 
1717     tm
.AddMonths(diff
.GetMonths()); 
1719     // check that the resulting date is valid 
1720     if ( tm
.mday 
> GetNumOfDaysInMonth(tm
.year
, tm
.mon
) ) 
1722         // We suppose that when adding one month to Jan 31 we want to get Feb 
1723         // 28 (or 29), i.e. adding a month to the last day of the month should 
1724         // give the last day of the next month which is quite logical. 
1726         // Unfortunately, there is no logic way to understand what should 
1727         // Jan 30 + 1 month be - Feb 28 too or Feb 27 (assuming non leap year)? 
1728         // We make it Feb 28 (last day too), but it is highly questionable. 
1729         tm
.mday 
= GetNumOfDaysInMonth(tm
.year
, tm
.mon
); 
1732     tm
.AddDays(diff
.GetTotalDays()); 
1736     wxASSERT_MSG( IsSameTime(tm
), 
1737                   _T("Add(wxDateSpan) shouldn't modify time") ); 
1742 // ---------------------------------------------------------------------------- 
1743 // Weekday and monthday stuff 
1744 // ---------------------------------------------------------------------------- 
1746 // convert Sun, Mon, ..., Sat into 6, 0, ..., 5 
1747 static inline int ConvertWeekDayToMondayBase(int wd
) 
1749     return wd 
== wxDateTime::Sun 
? 6 : wd 
- 1; 
1754 wxDateTime::SetToWeekOfYear(int year
, wxDateTime_t numWeek
, WeekDay wd
) 
1756     wxASSERT_MSG( numWeek 
> 0, 
1757                   _T("invalid week number: weeks are counted from 1") ); 
1759     // Jan 4 always lies in the 1st week of the year 
1760     wxDateTime 
dt(4, Jan
, year
); 
1761     dt
.SetToWeekDayInSameWeek(wd
); 
1762     dt 
+= wxDateSpan::Weeks(numWeek 
- 1); 
1767 // use a separate function to avoid warnings about using deprecated 
1768 // SetToTheWeek in GetWeek below 
1770 SetToTheWeek(int year
, 
1771              wxDateTime::wxDateTime_t numWeek
, 
1772              wxDateTime::WeekDay weekday
, 
1773              wxDateTime::WeekFlags flags
) 
1775     // Jan 4 always lies in the 1st week of the year 
1776     wxDateTime 
dt(4, wxDateTime::Jan
, year
); 
1777     dt
.SetToWeekDayInSameWeek(weekday
, flags
); 
1778     dt 
+= wxDateSpan::Weeks(numWeek 
- 1); 
1783 bool wxDateTime::SetToTheWeek(wxDateTime_t numWeek
, 
1787     int year 
= GetYear(); 
1788     *this = ::SetToTheWeek(year
, numWeek
, weekday
, flags
); 
1789     if ( GetYear() != year 
) 
1791         // oops... numWeek was too big 
1798 wxDateTime 
wxDateTime::GetWeek(wxDateTime_t numWeek
, 
1800                                WeekFlags flags
) const 
1802     return ::SetToTheWeek(GetYear(), numWeek
, weekday
, flags
); 
1805 wxDateTime
& wxDateTime::SetToLastMonthDay(Month month
, 
1808     // take the current month/year if none specified 
1809     if ( year 
== Inv_Year 
) 
1811     if ( month 
== Inv_Month 
) 
1814     return Set(GetNumOfDaysInMonth(year
, month
), month
, year
); 
1817 wxDateTime
& wxDateTime::SetToWeekDayInSameWeek(WeekDay weekday
, WeekFlags flags
) 
1819     wxDATETIME_CHECK( weekday 
!= Inv_WeekDay
, _T("invalid weekday") ); 
1821     int wdayThis 
= GetWeekDay(); 
1822     if ( weekday 
== wdayThis 
) 
1828     if ( flags 
== Default_First 
) 
1830         flags 
= GetCountry() == USA 
? Sunday_First 
: Monday_First
; 
1833     // the logic below based on comparing weekday and wdayThis works if Sun (0) 
1834     // is the first day in the week, but breaks down for Monday_First case so 
1835     // we adjust the week days in this case 
1836     if( flags 
== Monday_First 
) 
1838         if ( wdayThis 
== Sun 
) 
1841     //else: Sunday_First, nothing to do 
1843     // go forward or back in time to the day we want 
1844     if ( weekday 
< wdayThis 
) 
1846         return Subtract(wxDateSpan::Days(wdayThis 
- weekday
)); 
1848     else // weekday > wdayThis 
1850         return Add(wxDateSpan::Days(weekday 
- wdayThis
)); 
1854 wxDateTime
& wxDateTime::SetToNextWeekDay(WeekDay weekday
) 
1856     wxDATETIME_CHECK( weekday 
!= Inv_WeekDay
, _T("invalid weekday") ); 
1859     WeekDay wdayThis 
= GetWeekDay(); 
1860     if ( weekday 
== wdayThis 
) 
1865     else if ( weekday 
< wdayThis 
) 
1867         // need to advance a week 
1868         diff 
= 7 - (wdayThis 
- weekday
); 
1870     else // weekday > wdayThis 
1872         diff 
= weekday 
- wdayThis
; 
1875     return Add(wxDateSpan::Days(diff
)); 
1878 wxDateTime
& wxDateTime::SetToPrevWeekDay(WeekDay weekday
) 
1880     wxDATETIME_CHECK( weekday 
!= Inv_WeekDay
, _T("invalid weekday") ); 
1883     WeekDay wdayThis 
= GetWeekDay(); 
1884     if ( weekday 
== wdayThis 
) 
1889     else if ( weekday 
> wdayThis 
) 
1891         // need to go to previous week 
1892         diff 
= 7 - (weekday 
- wdayThis
); 
1894     else // weekday < wdayThis 
1896         diff 
= wdayThis 
- weekday
; 
1899     return Subtract(wxDateSpan::Days(diff
)); 
1902 bool wxDateTime::SetToWeekDay(WeekDay weekday
, 
1907     wxCHECK_MSG( weekday 
!= Inv_WeekDay
, false, _T("invalid weekday") ); 
1909     // we don't check explicitly that -5 <= n <= 5 because we will return false 
1910     // anyhow in such case - but may be should still give an assert for it? 
1912     // take the current month/year if none specified 
1913     ReplaceDefaultYearMonthWithCurrent(&year
, &month
); 
1917     // TODO this probably could be optimised somehow... 
1921         // get the first day of the month 
1922         dt
.Set(1, month
, year
); 
1925         WeekDay wdayFirst 
= dt
.GetWeekDay(); 
1927         // go to the first weekday of the month 
1928         int diff 
= weekday 
- wdayFirst
; 
1932         // add advance n-1 weeks more 
1935         dt 
+= wxDateSpan::Days(diff
); 
1937     else // count from the end of the month 
1939         // get the last day of the month 
1940         dt
.SetToLastMonthDay(month
, year
); 
1943         WeekDay wdayLast 
= dt
.GetWeekDay(); 
1945         // go to the last weekday of the month 
1946         int diff 
= wdayLast 
- weekday
; 
1950         // and rewind n-1 weeks from there 
1953         dt 
-= wxDateSpan::Days(diff
); 
1956     // check that it is still in the same month 
1957     if ( dt
.GetMonth() == month 
) 
1965         // no such day in this month 
1971 wxDateTime::wxDateTime_t 
GetDayOfYearFromTm(const wxDateTime::Tm
& tm
) 
1973     return (wxDateTime::wxDateTime_t
)(gs_cumulatedDays
[wxDateTime::IsLeapYear(tm
.year
)][tm
.mon
] + tm
.mday
); 
1976 wxDateTime::wxDateTime_t 
wxDateTime::GetDayOfYear(const TimeZone
& tz
) const 
1978     return GetDayOfYearFromTm(GetTm(tz
)); 
1981 wxDateTime::wxDateTime_t
 
1982 wxDateTime::GetWeekOfYear(wxDateTime::WeekFlags flags
, const TimeZone
& tz
) const 
1984     if ( flags 
== Default_First 
) 
1986         flags 
= GetCountry() == USA 
? Sunday_First 
: Monday_First
; 
1990     wxDateTime_t nDayInYear 
= GetDayOfYearFromTm(tm
); 
1992     int wdTarget 
= GetWeekDay(tz
); 
1993     int wdYearStart 
= wxDateTime(1, Jan
, GetYear()).GetWeekDay(); 
1995     if ( flags 
== Sunday_First 
) 
1997         // FIXME: First week is not calculated correctly. 
1998         week 
= (nDayInYear 
- wdTarget 
+ 7) / 7; 
1999         if ( wdYearStart 
== Wed 
|| wdYearStart 
== Thu 
) 
2002     else // week starts with monday 
2004         // adjust the weekdays to non-US style. 
2005         wdYearStart 
= ConvertWeekDayToMondayBase(wdYearStart
); 
2006         wdTarget 
= ConvertWeekDayToMondayBase(wdTarget
); 
2008         // quoting from http://www.cl.cam.ac.uk/~mgk25/iso-time.html: 
2010         //      Week 01 of a year is per definition the first week that has the 
2011         //      Thursday in this year, which is equivalent to the week that 
2012         //      contains the fourth day of January. In other words, the first 
2013         //      week of a new year is the week that has the majority of its 
2014         //      days in the new year. Week 01 might also contain days from the 
2015         //      previous year and the week before week 01 of a year is the last 
2016         //      week (52 or 53) of the previous year even if it contains days 
2017         //      from the new year. A week starts with Monday (day 1) and ends 
2018         //      with Sunday (day 7). 
2021         // if Jan 1 is Thursday or less, it is in the first week of this year 
2022         if ( wdYearStart 
< 4 ) 
2024             // count the number of entire weeks between Jan 1 and this date 
2025             week 
= (nDayInYear 
+ wdYearStart 
+ 6 - wdTarget
)/7; 
2027             // be careful to check for overflow in the next year 
2028             if ( week 
== 53 && tm
.mday 
- wdTarget 
> 28 ) 
2031         else // Jan 1 is in the last week of the previous year 
2033             // check if we happen to be at the last week of previous year: 
2034             if ( tm
.mon 
== Jan 
&& tm
.mday 
< 8 - wdYearStart 
) 
2035                 week 
= wxDateTime(31, Dec
, GetYear()-1).GetWeekOfYear(); 
2037                 week 
= (nDayInYear 
+ wdYearStart 
- 1 - wdTarget
)/7; 
2041     return (wxDateTime::wxDateTime_t
)week
; 
2044 wxDateTime::wxDateTime_t 
wxDateTime::GetWeekOfMonth(wxDateTime::WeekFlags flags
, 
2045                                                     const TimeZone
& tz
) const 
2048     wxDateTime dtMonthStart 
= wxDateTime(1, tm
.mon
, tm
.year
); 
2049     int nWeek 
= GetWeekOfYear(flags
) - dtMonthStart
.GetWeekOfYear(flags
) + 1; 
2052         // this may happen for January when Jan, 1 is the last week of the 
2054         nWeek 
+= IsLeapYear(tm
.year 
- 1) ? 53 : 52; 
2057     return (wxDateTime::wxDateTime_t
)nWeek
; 
2060 wxDateTime
& wxDateTime::SetToYearDay(wxDateTime::wxDateTime_t yday
) 
2062     int year 
= GetYear(); 
2063     wxDATETIME_CHECK( (0 < yday
) && (yday 
<= GetNumberOfDays(year
)), 
2064                       _T("invalid year day") ); 
2066     bool isLeap 
= IsLeapYear(year
); 
2067     for ( Month mon 
= Jan
; mon 
< Inv_Month
; wxNextMonth(mon
) ) 
2069         // for Dec, we can't compare with gs_cumulatedDays[mon + 1], but we 
2070         // don't need it neither - because of the CHECK above we know that 
2071         // yday lies in December then 
2072         if ( (mon 
== Dec
) || (yday 
<= gs_cumulatedDays
[isLeap
][mon 
+ 1]) ) 
2074             Set((wxDateTime::wxDateTime_t
)(yday 
- gs_cumulatedDays
[isLeap
][mon
]), mon
, year
); 
2083 // ---------------------------------------------------------------------------- 
2084 // Julian day number conversion and related stuff 
2085 // ---------------------------------------------------------------------------- 
2087 double wxDateTime::GetJulianDayNumber() const 
2089     // JDN are always expressed for the UTC dates 
2090     Tm 
tm(ToTimezone(UTC
).GetTm(UTC
)); 
2092     double result 
= GetTruncatedJDN(tm
.mday
, tm
.mon
, tm
.year
); 
2094     // add the part GetTruncatedJDN() neglected 
2097     // and now add the time: 86400 sec = 1 JDN 
2098     return result 
+ ((double)(60*(60*tm
.hour 
+ tm
.min
) + tm
.sec
)) / 86400; 
2101 double wxDateTime::GetRataDie() const 
2103     // March 1 of the year 0 is Rata Die day -306 and JDN 1721119.5 
2104     return GetJulianDayNumber() - 1721119.5 - 306; 
2107 // ---------------------------------------------------------------------------- 
2108 // timezone and DST stuff 
2109 // ---------------------------------------------------------------------------- 
2111 int wxDateTime::IsDST(wxDateTime::Country country
) const 
2113     wxCHECK_MSG( country 
== Country_Default
, -1, 
2114                  _T("country support not implemented") ); 
2116     // use the C RTL for the dates in the standard range 
2117     time_t timet 
= GetTicks(); 
2118     if ( timet 
!= (time_t)-1 ) 
2120         tm 
*tm 
= localtime(&timet
); 
2122         wxCHECK_MSG( tm
, -1, _T("localtime() failed") ); 
2124         return tm
->tm_isdst
; 
2128         int year 
= GetYear(); 
2130         if ( !IsDSTApplicable(year
, country
) ) 
2132             // no DST time in this year in this country 
2136         return IsBetween(GetBeginDST(year
, country
), GetEndDST(year
, country
)); 
2140 wxDateTime
& wxDateTime::MakeTimezone(const TimeZone
& tz
, bool noDST
) 
2142     long secDiff 
= GetTimeZone() + tz
.GetOffset(); 
2144     // we need to know whether DST is or not in effect for this date unless 
2145     // the test disabled by the caller 
2146     if ( !noDST 
&& (IsDST() == 1) ) 
2148         // FIXME we assume that the DST is always shifted by 1 hour 
2152     return Subtract(wxTimeSpan::Seconds(secDiff
)); 
2155 // ---------------------------------------------------------------------------- 
2156 // wxDateTime to/from text representations 
2157 // ---------------------------------------------------------------------------- 
2159 wxString 
wxDateTime::Format(const wxChar 
*format
, const TimeZone
& tz
) const 
2161     wxCHECK_MSG( format
, wxEmptyString
, _T("NULL format in wxDateTime::Format") ); 
2163     // we have to use our own implementation if the date is out of range of 
2164     // strftime() or if we use non standard specificators 
2165     time_t time 
= GetTicks(); 
2166     if ( (time 
!= (time_t)-1) && !wxStrstr(format
, _T("%l")) ) 
2170         if ( tz
.GetOffset() == -GetTimeZone() ) 
2172             // we are working with local time 
2173             tm 
= localtime(&time
); 
2175             // should never happen 
2176             wxCHECK_MSG( tm
, wxEmptyString
, _T("localtime() failed") ); 
2180             time 
+= (int)tz
.GetOffset(); 
2182 #if defined(__VMS__) || defined(__WATCOMC__) // time is unsigned so avoid warning 
2183             int time2 
= (int) time
; 
2191                 // should never happen 
2192                 wxCHECK_MSG( tm
, wxEmptyString
, _T("gmtime() failed") ); 
2196                 tm 
= (struct tm 
*)NULL
; 
2200         //Windows CE doesn't support strftime or wcsftime, so we use the generic implementation 
2203             return CallStrftime(format
, tm
); 
2206         //else: use generic code below 
2209     // we only parse ANSI C format specifications here, no POSIX 2 
2210     // complications, no GNU extensions but we do add support for a "%l" format 
2211     // specifier allowing to get the number of milliseconds 
2214     // used for calls to strftime() when we only deal with time 
2215     struct tm tmTimeOnly
; 
2216     tmTimeOnly
.tm_hour 
= tm
.hour
; 
2217     tmTimeOnly
.tm_min 
= tm
.min
; 
2218     tmTimeOnly
.tm_sec 
= tm
.sec
; 
2219     tmTimeOnly
.tm_wday 
= 0; 
2220     tmTimeOnly
.tm_yday 
= 0; 
2221     tmTimeOnly
.tm_mday 
= 1;         // any date will do 
2222     tmTimeOnly
.tm_mon 
= 0; 
2223     tmTimeOnly
.tm_year 
= 76; 
2224     tmTimeOnly
.tm_isdst 
= 0;        // no DST, we adjust for tz ourselves 
2226     wxString tmp
, res
, fmt
; 
2227     for ( const wxChar 
*p 
= format
; *p
; p
++ ) 
2229         if ( *p 
!= _T('%') ) 
2237         // set the default format 
2240             case _T('Y'):               // year has 4 digits 
2244             case _T('j'):               // day of year has 3 digits 
2245             case _T('l'):               // milliseconds have 3 digits 
2249             case _T('w'):               // week day as number has only one 
2254                 // it's either another valid format specifier in which case 
2255                 // the format is "%02d" (for all the rest) or we have the 
2256                 // field width preceding the format in which case it will 
2257                 // override the default format anyhow 
2261         bool restart 
= true; 
2266             // start of the format specification 
2269                 case _T('a'):       // a weekday name 
2271                     // second parameter should be true for abbreviated names 
2272                     res 
+= GetWeekDayName(tm
.GetWeekDay(), 
2273                                           *p 
== _T('a') ? Name_Abbr 
: Name_Full
); 
2276                 case _T('b'):       // a month name 
2278                     res 
+= GetMonthName(tm
.mon
, 
2279                                         *p 
== _T('b') ? Name_Abbr 
: Name_Full
); 
2282                 case _T('c'):       // locale default date and time  representation 
2283                 case _T('x'):       // locale default date representation 
2286                     // the problem: there is no way to know what do these format 
2287                     // specifications correspond to for the current locale. 
2289                     // the solution: use a hack and still use strftime(): first 
2290                     // find the YEAR which is a year in the strftime() range (1970 
2291                     // - 2038) whose Jan 1 falls on the same week day as the Jan 1 
2292                     // of the real year. Then make a copy of the format and 
2293                     // replace all occurences of YEAR in it with some unique 
2294                     // string not appearing anywhere else in it, then use 
2295                     // strftime() to format the date in year YEAR and then replace 
2296                     // YEAR back by the real year and the unique replacement 
2297                     // string back with YEAR. Notice that "all occurences of YEAR" 
2298                     // means all occurences of 4 digit as well as 2 digit form! 
2300                     // the bugs: we assume that neither of %c nor %x contains any 
2301                     // fields which may change between the YEAR and real year. For 
2302                     // example, the week number (%U, %W) and the day number (%j) 
2303                     // will change if one of these years is leap and the other one 
2306                         // find the YEAR: normally, for any year X, Jan 1 or the 
2307                         // year X + 28 is the same weekday as Jan 1 of X (because 
2308                         // the weekday advances by 1 for each normal X and by 2 
2309                         // for each leap X, hence by 5 every 4 years or by 35 
2310                         // which is 0 mod 7 every 28 years) but this rule breaks 
2311                         // down if there are years between X and Y which are 
2312                         // divisible by 4 but not leap (i.e. divisible by 100 but 
2313                         // not 400), hence the correction. 
2315                         int yearReal 
= GetYear(tz
); 
2316                         int mod28 
= yearReal 
% 28; 
2318                         // be careful to not go too far - we risk to leave the 
2323                             year 
= 1988 + mod28
;      // 1988 == 0 (mod 28) 
2327                             year 
= 1970 + mod28 
- 10; // 1970 == 10 (mod 28) 
2330                         int nCentury 
= year 
/ 100, 
2331                             nCenturyReal 
= yearReal 
/ 100; 
2333                         // need to adjust for the years divisble by 400 which are 
2334                         // not leap but are counted like leap ones if we just take 
2335                         // the number of centuries in between for nLostWeekDays 
2336                         int nLostWeekDays 
= (nCentury 
- nCenturyReal
) - 
2337                                             (nCentury 
/ 4 - nCenturyReal 
/ 4); 
2339                         // we have to gain back the "lost" weekdays: note that the 
2340                         // effect of this loop is to not do anything to 
2341                         // nLostWeekDays (which we won't use any more), but to 
2342                         // (indirectly) set the year correctly 
2343                         while ( (nLostWeekDays 
% 7) != 0 ) 
2345                             nLostWeekDays 
+= year
++ % 4 ? 1 : 2; 
2348                         // at any rate, we couldn't go further than 1988 + 9 + 28! 
2349                         wxASSERT_MSG( year 
< 2030, 
2350                                       _T("logic error in wxDateTime::Format") ); 
2352                         wxString strYear
, strYear2
; 
2353                         strYear
.Printf(_T("%d"), year
); 
2354                         strYear2
.Printf(_T("%d"), year 
% 100); 
2356                         // find two strings not occuring in format (this is surely 
2357                         // not optimal way of doing it... improvements welcome!) 
2358                         wxString fmt 
= format
; 
2359                         wxString replacement 
= (wxChar
)-1; 
2360                         while ( fmt
.Find(replacement
) != wxNOT_FOUND 
) 
2362                             replacement 
<< (wxChar
)-1; 
2365                         wxString replacement2 
= (wxChar
)-2; 
2366                         while ( fmt
.Find(replacement
) != wxNOT_FOUND 
) 
2368                             replacement 
<< (wxChar
)-2; 
2371                         // replace all occurences of year with it 
2372                         bool wasReplaced 
= fmt
.Replace(strYear
, replacement
) > 0; 
2374                             wasReplaced 
= fmt
.Replace(strYear2
, replacement2
) > 0; 
2376                         // use strftime() to format the same date but in supported 
2379                         // NB: we assume that strftime() doesn't check for the 
2380                         //     date validity and will happily format the date 
2381                         //     corresponding to Feb 29 of a non leap year (which 
2382                         //     may happen if yearReal was leap and year is not) 
2383                         struct tm tmAdjusted
; 
2385                         tmAdjusted
.tm_hour 
= tm
.hour
; 
2386                         tmAdjusted
.tm_min 
= tm
.min
; 
2387                         tmAdjusted
.tm_sec 
= tm
.sec
; 
2388                         tmAdjusted
.tm_wday 
= tm
.GetWeekDay(); 
2389                         tmAdjusted
.tm_yday 
= GetDayOfYear(); 
2390                         tmAdjusted
.tm_mday 
= tm
.mday
; 
2391                         tmAdjusted
.tm_mon 
= tm
.mon
; 
2392                         tmAdjusted
.tm_year 
= year 
- 1900; 
2393                         tmAdjusted
.tm_isdst 
= 0; // no DST, already adjusted 
2394                         wxString str 
= CallStrftime(*p 
== _T('c') ? _T("%c") 
2398                         // now replace the occurence of 1999 with the real year 
2399                         wxString strYearReal
, strYearReal2
; 
2400                         strYearReal
.Printf(_T("%04d"), yearReal
); 
2401                         strYearReal2
.Printf(_T("%02d"), yearReal 
% 100); 
2402                         str
.Replace(strYear
, strYearReal
); 
2403                         str
.Replace(strYear2
, strYearReal2
); 
2405                         // and replace back all occurences of replacement string 
2408                             str
.Replace(replacement2
, strYear2
); 
2409                             str
.Replace(replacement
, strYear
); 
2415                                         //Use "%m/%d/%y %H:%M:%S" format instead 
2416                                         res 
+= wxString::Format(wxT("%02d/%02d/%04d %02d:%02d:%02d"), 
2417                                                         tm
.mon
+1,tm
.mday
, tm
.year
, tm
.hour
, tm
.min
, tm
.sec
); 
2421                 case _T('d'):       // day of a month (01-31) 
2422                     res 
+= wxString::Format(fmt
, tm
.mday
); 
2425                 case _T('H'):       // hour in 24h format (00-23) 
2426                     res 
+= wxString::Format(fmt
, tm
.hour
); 
2429                 case _T('I'):       // hour in 12h format (01-12) 
2431                         // 24h -> 12h, 0h -> 12h too 
2432                         int hour12 
= tm
.hour 
> 12 ? tm
.hour 
- 12 
2433                                                   : tm
.hour 
? tm
.hour 
: 12; 
2434                         res 
+= wxString::Format(fmt
, hour12
); 
2438                 case _T('j'):       // day of the year 
2439                     res 
+= wxString::Format(fmt
, GetDayOfYear(tz
)); 
2442                 case _T('l'):       // milliseconds (NOT STANDARD) 
2443                     res 
+= wxString::Format(fmt
, GetMillisecond(tz
)); 
2446                 case _T('m'):       // month as a number (01-12) 
2447                     res 
+= wxString::Format(fmt
, tm
.mon 
+ 1); 
2450                 case _T('M'):       // minute as a decimal number (00-59) 
2451                     res 
+= wxString::Format(fmt
, tm
.min
); 
2454                 case _T('p'):       // AM or PM string 
2456                     res 
+= CallStrftime(_T("%p"), &tmTimeOnly
); 
2458                                         res 
+= (tmTimeOnly
.tm_hour 
> 12) ? wxT("pm") : wxT("am"); 
2462                 case _T('S'):       // second as a decimal number (00-61) 
2463                     res 
+= wxString::Format(fmt
, tm
.sec
); 
2466                 case _T('U'):       // week number in the year (Sunday 1st week day) 
2467                     res 
+= wxString::Format(fmt
, GetWeekOfYear(Sunday_First
, tz
)); 
2470                 case _T('W'):       // week number in the year (Monday 1st week day) 
2471                     res 
+= wxString::Format(fmt
, GetWeekOfYear(Monday_First
, tz
)); 
2474                 case _T('w'):       // weekday as a number (0-6), Sunday = 0 
2475                     res 
+= wxString::Format(fmt
, tm
.GetWeekDay()); 
2478                 // case _T('x'): -- handled with "%c" 
2480                 case _T('X'):       // locale default time representation 
2481                     // just use strftime() to format the time for us 
2483                     res 
+= CallStrftime(_T("%X"), &tmTimeOnly
); 
2485                                         res 
+= wxString::Format(wxT("%02d:%02d:%02d"),tm
.hour
, tm
.min
, tm
.sec
); 
2489                 case _T('y'):       // year without century (00-99) 
2490                     res 
+= wxString::Format(fmt
, tm
.year 
% 100); 
2493                 case _T('Y'):       // year with century 
2494                     res 
+= wxString::Format(fmt
, tm
.year
); 
2497                 case _T('Z'):       // timezone name 
2499                     res 
+= CallStrftime(_T("%Z"), &tmTimeOnly
); 
2504                     // is it the format width? 
2506                     while ( *p 
== _T('-') || *p 
== _T('+') || 
2507                             *p 
== _T(' ') || wxIsdigit(*p
) ) 
2514                         // we've only got the flags and width so far in fmt 
2515                         fmt
.Prepend(_T('%')); 
2516                         fmt
.Append(_T('d')); 
2523                     // no, it wasn't the width 
2524                     wxFAIL_MSG(_T("unknown format specificator")); 
2526                     // fall through and just copy it nevertheless 
2528                 case _T('%'):       // a percent sign 
2532                 case 0:             // the end of string 
2533                     wxFAIL_MSG(_T("missing format at the end of string")); 
2535                     // just put the '%' which was the last char in format 
2545 // this function parses a string in (strict) RFC 822 format: see the section 5 
2546 // of the RFC for the detailed description, but briefly it's something of the 
2547 // form "Sat, 18 Dec 1999 00:48:30 +0100" 
2549 // this function is "strict" by design - it must reject anything except true 
2550 // RFC822 time specs. 
2552 // TODO a great candidate for using reg exps 
2553 const wxChar 
*wxDateTime::ParseRfc822Date(const wxChar
* date
) 
2555     wxCHECK_MSG( date
, (wxChar 
*)NULL
, _T("NULL pointer in wxDateTime::Parse") ); 
2557     const wxChar 
*p 
= date
; 
2558     const wxChar 
*comma 
= wxStrchr(p
, _T(',')); 
2561         // the part before comma is the weekday 
2563         // skip it for now - we don't use but might check that it really 
2564         // corresponds to the specfied date 
2567         if ( *p 
!= _T(' ') ) 
2569             wxLogDebug(_T("no space after weekday in RFC822 time spec")); 
2571             return (wxChar 
*)NULL
; 
2577     // the following 1 or 2 digits are the day number 
2578     if ( !wxIsdigit(*p
) ) 
2580         wxLogDebug(_T("day number expected in RFC822 time spec, none found")); 
2582         return (wxChar 
*)NULL
; 
2585     wxDateTime_t day 
= (wxDateTime_t
)(*p
++ - _T('0')); 
2586     if ( wxIsdigit(*p
) ) 
2589         day 
= (wxDateTime_t
)(day 
+ (*p
++ - _T('0'))); 
2592     if ( *p
++ != _T(' ') ) 
2594         return (wxChar 
*)NULL
; 
2597     // the following 3 letters specify the month 
2598     wxString 
monName(p
, 3); 
2600     if ( monName 
== _T("Jan") ) 
2602     else if ( monName 
== _T("Feb") ) 
2604     else if ( monName 
== _T("Mar") ) 
2606     else if ( monName 
== _T("Apr") ) 
2608     else if ( monName 
== _T("May") ) 
2610     else if ( monName 
== _T("Jun") ) 
2612     else if ( monName 
== _T("Jul") ) 
2614     else if ( monName 
== _T("Aug") ) 
2616     else if ( monName 
== _T("Sep") ) 
2618     else if ( monName 
== _T("Oct") ) 
2620     else if ( monName 
== _T("Nov") ) 
2622     else if ( monName 
== _T("Dec") ) 
2626         wxLogDebug(_T("Invalid RFC 822 month name '%s'"), monName
.c_str()); 
2628         return (wxChar 
*)NULL
; 
2633     if ( *p
++ != _T(' ') ) 
2635         return (wxChar 
*)NULL
; 
2639     if ( !wxIsdigit(*p
) ) 
2642         return (wxChar 
*)NULL
; 
2645     int year 
= *p
++ - _T('0'); 
2647     if ( !wxIsdigit(*p
) ) 
2649         // should have at least 2 digits in the year 
2650         return (wxChar 
*)NULL
; 
2654     year 
+= *p
++ - _T('0'); 
2656     // is it a 2 digit year (as per original RFC 822) or a 4 digit one? 
2657     if ( wxIsdigit(*p
) ) 
2660         year 
+= *p
++ - _T('0'); 
2662         if ( !wxIsdigit(*p
) ) 
2664             // no 3 digit years please 
2665             return (wxChar 
*)NULL
; 
2669         year 
+= *p
++ - _T('0'); 
2672     if ( *p
++ != _T(' ') ) 
2674         return (wxChar 
*)NULL
; 
2677     // time is in the format hh:mm:ss and seconds are optional 
2678     if ( !wxIsdigit(*p
) ) 
2680         return (wxChar 
*)NULL
; 
2683     wxDateTime_t hour 
= (wxDateTime_t
)(*p
++ - _T('0')); 
2685     if ( !wxIsdigit(*p
) ) 
2687         return (wxChar 
*)NULL
; 
2691     hour 
= (wxDateTime_t
)(hour 
+ (*p
++ - _T('0'))); 
2693     if ( *p
++ != _T(':') ) 
2695         return (wxChar 
*)NULL
; 
2698     if ( !wxIsdigit(*p
) ) 
2700         return (wxChar 
*)NULL
; 
2703     wxDateTime_t min 
= (wxDateTime_t
)(*p
++ - _T('0')); 
2705     if ( !wxIsdigit(*p
) ) 
2707         return (wxChar 
*)NULL
; 
2711     min 
= (wxDateTime_t
)(min 
+ *p
++ - _T('0')); 
2713     wxDateTime_t sec 
= 0; 
2714     if ( *p
++ == _T(':') ) 
2716         if ( !wxIsdigit(*p
) ) 
2718             return (wxChar 
*)NULL
; 
2721         sec 
= (wxDateTime_t
)(*p
++ - _T('0')); 
2723         if ( !wxIsdigit(*p
) ) 
2725             return (wxChar 
*)NULL
; 
2729         sec 
= (wxDateTime_t
)(sec 
+ *p
++ - _T('0')); 
2732     if ( *p
++ != _T(' ') ) 
2734         return (wxChar 
*)NULL
; 
2737     // and now the interesting part: the timezone 
2739     if ( *p 
== _T('-') || *p 
== _T('+') ) 
2741         // the explicit offset given: it has the form of hhmm 
2742         bool plus 
= *p
++ == _T('+'); 
2744         if ( !wxIsdigit(*p
) || !wxIsdigit(*(p 
+ 1)) ) 
2746             return (wxChar 
*)NULL
; 
2750         offset 
= 60*(10*(*p 
- _T('0')) + (*(p 
+ 1) - _T('0'))); 
2754         if ( !wxIsdigit(*p
) || !wxIsdigit(*(p 
+ 1)) ) 
2756             return (wxChar 
*)NULL
; 
2760         offset 
+= 10*(*p 
- _T('0')) + (*(p 
+ 1) - _T('0')); 
2771         // the symbolic timezone given: may be either military timezone or one 
2772         // of standard abbreviations 
2775             // military: Z = UTC, J unused, A = -1, ..., Y = +12 
2776             static const int offsets
[26] = 
2778                 //A  B   C   D   E   F   G   H   I    J    K    L    M 
2779                 -1, -2, -3, -4, -5, -6, -7, -8, -9,   0, -10, -11, -12, 
2780                 //N  O   P   R   Q   S   T   U   V    W    Z    Y    Z 
2781                 +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, 0 
2784             if ( *p 
< _T('A') || *p 
> _T('Z') || *p 
== _T('J') ) 
2786                 wxLogDebug(_T("Invalid militaty timezone '%c'"), *p
); 
2788                 return (wxChar 
*)NULL
; 
2791             offset 
= offsets
[*p
++ - _T('A')]; 
2797             if ( tz 
== _T("UT") || tz 
== _T("UTC") || tz 
== _T("GMT") ) 
2799             else if ( tz 
== _T("AST") ) 
2800                 offset 
= AST 
- GMT0
; 
2801             else if ( tz 
== _T("ADT") ) 
2802                 offset 
= ADT 
- GMT0
; 
2803             else if ( tz 
== _T("EST") ) 
2804                 offset 
= EST 
- GMT0
; 
2805             else if ( tz 
== _T("EDT") ) 
2806                 offset 
= EDT 
- GMT0
; 
2807             else if ( tz 
== _T("CST") ) 
2808                 offset 
= CST 
- GMT0
; 
2809             else if ( tz 
== _T("CDT") ) 
2810                 offset 
= CDT 
- GMT0
; 
2811             else if ( tz 
== _T("MST") ) 
2812                 offset 
= MST 
- GMT0
; 
2813             else if ( tz 
== _T("MDT") ) 
2814                 offset 
= MDT 
- GMT0
; 
2815             else if ( tz 
== _T("PST") ) 
2816                 offset 
= PST 
- GMT0
; 
2817             else if ( tz 
== _T("PDT") ) 
2818                 offset 
= PDT 
- GMT0
; 
2821                 wxLogDebug(_T("Unknown RFC 822 timezone '%s'"), p
); 
2823                 return (wxChar 
*)NULL
; 
2833     // the spec was correct 
2834     Set(day
, mon
, year
, hour
, min
, sec
); 
2835     MakeTimezone((wxDateTime_t
)(60*offset
)); 
2842 // Get's current locale's date formatting string and stores it in fmt if 
2843 // the locale is set; otherwise or in case of failure, leaves fmt unchanged 
2844 static void GetLocaleDateFormat(wxString 
*fmt
) 
2846     // there is no setlocale() under Windows CE, so just always query the 
2849     if ( strcmp(setlocale(LC_ALL
, NULL
), "C") != 0 ) 
2852         // The locale was programatically set to non-C. We assume that this was 
2853         // done using wxLocale, in which case thread's current locale is also 
2854         // set to correct LCID value and we can use GetLocaleInfo to determine 
2855         // the correct formatting string: 
2857         LCID lcid 
= LOCALE_USER_DEFAULT
; 
2859         LCID lcid 
= GetThreadLocale(); 
2861         wxChar delim
[5]; // fields deliminer, 4 chars max 
2862         if ( GetLocaleInfo(lcid
, LOCALE_SDATE
, delim
, 5) ) 
2864             wxChar centurybuf
[2]; // use %y or %Y, 1 char max 
2865             wxChar century 
= 'y'; 
2866             if ( GetLocaleInfo(lcid
, LOCALE_ICENTURY
, centurybuf
, 2) ) 
2868                 if ( centurybuf
[0] == _T('1') ) 
2870                 // else 'y' as above 
2873             wxChar order
[2]; // order code, 1 char max 
2874             if ( GetLocaleInfo(lcid
, LOCALE_IDATE
, order
, 2) ) 
2876                 if ( order
[0] == _T('0') ) // M-D-Y 
2878                     *fmt 
= wxString::Format(_T("%%m%s%%d%s%%%c"), 
2879                                             delim
, delim
, century
); 
2881                 else if ( order
[0] == _T('1') ) // D-M-Y 
2883                     *fmt 
= wxString::Format(_T("%%d%s%%m%s%%%c"), 
2884                                             delim
, delim
, century
); 
2886                 else if ( order
[0] == _T('2') ) // Y-M-D 
2888                     *fmt 
= wxString::Format(_T("%%%c%s%%m%s%%d"), 
2889                                             century
, delim
, delim
); 
2893                     wxFAIL_MSG(_T("unexpected GetLocaleInfo return value")); 
2897         // if we failed, leave fmtDate value unchanged and 
2898         // try our luck with the default set above 
2902 #endif // __WINDOWS__ 
2904 const wxChar 
*wxDateTime::ParseFormat(const wxChar 
*date
, 
2905                                       const wxChar 
*format
, 
2906                                       const wxDateTime
& dateDef
) 
2908     wxCHECK_MSG( date 
&& format
, (wxChar 
*)NULL
, 
2909                  _T("NULL pointer in wxDateTime::ParseFormat()") ); 
2914     // what fields have we found? 
2915     bool haveWDay 
= false, 
2924     bool hourIsIn12hFormat 
= false, // or in 24h one? 
2925          isPM 
= false;              // AM by default 
2927     // and the value of the items we have (init them to get rid of warnings) 
2928     wxDateTime_t sec 
= 0, 
2931     WeekDay wday 
= Inv_WeekDay
; 
2932     wxDateTime_t yday 
= 0, 
2934     wxDateTime::Month mon 
= Inv_Month
; 
2937     const wxChar 
*input 
= date
; 
2938     for ( const wxChar 
*fmt 
= format
; *fmt
; fmt
++ ) 
2940         if ( *fmt 
!= _T('%') ) 
2942             if ( wxIsspace(*fmt
) ) 
2944                 // a white space in the format string matches 0 or more white 
2945                 // spaces in the input 
2946                 while ( wxIsspace(*input
) ) 
2953                 // any other character (not whitespace, not '%') must be 
2954                 // matched by itself in the input 
2955                 if ( *input
++ != *fmt 
) 
2958                     return (wxChar 
*)NULL
; 
2962             // done with this format char 
2966         // start of a format specification 
2968         // parse the optional width 
2970         while ( wxIsdigit(*++fmt
) ) 
2973             width 
+= *fmt 
- _T('0'); 
2976         // the default widths for the various fields 
2981                 case _T('Y'):               // year has 4 digits 
2985                 case _T('j'):               // day of year has 3 digits 
2986                 case _T('l'):               // milliseconds have 3 digits 
2990                 case _T('w'):               // week day as number has only one 
2995                     // default for all other fields 
3000         // then the format itself 
3003             case _T('a'):       // a weekday name 
3006                     int flag 
= *fmt 
== _T('a') ? Name_Abbr 
: Name_Full
; 
3007                     wday 
= GetWeekDayFromName(GetAlphaToken(input
), flag
); 
3008                     if ( wday 
== Inv_WeekDay 
) 
3011                         return (wxChar 
*)NULL
; 
3017             case _T('b'):       // a month name 
3020                     int flag 
= *fmt 
== _T('b') ? Name_Abbr 
: Name_Full
; 
3021                     mon 
= GetMonthFromName(GetAlphaToken(input
), flag
); 
3022                     if ( mon 
== Inv_Month 
) 
3025                         return (wxChar 
*)NULL
; 
3031             case _T('c'):       // locale default date and time  representation 
3035                     // this is the format which corresponds to ctime() output 
3036                     // and strptime("%c") should parse it, so try it first 
3037                     static const wxChar 
*fmtCtime 
= _T("%a %b %d %H:%M:%S %Y"); 
3039                     const wxChar 
*result 
= dt
.ParseFormat(input
, fmtCtime
); 
3042                         result 
= dt
.ParseFormat(input
, _T("%x %X")); 
3047                         result 
= dt
.ParseFormat(input
, _T("%X %x")); 
3052                         // we've tried everything and still no match 
3053                         return (wxChar 
*)NULL
; 
3058                     haveDay 
= haveMon 
= haveYear 
= 
3059                     haveHour 
= haveMin 
= haveSec 
= true; 
3073             case _T('d'):       // day of a month (01-31) 
3074                 if ( !GetNumericToken(width
, input
, &num
) || 
3075                         (num 
> 31) || (num 
< 1) ) 
3078                     return (wxChar 
*)NULL
; 
3081                 // we can't check whether the day range is correct yet, will 
3082                 // do it later - assume ok for now 
3084                 mday 
= (wxDateTime_t
)num
; 
3087             case _T('H'):       // hour in 24h format (00-23) 
3088                 if ( !GetNumericToken(width
, input
, &num
) || (num 
> 23) ) 
3091                     return (wxChar 
*)NULL
; 
3095                 hour 
= (wxDateTime_t
)num
; 
3098             case _T('I'):       // hour in 12h format (01-12) 
3099                 if ( !GetNumericToken(width
, input
, &num
) || !num 
|| (num 
> 12) ) 
3102                     return (wxChar 
*)NULL
; 
3106                 hourIsIn12hFormat 
= true; 
3107                 hour 
= (wxDateTime_t
)(num 
% 12);        // 12 should be 0 
3110             case _T('j'):       // day of the year 
3111                 if ( !GetNumericToken(width
, input
, &num
) || !num 
|| (num 
> 366) ) 
3114                     return (wxChar 
*)NULL
; 
3118                 yday 
= (wxDateTime_t
)num
; 
3121             case _T('m'):       // month as a number (01-12) 
3122                 if ( !GetNumericToken(width
, input
, &num
) || !num 
|| (num 
> 12) ) 
3125                     return (wxChar 
*)NULL
; 
3129                 mon 
= (Month
)(num 
- 1); 
3132             case _T('M'):       // minute as a decimal number (00-59) 
3133                 if ( !GetNumericToken(width
, input
, &num
) || (num 
> 59) ) 
3136                     return (wxChar 
*)NULL
; 
3140                 min 
= (wxDateTime_t
)num
; 
3143             case _T('p'):       // AM or PM string 
3145                     wxString am
, pm
, token 
= GetAlphaToken(input
); 
3147                     GetAmPmStrings(&am
, &pm
); 
3148                     if (am
.empty() && pm
.empty()) 
3149                         return (wxChar 
*)NULL
;  // no am/pm strings defined 
3150                     if ( token
.CmpNoCase(pm
) == 0 ) 
3154                     else if ( token
.CmpNoCase(am
) != 0 ) 
3157                         return (wxChar 
*)NULL
; 
3162             case _T('r'):       // time as %I:%M:%S %p 
3165                     input 
= dt
.ParseFormat(input
, _T("%I:%M:%S %p")); 
3169                         return (wxChar 
*)NULL
; 
3172                     haveHour 
= haveMin 
= haveSec 
= true; 
3181             case _T('R'):       // time as %H:%M 
3184                     input 
= dt
.ParseFormat(input
, _T("%H:%M")); 
3188                         return (wxChar 
*)NULL
; 
3191                     haveHour 
= haveMin 
= true; 
3198             case _T('S'):       // second as a decimal number (00-61) 
3199                 if ( !GetNumericToken(width
, input
, &num
) || (num 
> 61) ) 
3202                     return (wxChar 
*)NULL
; 
3206                 sec 
= (wxDateTime_t
)num
; 
3209             case _T('T'):       // time as %H:%M:%S 
3212                     input 
= dt
.ParseFormat(input
, _T("%H:%M:%S")); 
3216                         return (wxChar 
*)NULL
; 
3219                     haveHour 
= haveMin 
= haveSec 
= true; 
3228             case _T('w'):       // weekday as a number (0-6), Sunday = 0 
3229                 if ( !GetNumericToken(width
, input
, &num
) || (wday 
> 6) ) 
3232                     return (wxChar 
*)NULL
; 
3236                 wday 
= (WeekDay
)num
; 
3239             case _T('x'):       // locale default date representation 
3240 #ifdef HAVE_STRPTIME 
3241                 // try using strptime() -- it may fail even if the input is 
3242                 // correct but the date is out of range, so we will fall back 
3243                 // to our generic code anyhow 
3247                     const wxChar 
*result 
= CallStrptime(input
, "%x", &tm
); 
3252                         haveDay 
= haveMon 
= haveYear 
= true; 
3254                         year 
= 1900 + tm
.tm_year
; 
3255                         mon 
= (Month
)tm
.tm_mon
; 
3261 #endif // HAVE_STRPTIME 
3266                     wxString fmtDate
, fmtDateAlt
; 
3268                     if ( IsWestEuropeanCountry(GetCountry()) || 
3269                          GetCountry() == Russia 
) 
3271                         fmtDate 
= _T("%d/%m/%y"); 
3272                         fmtDateAlt 
= _T("%m/%d/%y"); 
3276                         fmtDate 
= _T("%m/%d/%y"); 
3277                         fmtDateAlt 
= _T("%d/%m/%y"); 
3281                     // The above doesn't work for all locales, try to query 
3282                     // Windows for the right way of formatting the date: 
3283                     GetLocaleDateFormat(&fmtDate
); 
3286                     const wxChar 
*result 
= dt
.ParseFormat(input
, fmtDate
); 
3290                         // ok, be nice and try another one 
3291                         result 
= dt
.ParseFormat(input
, fmtDateAlt
); 
3297                         return (wxChar 
*)NULL
; 
3302                     haveDay 
= haveMon 
= haveYear 
= true; 
3313             case _T('X'):       // locale default time representation 
3314 #ifdef HAVE_STRPTIME 
3316                     // use strptime() to do it for us (FIXME !Unicode friendly) 
3318                     input 
= CallStrptime(input
, "%X", &tm
); 
3321                         return (wxChar 
*)NULL
; 
3324                     haveHour 
= haveMin 
= haveSec 
= true; 
3330 #else // !HAVE_STRPTIME 
3331                 // TODO under Win32 we can query the LOCALE_ITIME system 
3332                 //      setting which says whether the default time format is 
3335                     // try to parse what follows as "%H:%M:%S" and, if this 
3336                     // fails, as "%I:%M:%S %p" - this should catch the most 
3340                     const wxChar 
*result 
= dt
.ParseFormat(input
, _T("%T")); 
3343                         result 
= dt
.ParseFormat(input
, _T("%r")); 
3349                         return (wxChar 
*)NULL
; 
3352                     haveHour 
= haveMin 
= haveSec 
= true; 
3361 #endif // HAVE_STRPTIME/!HAVE_STRPTIME 
3364             case _T('y'):       // year without century (00-99) 
3365                 if ( !GetNumericToken(width
, input
, &num
) || (num 
> 99) ) 
3368                     return (wxChar 
*)NULL
; 
3373                 // TODO should have an option for roll over date instead of 
3374                 //      hard coding it here 
3375                 year 
= (num 
> 30 ? 1900 : 2000) + (wxDateTime_t
)num
; 
3378             case _T('Y'):       // year with century 
3379                 if ( !GetNumericToken(width
, input
, &num
) ) 
3382                     return (wxChar 
*)NULL
; 
3386                 year 
= (wxDateTime_t
)num
; 
3389             case _T('Z'):       // timezone name 
3390                 wxFAIL_MSG(_T("TODO")); 
3393             case _T('%'):       // a percent sign 
3394                 if ( *input
++ != _T('%') ) 
3397                     return (wxChar 
*)NULL
; 
3401             case 0:             // the end of string 
3402                 wxFAIL_MSG(_T("unexpected format end")); 
3406             default:            // not a known format spec 
3407                 return (wxChar 
*)NULL
; 
3411     // format matched, try to construct a date from what we have now 
3413     if ( dateDef
.IsValid() ) 
3415         // take this date as default 
3416         tmDef 
= dateDef
.GetTm(); 
3418     else if ( IsValid() ) 
3420         // if this date is valid, don't change it 
3425         // no default and this date is invalid - fall back to Today() 
3426         tmDef 
= Today().GetTm(); 
3437     // TODO we don't check here that the values are consistent, if both year 
3438     //      day and month/day were found, we just ignore the year day and we 
3439     //      also always ignore the week day 
3440     if ( haveMon 
&& haveDay 
) 
3442         if ( mday 
> GetNumOfDaysInMonth(tm
.year
, mon
) ) 
3444             wxLogDebug(_T("bad month day in wxDateTime::ParseFormat")); 
3446             return (wxChar 
*)NULL
; 
3452     else if ( haveYDay 
) 
3454         if ( yday 
> GetNumberOfDays(tm
.year
) ) 
3456             wxLogDebug(_T("bad year day in wxDateTime::ParseFormat")); 
3458             return (wxChar 
*)NULL
; 
3461         Tm tm2 
= wxDateTime(1, Jan
, tm
.year
).SetToYearDay(yday
).GetTm(); 
3468     if ( haveHour 
&& hourIsIn12hFormat 
&& isPM 
) 
3470         // translate to 24hour format 
3473     //else: either already in 24h format or no translation needed 
3493     // finally check that the week day is consistent -- if we had it 
3494     if ( haveWDay 
&& GetWeekDay() != wday 
) 
3496         wxLogDebug(_T("inconsistsnet week day in wxDateTime::ParseFormat()")); 
3504 const wxChar 
*wxDateTime::ParseDateTime(const wxChar 
*date
) 
3506     wxCHECK_MSG( date
, (wxChar 
*)NULL
, _T("NULL pointer in wxDateTime::Parse") ); 
3508     // Set to current day and hour, so strings like '14:00' becomes today at 
3509     // 14, not some other random date 
3510     wxDateTime dtDate 
= wxDateTime::Today(); 
3511     wxDateTime dtTime 
= wxDateTime::Today(); 
3513     const wxChar
* pchTime
; 
3515     // Try to parse the beginning of the string as a date 
3516     const wxChar
* pchDate 
= dtDate
.ParseDate(date
); 
3518     // We got a date in the beginning, see if there is a time specified after the date 
3521         // Skip spaces, as the ParseTime() function fails on spaces 
3522         while ( wxIsspace(*pchDate
) ) 
3525         pchTime 
= dtTime
.ParseTime(pchDate
); 
3527     else // no date in the beginning 
3529         // check and see if we have a time followed by a date 
3530         pchTime 
= dtTime
.ParseTime(date
); 
3533             while ( wxIsspace(*pchTime
) ) 
3536             pchDate 
= dtDate
.ParseDate(pchTime
); 
3540     // If we have a date specified, set our own data to the same date 
3541     if ( !pchDate 
|| !pchTime 
) 
3544     Set(dtDate
.GetDay(), dtDate
.GetMonth(), dtDate
.GetYear(), 
3545         dtTime
.GetHour(), dtTime
.GetMinute(), dtTime
.GetSecond(), 
3546         dtTime
.GetMillisecond()); 
3548     // Return endpoint of scan 
3549     return pchDate 
> pchTime 
? pchDate 
: pchTime
; 
3552 const wxChar 
*wxDateTime::ParseDate(const wxChar 
*date
) 
3554     // this is a simplified version of ParseDateTime() which understands only 
3555     // "today" (for wxDate compatibility) and digits only otherwise (and not 
3556     // all esoteric constructions ParseDateTime() knows about) 
3558     wxCHECK_MSG( date
, (wxChar 
*)NULL
, _T("NULL pointer in wxDateTime::Parse") ); 
3560     const wxChar 
*p 
= date
; 
3561     while ( wxIsspace(*p
) ) 
3564     // some special cases 
3568         int dayDiffFromToday
; 
3571         { wxTRANSLATE("today"),             0 }, 
3572         { wxTRANSLATE("yesterday"),        -1 }, 
3573         { wxTRANSLATE("tomorrow"),          1 }, 
3576     for ( size_t n 
= 0; n 
< WXSIZEOF(literalDates
); n
++ ) 
3578         wxString date 
= wxGetTranslation(literalDates
[n
].str
); 
3579         size_t len 
= date
.length(); 
3580         if ( wxStrlen(p
) >= len 
) 
3582             wxString 
str(p
, len
); 
3583             if ( str
.CmpNoCase(date
) == 0 ) 
3585                 // nothing can follow this, so stop here 
3588                 int dayDiffFromToday 
= literalDates
[n
].dayDiffFromToday
; 
3590                 if ( dayDiffFromToday 
) 
3592                     *this += wxDateSpan::Days(dayDiffFromToday
); 
3600     // We try to guess what we have here: for each new (numeric) token, we 
3601     // determine if it can be a month, day or a year. Of course, there is an 
3602     // ambiguity as some numbers may be days as well as months, so we also 
3603     // have the ability to back track. 
3606     bool haveDay 
= false,       // the months day? 
3607          haveWDay 
= false,      // the day of week? 
3608          haveMon 
= false,       // the month? 
3609          haveYear 
= false;      // the year? 
3611     // and the value of the items we have (init them to get rid of warnings) 
3612     WeekDay wday 
= Inv_WeekDay
; 
3613     wxDateTime_t day 
= 0; 
3614     wxDateTime::Month mon 
= Inv_Month
; 
3617     // tokenize the string 
3619     static const wxChar 
*dateDelimiters 
= _T(".,/-\t\r\n "); 
3620     wxStringTokenizer 
tok(p
, dateDelimiters
); 
3621     while ( tok
.HasMoreTokens() ) 
3623         wxString token 
= tok
.GetNextToken(); 
3629         if ( token
.ToULong(&val
) ) 
3631             // guess what this number is 
3637             if ( !haveMon 
&& val 
> 0 && val 
<= 12 ) 
3639                 // assume it is month 
3642             else // not the month 
3646                     // this can only be the year 
3649                 else // may be either day or year 
3651                     wxDateTime_t max_days 
= (wxDateTime_t
)( 
3653                         ? GetNumOfDaysInMonth(haveYear 
? year 
: Inv_Year
, mon
) 
3658                     if ( (val 
== 0) || (val 
> (unsigned long)max_days
) ) 
3663                     else // yes, suppose it's the day 
3677                 year 
= (wxDateTime_t
)val
; 
3686                 day 
= (wxDateTime_t
)val
; 
3692                 mon 
= (Month
)(val 
- 1); 
3695         else // not a number 
3697             // be careful not to overwrite the current mon value 
3698             Month mon2 
= GetMonthFromName(token
, Name_Full 
| Name_Abbr
); 
3699             if ( mon2 
!= Inv_Month 
) 
3704                     // but we already have a month - maybe we guessed wrong? 
3707                         // no need to check in month range as always < 12, but 
3708                         // the days are counted from 1 unlike the months 
3709                         day 
= (wxDateTime_t
)(mon 
+ 1); 
3714                         // could possible be the year (doesn't the year come 
3715                         // before the month in the japanese format?) (FIXME) 
3724             else // not a valid month name 
3726                 wday 
= GetWeekDayFromName(token
, Name_Full 
| Name_Abbr
); 
3727                 if ( wday 
!= Inv_WeekDay 
) 
3737                 else // not a valid weekday name 
3740                     static const wxChar 
*ordinals
[] = 
3742                         wxTRANSLATE("first"), 
3743                         wxTRANSLATE("second"), 
3744                         wxTRANSLATE("third"), 
3745                         wxTRANSLATE("fourth"), 
3746                         wxTRANSLATE("fifth"), 
3747                         wxTRANSLATE("sixth"), 
3748                         wxTRANSLATE("seventh"), 
3749                         wxTRANSLATE("eighth"), 
3750                         wxTRANSLATE("ninth"), 
3751                         wxTRANSLATE("tenth"), 
3752                         wxTRANSLATE("eleventh"), 
3753                         wxTRANSLATE("twelfth"), 
3754                         wxTRANSLATE("thirteenth"), 
3755                         wxTRANSLATE("fourteenth"), 
3756                         wxTRANSLATE("fifteenth"), 
3757                         wxTRANSLATE("sixteenth"), 
3758                         wxTRANSLATE("seventeenth"), 
3759                         wxTRANSLATE("eighteenth"), 
3760                         wxTRANSLATE("nineteenth"), 
3761                         wxTRANSLATE("twentieth"), 
3762                         // that's enough - otherwise we'd have problems with 
3763                         // composite (or not) ordinals 
3767                     for ( n 
= 0; n 
< WXSIZEOF(ordinals
); n
++ ) 
3769                         if ( token
.CmpNoCase(ordinals
[n
]) == 0 ) 
3775                     if ( n 
== WXSIZEOF(ordinals
) ) 
3777                         // stop here - something unknown 
3784                         // don't try anything here (as in case of numeric day 
3785                         // above) - the symbolic day spec should always 
3786                         // precede the month/year 
3792                     day 
= (wxDateTime_t
)(n 
+ 1); 
3797         nPosCur 
= tok
.GetPosition(); 
3800     // either no more tokens or the scan was stopped by something we couldn't 
3801     // parse - in any case, see if we can construct a date from what we have 
3802     if ( !haveDay 
&& !haveWDay 
) 
3804         wxLogDebug(_T("ParseDate: no day, no weekday hence no date.")); 
3806         return (wxChar 
*)NULL
; 
3809     if ( haveWDay 
&& (haveMon 
|| haveYear 
|| haveDay
) && 
3810          !(haveDay 
&& haveMon 
&& haveYear
) ) 
3812         // without adjectives (which we don't support here) the week day only 
3813         // makes sense completely separately or with the full date 
3814         // specification (what would "Wed 1999" mean?) 
3815         return (wxChar 
*)NULL
; 
3818     if ( !haveWDay 
&& haveYear 
&& !(haveDay 
&& haveMon
) ) 
3820         // may be we have month and day instead of day and year? 
3821         if ( haveDay 
&& !haveMon 
) 
3825                 // exchange day and month 
3826                 mon 
= (wxDateTime::Month
)(day 
- 1); 
3828                 // we're in the current year then 
3829                 if ( (year 
> 0) && (year 
<= (int)GetNumOfDaysInMonth(Inv_Year
, mon
)) ) 
3831                     day 
= (wxDateTime_t
)year
; 
3836                 //else: no, can't exchange, leave haveMon == false 
3842             // if we give the year, month and day must be given too 
3843             wxLogDebug(_T("ParseDate: day and month should be specified if year is.")); 
3845             return (wxChar 
*)NULL
; 
3851         mon 
= GetCurrentMonth(); 
3856         year 
= GetCurrentYear(); 
3861         Set(day
, mon
, year
); 
3865             // check that it is really the same 
3866             if ( GetWeekDay() != wday 
) 
3868                 // inconsistency detected 
3869                 wxLogDebug(_T("ParseDate: inconsistent day/weekday.")); 
3871                 return (wxChar 
*)NULL
; 
3879         SetToWeekDayInSameWeek(wday
); 
3882     // return the pointer to the first unparsed char 
3884     if ( nPosCur 
&& wxStrchr(dateDelimiters
, *(p 
- 1)) ) 
3886         // if we couldn't parse the token after the delimiter, put back the 
3887         // delimiter as well 
3894 const wxChar 
*wxDateTime::ParseTime(const wxChar 
*time
) 
3896     wxCHECK_MSG( time
, (wxChar 
*)NULL
, _T("NULL pointer in wxDateTime::Parse") ); 
3898     // first try some extra things 
3905         { wxTRANSLATE("noon"),      12 }, 
3906         { wxTRANSLATE("midnight"),  00 }, 
3910     for ( size_t n 
= 0; n 
< WXSIZEOF(stdTimes
); n
++ ) 
3912         wxString timeString 
= wxGetTranslation(stdTimes
[n
].name
); 
3913         size_t len 
= timeString
.length(); 
3914         if ( timeString
.CmpNoCase(wxString(time
, len
)) == 0 ) 
3916             // casts required by DigitalMars 
3917             Set(stdTimes
[n
].hour
, wxDateTime_t(0), wxDateTime_t(0)); 
3923     // try all time formats we may think about in the order from longest to 
3926     // 12hour with AM/PM? 
3927     const wxChar 
*result 
= ParseFormat(time
, _T("%I:%M:%S %p")); 
3931         // normally, it's the same, but why not try it? 
3932         result 
= ParseFormat(time
, _T("%H:%M:%S")); 
3937         // 12hour with AM/PM but without seconds? 
3938         result 
= ParseFormat(time
, _T("%I:%M %p")); 
3944         result 
= ParseFormat(time
, _T("%H:%M")); 
3949         // just the hour and AM/PM? 
3950         result 
= ParseFormat(time
, _T("%I %p")); 
3956         result 
= ParseFormat(time
, _T("%H")); 
3961         // parse the standard format: normally it is one of the formats above 
3962         // but it may be set to something completely different by the user 
3963         result 
= ParseFormat(time
, _T("%X")); 
3966     // TODO: parse timezones 
3971 // ---------------------------------------------------------------------------- 
3972 // Workdays and holidays support 
3973 // ---------------------------------------------------------------------------- 
3975 bool wxDateTime::IsWorkDay(Country 
WXUNUSED(country
)) const 
3977     return !wxDateTimeHolidayAuthority::IsHoliday(*this); 
3980 // ============================================================================ 
3982 // ============================================================================ 
3984 wxDateSpan WXDLLIMPEXP_BASE 
operator*(int n
, const wxDateSpan
& ds
) 
3987     return ds1
.Multiply(n
); 
3990 // ============================================================================ 
3992 // ============================================================================ 
3994 wxTimeSpan WXDLLIMPEXP_BASE 
operator*(int n
, const wxTimeSpan
& ts
) 
3996     return wxTimeSpan(ts
).Multiply(n
); 
3999 // this enum is only used in wxTimeSpan::Format() below but we can't declare 
4000 // it locally to the method as it provokes an internal compiler error in egcs 
4001 // 2.91.60 when building with -O2 
4012 // not all strftime(3) format specifiers make sense here because, for example, 
4013 // a time span doesn't have a year nor a timezone 
4015 // Here are the ones which are supported (all of them are supported by strftime 
4017 //  %H          hour in 24 hour format 
4018 //  %M          minute (00 - 59) 
4019 //  %S          second (00 - 59) 
4022 // Also, for MFC CTimeSpan compatibility, we support 
4023 //  %D          number of days 
4025 // And, to be better than MFC :-), we also have 
4026 //  %E          number of wEeks 
4027 //  %l          milliseconds (000 - 999) 
4028 wxString 
wxTimeSpan::Format(const wxChar 
*format
) const 
4030     wxCHECK_MSG( format
, wxEmptyString
, _T("NULL format in wxTimeSpan::Format") ); 
4033     str
.Alloc(wxStrlen(format
)); 
4035     // Suppose we have wxTimeSpan ts(1 /* hour */, 2 /* min */, 3 /* sec */) 
4037     // Then, of course, ts.Format("%H:%M:%S") must return "01:02:03", but the 
4038     // question is what should ts.Format("%S") do? The code here returns "3273" 
4039     // in this case (i.e. the total number of seconds, not just seconds % 60) 
4040     // because, for me, this call means "give me entire time interval in 
4041     // seconds" and not "give me the seconds part of the time interval" 
4043     // If we agree that it should behave like this, it is clear that the 
4044     // interpretation of each format specifier depends on the presence of the 
4045     // other format specs in the string: if there was "%H" before "%M", we 
4046     // should use GetMinutes() % 60, otherwise just GetMinutes() &c 
4048     // we remember the most important unit found so far 
4049     TimeSpanPart partBiggest 
= Part_MSec
; 
4051     for ( const wxChar 
*pch 
= format
; *pch
; pch
++ ) 
4055         if ( ch 
== _T('%') ) 
4057             // the start of the format specification of the printf() below 
4058             wxString fmtPrefix 
= _T('%'); 
4063             ch 
= *++pch
;    // get the format spec char 
4067                     wxFAIL_MSG( _T("invalid format character") ); 
4073                     // skip the part below switch 
4078                     if ( partBiggest 
< Part_Day 
) 
4084                         partBiggest 
= Part_Day
; 
4089                     partBiggest 
= Part_Week
; 
4095                     if ( partBiggest 
< Part_Hour 
) 
4101                         partBiggest 
= Part_Hour
; 
4104                     fmtPrefix 
+= _T("02"); 
4108                     n 
= GetMilliseconds().ToLong(); 
4109                     if ( partBiggest 
< Part_MSec 
) 
4113                     //else: no need to reset partBiggest to Part_MSec, it is 
4114                     //      the least significant one anyhow 
4116                     fmtPrefix 
+= _T("03"); 
4121                     if ( partBiggest 
< Part_Min 
) 
4127                         partBiggest 
= Part_Min
; 
4130                     fmtPrefix 
+= _T("02"); 
4134                     n 
= GetSeconds().ToLong(); 
4135                     if ( partBiggest 
< Part_Sec 
) 
4141                         partBiggest 
= Part_Sec
; 
4144                     fmtPrefix 
+= _T("02"); 
4148             str 
+= wxString::Format(fmtPrefix 
+ _T("ld"), n
); 
4152             // normal character, just copy 
4160 // ============================================================================ 
4161 // wxDateTimeHolidayAuthority and related classes 
4162 // ============================================================================ 
4164 #include "wx/arrimpl.cpp" 
4166 WX_DEFINE_OBJARRAY(wxDateTimeArray
); 
4168 static int wxCMPFUNC_CONV
 
4169 wxDateTimeCompareFunc(wxDateTime 
**first
, wxDateTime 
**second
) 
4171     wxDateTime dt1 
= **first
, 
4174     return dt1 
== dt2 
? 0 : dt1 
< dt2 
? -1 : +1; 
4177 // ---------------------------------------------------------------------------- 
4178 // wxDateTimeHolidayAuthority 
4179 // ---------------------------------------------------------------------------- 
4181 wxHolidayAuthoritiesArray 
wxDateTimeHolidayAuthority::ms_authorities
; 
4184 bool wxDateTimeHolidayAuthority::IsHoliday(const wxDateTime
& dt
) 
4186     size_t count 
= ms_authorities
.size(); 
4187     for ( size_t n 
= 0; n 
< count
; n
++ ) 
4189         if ( ms_authorities
[n
]->DoIsHoliday(dt
) ) 
4200 wxDateTimeHolidayAuthority::GetHolidaysInRange(const wxDateTime
& dtStart
, 
4201                                                const wxDateTime
& dtEnd
, 
4202                                                wxDateTimeArray
& holidays
) 
4204     wxDateTimeArray hol
; 
4208     size_t count 
= ms_authorities
.size(); 
4209     for ( size_t nAuth 
= 0; nAuth 
< count
; nAuth
++ ) 
4211         ms_authorities
[nAuth
]->DoGetHolidaysInRange(dtStart
, dtEnd
, hol
); 
4213         WX_APPEND_ARRAY(holidays
, hol
); 
4216     holidays
.Sort(wxDateTimeCompareFunc
); 
4218     return holidays
.size(); 
4222 void wxDateTimeHolidayAuthority::ClearAllAuthorities() 
4224     WX_CLEAR_ARRAY(ms_authorities
); 
4228 void wxDateTimeHolidayAuthority::AddAuthority(wxDateTimeHolidayAuthority 
*auth
) 
4230     ms_authorities
.push_back(auth
); 
4233 wxDateTimeHolidayAuthority::~wxDateTimeHolidayAuthority() 
4235     // required here for Darwin 
4238 // ---------------------------------------------------------------------------- 
4239 // wxDateTimeWorkDays 
4240 // ---------------------------------------------------------------------------- 
4242 bool wxDateTimeWorkDays::DoIsHoliday(const wxDateTime
& dt
) const 
4244     wxDateTime::WeekDay wd 
= dt
.GetWeekDay(); 
4246     return (wd 
== wxDateTime::Sun
) || (wd 
== wxDateTime::Sat
); 
4249 size_t wxDateTimeWorkDays::DoGetHolidaysInRange(const wxDateTime
& dtStart
, 
4250                                                 const wxDateTime
& dtEnd
, 
4251                                                 wxDateTimeArray
& holidays
) const 
4253     if ( dtStart 
> dtEnd 
) 
4255         wxFAIL_MSG( _T("invalid date range in GetHolidaysInRange") ); 
4262     // instead of checking all days, start with the first Sat after dtStart and 
4263     // end with the last Sun before dtEnd 
4264     wxDateTime dtSatFirst 
= dtStart
.GetNextWeekDay(wxDateTime::Sat
), 
4265                dtSatLast 
= dtEnd
.GetPrevWeekDay(wxDateTime::Sat
), 
4266                dtSunFirst 
= dtStart
.GetNextWeekDay(wxDateTime::Sun
), 
4267                dtSunLast 
= dtEnd
.GetPrevWeekDay(wxDateTime::Sun
), 
4270     for ( dt 
= dtSatFirst
; dt 
<= dtSatLast
; dt 
+= wxDateSpan::Week() ) 
4275     for ( dt 
= dtSunFirst
; dt 
<= dtSunLast
; dt 
+= wxDateSpan::Week() ) 
4280     return holidays
.GetCount(); 
4283 // ============================================================================ 
4284 // other helper functions 
4285 // ============================================================================ 
4287 // ---------------------------------------------------------------------------- 
4288 // iteration helpers: can be used to write a for loop over enum variable like 
4290 //  for ( m = wxDateTime::Jan; m < wxDateTime::Inv_Month; wxNextMonth(m) ) 
4291 // ---------------------------------------------------------------------------- 
4293 WXDLLIMPEXP_BASE 
void wxNextMonth(wxDateTime::Month
& m
) 
4295     wxASSERT_MSG( m 
< wxDateTime::Inv_Month
, _T("invalid month") ); 
4297     // no wrapping or the for loop above would never end! 
4298     m 
= (wxDateTime::Month
)(m 
+ 1); 
4301 WXDLLIMPEXP_BASE 
void wxPrevMonth(wxDateTime::Month
& m
) 
4303     wxASSERT_MSG( m 
< wxDateTime::Inv_Month
, _T("invalid month") ); 
4305     m 
= m 
== wxDateTime::Jan 
? wxDateTime::Inv_Month
 
4306                              : (wxDateTime::Month
)(m 
- 1); 
4309 WXDLLIMPEXP_BASE 
void wxNextWDay(wxDateTime::WeekDay
& wd
) 
4311     wxASSERT_MSG( wd 
< wxDateTime::Inv_WeekDay
, _T("invalid week day") ); 
4313     // no wrapping or the for loop above would never end! 
4314     wd 
= (wxDateTime::WeekDay
)(wd 
+ 1); 
4317 WXDLLIMPEXP_BASE 
void wxPrevWDay(wxDateTime::WeekDay
& wd
) 
4319     wxASSERT_MSG( wd 
< wxDateTime::Inv_WeekDay
, _T("invalid week day") ); 
4321     wd 
= wd 
== wxDateTime::Sun 
? wxDateTime::Inv_WeekDay
 
4322                                : (wxDateTime::WeekDay
)(wd 
- 1); 
4325 #endif // wxUSE_DATETIME