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 /////////////////////////////////////////////////////////////////////////////// 
  20  * Implementation notes: 
  22  * 1. the time is stored as a 64bit integer containing the signed number of 
  23  *    milliseconds since Jan 1. 1970 (the Unix Epoch) - so it is always 
  26  * 2. the range is thus something about 580 million years, but due to current 
  27  *    algorithms limitations, only dates from Nov 24, 4714BC are handled 
  29  * 3. standard ANSI C functions are used to do time calculations whenever 
  30  *    possible, i.e. when the date is in the range Jan 1, 1970 to 2038 
  32  * 4. otherwise, the calculations are done by converting the date to/from JDN 
  33  *    first (the range limitation mentioned above comes from here: the 
  34  *    algorithm used by Scott E. Lee's code only works for positive JDNs, more 
  37  * 5. the object constructed for the given DD-MM-YYYY HH:MM:SS corresponds to 
  38  *    this moment in local time and may be converted to the object 
  39  *    corresponding to the same date/time in another time zone by using 
  42  * 6. the conversions to the current (or any other) timezone are done when the 
  43  *    internal time representation is converted to the broken-down one in 
  47 // ============================================================================ 
  49 // ============================================================================ 
  51 // ---------------------------------------------------------------------------- 
  53 // ---------------------------------------------------------------------------- 
  55 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  56     #pragma implementation "datetime.h" 
  59 // For compilers that support precompilation, includes "wx.h". 
  60 #include "wx/wxprec.h" 
  66 #if !defined(wxUSE_DATETIME) || wxUSE_DATETIME 
  69     #include "wx/string.h" 
  74 #include "wx/thread.h" 
  75 #include "wx/tokenzr.h" 
  76 #include "wx/module.h" 
  80 #include "wx/datetime.h" 
  81 #include "wx/stopwatch.h"           // for wxGetLocalTimeMillis() 
  83 const long wxDateTime::TIME_T_FACTOR 
= 1000l; 
  85 #if wxUSE_EXTENDED_RTTI 
  87 template<> void wxStringReadValue(const wxString 
&s 
, wxDateTime 
&data 
) 
  89     data
.ParseFormat(s
,wxT("%Y-%m-%d %H:%M:%S")) ; 
  92 template<> void wxStringWriteValue(wxString 
&s 
, const wxDateTime 
&data 
) 
  94     s 
= data
.Format(wxT("%Y-%m-%d %H:%M:%S")) ; 
  97 wxCUSTOM_TYPE_INFO(wxDateTime
, wxToStringConverter
<wxDateTime
> , wxFromStringConverter
<wxDateTime
>) 
 102 // ---------------------------------------------------------------------------- 
 103 // conditional compilation 
 104 // ---------------------------------------------------------------------------- 
 106 #if defined(HAVE_STRPTIME) && defined(__GLIBC__) && \ 
 107         ((__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0)) 
 108     // glibc 2.0.7 strptime() is broken - the following snippet causes it to 
 109     // crash (instead of just failing): 
 111     //      strncpy(buf, "Tue Dec 21 20:25:40 1999", 128); 
 112     //      strptime(buf, "%x", &tm); 
 116 #endif // broken strptime() 
 118 #if defined(__MWERKS__) && wxUSE_UNICODE 
 122 #if !defined(WX_TIMEZONE) && !defined(WX_GMTOFF_IN_TM) 
 123     #if defined(__WXPALMOS__) 
 124         #define WX_GMTOFF_IN_TM 
 125     #elif defined(__BORLANDC__) || defined(__MINGW32__) || defined(__VISAGECPP__) 
 126         #define WX_TIMEZONE _timezone 
 127     #elif defined(__MWERKS__) 
 128         long wxmw_timezone 
= 28800; 
 129         #define WX_TIMEZONE wxmw_timezone 
 130     #elif defined(__DJGPP__) || defined(__WINE__) 
 131         #include <sys/timeb.h> 
 133         static long wxGetTimeZone() 
 135             static long timezone 
= MAXLONG
; // invalid timezone 
 136             if (timezone 
== MAXLONG
) 
 140                 timezone 
= tb
.timezone
; 
 144         #define WX_TIMEZONE wxGetTimeZone() 
 145     #elif defined(__DARWIN__) 
 146         #define WX_GMTOFF_IN_TM 
 147     #else // unknown platform - try timezone 
 148         #define WX_TIMEZONE timezone 
 150 #endif // !WX_TIMEZONE && !WX_GMTOFF_IN_TM 
 152 // ---------------------------------------------------------------------------- 
 154 // ---------------------------------------------------------------------------- 
 156 // debugging helper: just a convenient replacement of wxCHECK() 
 157 #define wxDATETIME_CHECK(expr, msg)     \ 
 161             *this = wxInvalidDateTime;  \ 
 165 // ---------------------------------------------------------------------------- 
 167 // ---------------------------------------------------------------------------- 
 169 class wxDateTimeHolidaysModule 
: public wxModule
 
 172     virtual bool OnInit() 
 174         wxDateTimeHolidayAuthority::AddAuthority(new wxDateTimeWorkDays
); 
 179     virtual void OnExit() 
 181         wxDateTimeHolidayAuthority::ClearAllAuthorities(); 
 182         wxDateTimeHolidayAuthority::ms_authorities
.clear(); 
 186     DECLARE_DYNAMIC_CLASS(wxDateTimeHolidaysModule
) 
 189 IMPLEMENT_DYNAMIC_CLASS(wxDateTimeHolidaysModule
, wxModule
) 
 191 // ---------------------------------------------------------------------------- 
 193 // ---------------------------------------------------------------------------- 
 196 static const int MONTHS_IN_YEAR 
= 12; 
 198 static const int SEC_PER_MIN 
= 60; 
 200 static const int MIN_PER_HOUR 
= 60; 
 202 static const int HOURS_PER_DAY 
= 24; 
 204 static const long SECONDS_PER_DAY 
= 86400l; 
 206 static const int DAYS_PER_WEEK 
= 7; 
 208 static const long MILLISECONDS_PER_DAY 
= 86400000l; 
 210 // this is the integral part of JDN of the midnight of Jan 1, 1970 
 211 // (i.e. JDN(Jan 1, 1970) = 2440587.5) 
 212 static const long EPOCH_JDN 
= 2440587l; 
 214 // the date of JDN -0.5 (as we don't work with fractional parts, this is the 
 215 // reference date for us) is Nov 24, 4714BC 
 216 static const int JDN_0_YEAR 
= -4713; 
 217 static const int JDN_0_MONTH 
= wxDateTime::Nov
; 
 218 static const int JDN_0_DAY 
= 24; 
 220 // the constants used for JDN calculations 
 221 static const long JDN_OFFSET         
= 32046l; 
 222 static const long DAYS_PER_5_MONTHS  
= 153l; 
 223 static const long DAYS_PER_4_YEARS   
= 1461l; 
 224 static const long DAYS_PER_400_YEARS 
= 146097l; 
 226 // this array contains the cumulated number of days in all previous months for 
 227 // normal and leap years 
 228 static const wxDateTime::wxDateTime_t gs_cumulatedDays
[2][MONTHS_IN_YEAR
] = 
 230     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }, 
 231     { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 } 
 234 // ---------------------------------------------------------------------------- 
 236 // ---------------------------------------------------------------------------- 
 238 const wxChar 
* wxDefaultDateTimeFormat 
= wxT("%c"); 
 239 const wxChar 
* wxDefaultTimeSpanFormat 
= wxT("%H:%M:%S"); 
 241 // in the fine tradition of ANSI C we use our equivalent of (time_t)-1 to 
 242 // indicate an invalid wxDateTime object 
 243 const wxDateTime wxDefaultDateTime
; 
 245 wxDateTime::Country 
wxDateTime::ms_country 
= wxDateTime::Country_Unknown
; 
 247 // ---------------------------------------------------------------------------- 
 249 // ---------------------------------------------------------------------------- 
 251 // debugger helper: shows what the date really is 
 253 extern const wxChar 
*wxDumpDate(const wxDateTime
* dt
) 
 255     static wxChar buf
[128]; 
 257     wxStrcpy(buf
, dt
->Format(_T("%Y-%m-%d (%a) %H:%M:%S"))); 
 263 // get the number of days in the given month of the given year 
 265 wxDateTime::wxDateTime_t 
GetNumOfDaysInMonth(int year
, wxDateTime::Month month
) 
 267     // the number of days in month in Julian/Gregorian calendar: the first line 
 268     // is for normal years, the second one is for the leap ones 
 269     static wxDateTime::wxDateTime_t daysInMonth
[2][MONTHS_IN_YEAR
] = 
 271         { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 
 272         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 
 275     return daysInMonth
[wxDateTime::IsLeapYear(year
)][month
]; 
 278 // returns the time zone in the C sense, i.e. the difference UTC - local 
 280 static int GetTimeZone() 
 282 #ifdef WX_GMTOFF_IN_TM 
 283     // set to true when the timezone is set 
 284     static bool s_timezoneSet 
= false; 
 285     static long gmtoffset 
= LONG_MAX
; // invalid timezone 
 287     // ensure that the timezone variable is set by calling localtime 
 288     if ( !s_timezoneSet 
) 
 290         // just call localtime() instead of figuring out whether this system 
 291         // supports tzset(), _tzset() or something else 
 296         s_timezoneSet 
= true; 
 298         // note that GMT offset is the opposite of time zone and so to return 
 299         // consistent results in both WX_GMTOFF_IN_TM and !WX_GMTOFF_IN_TM 
 300         // cases we have to negate it 
 301         gmtoffset 
= -tm
->tm_gmtoff
; 
 304     return (int)gmtoffset
; 
 305 #else // !WX_GMTOFF_IN_TM 
 306     return (int)WX_TIMEZONE
; 
 307 #endif // WX_GMTOFF_IN_TM/!WX_GMTOFF_IN_TM 
 310 // return the integral part of the JDN for the midnight of the given date (to 
 311 // get the real JDN you need to add 0.5, this is, in fact, JDN of the 
 312 // noon of the previous day) 
 313 static long GetTruncatedJDN(wxDateTime::wxDateTime_t day
, 
 314                             wxDateTime::Month mon
, 
 317     // CREDIT: code below is by Scott E. Lee (but bugs are mine) 
 319     // check the date validity 
 321       (year 
> JDN_0_YEAR
) || 
 322       ((year 
== JDN_0_YEAR
) && (mon 
> JDN_0_MONTH
)) || 
 323       ((year 
== JDN_0_YEAR
) && (mon 
== JDN_0_MONTH
) && (day 
>= JDN_0_DAY
)), 
 324       _T("date out of range - can't convert to JDN") 
 327     // make the year positive to avoid problems with negative numbers division 
 330     // months are counted from March here 
 332     if ( mon 
>= wxDateTime::Mar 
) 
 342     // now we can simply add all the contributions together 
 343     return ((year 
/ 100) * DAYS_PER_400_YEARS
) / 4 
 344             + ((year 
% 100) * DAYS_PER_4_YEARS
) / 4 
 345             + (month 
* DAYS_PER_5_MONTHS 
+ 2) / 5 
 350 // this function is a wrapper around strftime(3) adding error checking 
 351 static wxString 
CallStrftime(const wxChar 
*format
, const tm
* tm
) 
 354         if ( !wxStrftime(buf
, WXSIZEOF(buf
), format
, tm
) ) 
 356         // buffer is too small? 
 357         wxFAIL_MSG(_T("strftime() failed")); 
 360     return wxString(buf
); 
 365 // glibc2 doesn't define this in the headers unless _XOPEN_SOURCE is defined 
 366 // which, unfortunately, wreaks havoc elsewhere 
 367 #if defined(__GLIBC__) && (__GLIBC__ == 2) 
 368     extern "C" char *strptime(const char *, const char *, struct tm 
*); 
 371 // Unicode-friendly strptime() wrapper 
 372 static const wxChar 
* 
 373 CallStrptime(const wxChar 
*input
, const char *fmt
, tm 
*tm
) 
 375     // the problem here is that strptime() returns pointer into the string we 
 376     // passed to it while we're really interested in the pointer into the 
 377     // original, Unicode, string so we try to transform the pointer back 
 379     wxCharBuffer 
inputMB(wxConvertWX2MB(input
)); 
 381     const char * const inputMB 
= input
; 
 382 #endif // Unicode/Ascii 
 384     const char *result 
= strptime(inputMB
, fmt
, tm
); 
 389     // FIXME: this is wrong in presence of surrogates &c 
 390     return input 
+ (result 
- inputMB
.data()); 
 393 #endif // Unicode/Ascii 
 396 #endif // HAVE_STRPTIME 
 398 // if year and/or month have invalid values, replace them with the current ones 
 399 static void ReplaceDefaultYearMonthWithCurrent(int *year
, 
 400                                                wxDateTime::Month 
*month
) 
 402     struct tm 
*tmNow 
= NULL
; 
 404     if ( *year 
== wxDateTime::Inv_Year 
) 
 406         tmNow 
= wxDateTime::GetTmNow(); 
 408         *year 
= 1900 + tmNow
->tm_year
; 
 411     if ( *month 
== wxDateTime::Inv_Month 
) 
 414             tmNow 
= wxDateTime::GetTmNow(); 
 416         *month 
= (wxDateTime::Month
)tmNow
->tm_mon
; 
 420 // fll the struct tm with default values 
 421 static void InitTm(struct tm
& tm
) 
 423     // struct tm may have etxra fields (undocumented and with unportable 
 424     // names) which, nevertheless, must be set to 0 
 425     memset(&tm
, 0, sizeof(struct tm
)); 
 427     tm
.tm_mday 
= 1;   // mday 0 is invalid 
 428     tm
.tm_year 
= 76;  // any valid year 
 429     tm
.tm_isdst 
= -1; // auto determine 
 435 // return the month if the string is a month name or Inv_Month otherwise 
 436 static wxDateTime::Month 
GetMonthFromName(const wxString
& name
, int flags
) 
 438     wxDateTime::Month mon
; 
 439     for ( mon 
= wxDateTime::Jan
; mon 
< wxDateTime::Inv_Month
; wxNextMonth(mon
) ) 
 441         // case-insensitive comparison either one of or with both abbreviated 
 443         if ( flags 
& wxDateTime::Name_Full 
) 
 445             if ( name
.CmpNoCase(wxDateTime:: 
 446                         GetMonthName(mon
, wxDateTime::Name_Full
)) == 0 ) 
 452         if ( flags 
& wxDateTime::Name_Abbr 
) 
 454             if ( name
.CmpNoCase(wxDateTime:: 
 455                         GetMonthName(mon
, wxDateTime::Name_Abbr
)) == 0 ) 
 465 // return the weekday if the string is a weekday name or Inv_WeekDay otherwise 
 466 static wxDateTime::WeekDay 
GetWeekDayFromName(const wxString
& name
, int flags
) 
 468     wxDateTime::WeekDay wd
; 
 469     for ( wd 
= wxDateTime::Sun
; wd 
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) ) 
 471         // case-insensitive comparison either one of or with both abbreviated 
 473         if ( flags 
& wxDateTime::Name_Full 
) 
 475             if ( name
.CmpNoCase(wxDateTime:: 
 476                         GetWeekDayName(wd
, wxDateTime::Name_Full
)) == 0 ) 
 482         if ( flags 
& wxDateTime::Name_Abbr 
) 
 484             if ( name
.CmpNoCase(wxDateTime:: 
 485                         GetWeekDayName(wd
, wxDateTime::Name_Abbr
)) == 0 ) 
 495 // scans all digits (but no more than len) and returns the resulting number 
 496 static bool GetNumericToken(size_t len
, const wxChar
*& p
, unsigned long *number
) 
 500     while ( wxIsdigit(*p
) ) 
 504         if ( len 
&& ++n 
> len 
) 
 508     return !s
.empty() && s
.ToULong(number
); 
 511 // scans all alphabetic characters and returns the resulting string 
 512 static wxString 
GetAlphaToken(const wxChar
*& p
) 
 515     while ( wxIsalpha(*p
) ) 
 523 // ============================================================================ 
 524 // implementation of wxDateTime 
 525 // ============================================================================ 
 527 // ---------------------------------------------------------------------------- 
 529 // ---------------------------------------------------------------------------- 
 533     year 
= (wxDateTime_t
)wxDateTime::Inv_Year
; 
 534     mon 
= wxDateTime::Inv_Month
; 
 536     hour 
= min 
= sec 
= msec 
= 0; 
 537     wday 
= wxDateTime::Inv_WeekDay
; 
 540 wxDateTime::Tm::Tm(const struct tm
& tm
, const TimeZone
& tz
) 
 544     sec 
= (wxDateTime::wxDateTime_t
)tm
.tm_sec
; 
 545     min 
= (wxDateTime::wxDateTime_t
)tm
.tm_min
; 
 546     hour 
= (wxDateTime::wxDateTime_t
)tm
.tm_hour
; 
 547     mday 
= (wxDateTime::wxDateTime_t
)tm
.tm_mday
; 
 548     mon 
= (wxDateTime::Month
)tm
.tm_mon
; 
 549     year 
= 1900 + tm
.tm_year
; 
 550     wday 
= (wxDateTime::wxDateTime_t
)tm
.tm_wday
; 
 551     yday 
= (wxDateTime::wxDateTime_t
)tm
.tm_yday
; 
 554 bool wxDateTime::Tm::IsValid() const 
 556     // we allow for the leap seconds, although we don't use them (yet) 
 557     return (year 
!= wxDateTime::Inv_Year
) && (mon 
!= wxDateTime::Inv_Month
) && 
 558            (mday 
<= GetNumOfDaysInMonth(year
, mon
)) && 
 559            (hour 
< 24) && (min 
< 60) && (sec 
< 62) && (msec 
< 1000); 
 562 void wxDateTime::Tm::ComputeWeekDay() 
 564     // compute the week day from day/month/year: we use the dumbest algorithm 
 565     // possible: just compute our JDN and then use the (simple to derive) 
 566     // formula: weekday = (JDN + 1.5) % 7 
 567     wday 
= (wxDateTime::wxDateTime_t
)((wxDateTime::WeekDay
)(GetTruncatedJDN(mday
, mon
, year
) + 2) % 7); 
 570 void wxDateTime::Tm::AddMonths(int monDiff
) 
 572     // normalize the months field 
 573     while ( monDiff 
< -mon 
) 
 577         monDiff 
+= MONTHS_IN_YEAR
; 
 580     while ( monDiff 
+ mon 
>= MONTHS_IN_YEAR 
) 
 584         monDiff 
-= MONTHS_IN_YEAR
; 
 587     mon 
= (wxDateTime::Month
)(mon 
+ monDiff
); 
 589     wxASSERT_MSG( mon 
>= 0 && mon 
< MONTHS_IN_YEAR
, _T("logic error") ); 
 591     // NB: we don't check here that the resulting date is valid, this function 
 592     //     is private and the caller must check it if needed 
 595 void wxDateTime::Tm::AddDays(int dayDiff
) 
 597     // normalize the days field 
 598     while ( dayDiff 
+ mday 
< 1 ) 
 602         dayDiff 
+= GetNumOfDaysInMonth(year
, mon
); 
 605     mday 
= (wxDateTime::wxDateTime_t
)( mday 
+ dayDiff 
); 
 606     while ( mday 
> GetNumOfDaysInMonth(year
, mon
) ) 
 608         mday 
-= GetNumOfDaysInMonth(year
, mon
); 
 613     wxASSERT_MSG( mday 
> 0 && mday 
<= GetNumOfDaysInMonth(year
, mon
), 
 617 // ---------------------------------------------------------------------------- 
 619 // ---------------------------------------------------------------------------- 
 621 wxDateTime::TimeZone::TimeZone(wxDateTime::TZ tz
) 
 625         case wxDateTime::Local
: 
 626             // get the offset from C RTL: it returns the difference GMT-local 
 627             // while we want to have the offset _from_ GMT, hence the '-' 
 628             m_offset 
= -GetTimeZone(); 
 631         case wxDateTime::GMT_12
: 
 632         case wxDateTime::GMT_11
: 
 633         case wxDateTime::GMT_10
: 
 634         case wxDateTime::GMT_9
: 
 635         case wxDateTime::GMT_8
: 
 636         case wxDateTime::GMT_7
: 
 637         case wxDateTime::GMT_6
: 
 638         case wxDateTime::GMT_5
: 
 639         case wxDateTime::GMT_4
: 
 640         case wxDateTime::GMT_3
: 
 641         case wxDateTime::GMT_2
: 
 642         case wxDateTime::GMT_1
: 
 643             m_offset 
= -3600*(wxDateTime::GMT0 
- tz
); 
 646         case wxDateTime::GMT0
: 
 647         case wxDateTime::GMT1
: 
 648         case wxDateTime::GMT2
: 
 649         case wxDateTime::GMT3
: 
 650         case wxDateTime::GMT4
: 
 651         case wxDateTime::GMT5
: 
 652         case wxDateTime::GMT6
: 
 653         case wxDateTime::GMT7
: 
 654         case wxDateTime::GMT8
: 
 655         case wxDateTime::GMT9
: 
 656         case wxDateTime::GMT10
: 
 657         case wxDateTime::GMT11
: 
 658         case wxDateTime::GMT12
: 
 659             m_offset 
= 3600*(tz 
- wxDateTime::GMT0
); 
 662         case wxDateTime::A_CST
: 
 663             // Central Standard Time in use in Australia = UTC + 9.5 
 664             m_offset 
= 60l*(9*60 + 30); 
 668             wxFAIL_MSG( _T("unknown time zone") ); 
 672 // ---------------------------------------------------------------------------- 
 674 // ---------------------------------------------------------------------------- 
 677 bool wxDateTime::IsLeapYear(int year
, wxDateTime::Calendar cal
) 
 679     if ( year 
== Inv_Year 
) 
 680         year 
= GetCurrentYear(); 
 682     if ( cal 
== Gregorian 
) 
 684         // in Gregorian calendar leap years are those divisible by 4 except 
 685         // those divisible by 100 unless they're also divisible by 400 
 686         // (in some countries, like Russia and Greece, additional corrections 
 687         // exist, but they won't manifest themselves until 2700) 
 688         return (year 
% 4 == 0) && ((year 
% 100 != 0) || (year 
% 400 == 0)); 
 690     else if ( cal 
== Julian 
) 
 692         // in Julian calendar the rule is simpler 
 693         return year 
% 4 == 0; 
 697         wxFAIL_MSG(_T("unknown calendar")); 
 704 int wxDateTime::GetCentury(int year
) 
 706     return year 
> 0 ? year 
/ 100 : year 
/ 100 - 1; 
 710 int wxDateTime::ConvertYearToBC(int year
) 
 713     return year 
> 0 ? year 
: year 
- 1; 
 717 int wxDateTime::GetCurrentYear(wxDateTime::Calendar cal
) 
 722             return Now().GetYear(); 
 725             wxFAIL_MSG(_T("TODO")); 
 729             wxFAIL_MSG(_T("unsupported calendar")); 
 737 wxDateTime::Month 
wxDateTime::GetCurrentMonth(wxDateTime::Calendar cal
) 
 742             return Now().GetMonth(); 
 745             wxFAIL_MSG(_T("TODO")); 
 749             wxFAIL_MSG(_T("unsupported calendar")); 
 757 wxDateTime::wxDateTime_t 
wxDateTime::GetNumberOfDays(int year
, Calendar cal
) 
 759     if ( year 
== Inv_Year 
) 
 761         // take the current year if none given 
 762         year 
= GetCurrentYear(); 
 769             return IsLeapYear(year
) ? 366 : 365; 
 772             wxFAIL_MSG(_T("unsupported calendar")); 
 780 wxDateTime::wxDateTime_t 
wxDateTime::GetNumberOfDays(wxDateTime::Month month
, 
 782                                                      wxDateTime::Calendar cal
) 
 784     wxCHECK_MSG( month 
< MONTHS_IN_YEAR
, 0, _T("invalid month") ); 
 786     if ( cal 
== Gregorian 
|| cal 
== Julian 
) 
 788         if ( year 
== Inv_Year 
) 
 790             // take the current year if none given 
 791             year 
= GetCurrentYear(); 
 794         return GetNumOfDaysInMonth(year
, month
); 
 798         wxFAIL_MSG(_T("unsupported calendar")); 
 805 wxString 
wxDateTime::GetMonthName(wxDateTime::Month month
, 
 806                                   wxDateTime::NameFlags flags
) 
 808     wxCHECK_MSG( month 
!= Inv_Month
, wxEmptyString
, _T("invalid month") ); 
 810     // notice that we must set all the fields to avoid confusing libc (GNU one 
 811     // gets confused to a crash if we don't do this) 
 816     return CallStrftime(flags 
== Name_Abbr 
? _T("%b") : _T("%B"), &tm
); 
 822                         ret 
= (flags 
== Name_Abbr 
? wxT("Jan"): wxT("January")); 
 825                         ret 
= (flags 
== Name_Abbr 
? wxT("Feb"): wxT("Febuary")); 
 828                         ret 
= (flags 
== Name_Abbr 
? wxT("Mar"): wxT("March")); 
 831                         ret 
= (flags 
== Name_Abbr 
? wxT("Apr"): wxT("April")); 
 834                         ret 
= (flags 
== Name_Abbr 
? wxT("May"): wxT("May")); 
 837                         ret 
= (flags 
== Name_Abbr 
? wxT("Jun"): wxT("June")); 
 840                         ret 
= (flags 
== Name_Abbr 
? wxT("Jul"): wxT("July")); 
 843                         ret 
= (flags 
== Name_Abbr 
? wxT("Aug"): wxT("August")); 
 846                         ret 
= (flags 
== Name_Abbr 
? wxT("Sep"): wxT("September")); 
 849                         ret 
= (flags 
== Name_Abbr 
? wxT("Oct"): wxT("October")); 
 852                         ret 
= (flags 
== Name_Abbr 
? wxT("Nov"): wxT("November")); 
 855                         ret 
= (flags 
== Name_Abbr 
? wxT("Dec"): wxT("December")); 
 863 wxString 
wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday
, 
 864                                     wxDateTime::NameFlags flags
) 
 866     wxCHECK_MSG( wday 
!= Inv_WeekDay
, wxEmptyString
, _T("invalid weekday") ); 
 868     // take some arbitrary Sunday (but notice that the day should be such that 
 869     // after adding wday to it below we still have a valid date, e.g. don't 
 877     // and offset it by the number of days needed to get the correct wday 
 880     // call mktime() to normalize it... 
 883     // ... and call strftime() 
 884     return CallStrftime(flags 
== Name_Abbr 
? _T("%a") : _T("%A"), &tm
); 
 890                         ret 
= (flags 
== Name_Abbr 
? wxT("Sun") : wxT("Sunday")); 
 893                         ret 
= (flags 
== Name_Abbr 
? wxT("Mon") : wxT("Monday")); 
 896                         ret 
= (flags 
== Name_Abbr 
? wxT("Tue") : wxT("Tuesday")); 
 899                         ret 
= (flags 
== Name_Abbr 
? wxT("Wed") : wxT("Wednesday")); 
 902                         ret 
= (flags 
== Name_Abbr 
? wxT("Thu") : wxT("Thursday")); 
 905                         ret 
= (flags 
== Name_Abbr 
? wxT("Fri") : wxT("Friday")); 
 908                         ret 
= (flags 
== Name_Abbr 
? wxT("Sat") : wxT("Saturday")); 
 917 void wxDateTime::GetAmPmStrings(wxString 
*am
, wxString 
*pm
) 
 922     // @Note: Do not call 'CallStrftime' here! CallStrftime checks the return code 
 923     // and causes an assertion failed if the buffer is to small (which is good) - OR - 
 924     // if strftime does not return anything because the format string is invalid - OR - 
 925     // if there are no 'am' / 'pm' tokens defined for the current locale (which is not good). 
 926     // wxDateTime::ParseTime will try several different formats to parse the time. 
 927     // As a result, GetAmPmStrings might get called, even if the current locale 
 928     // does not define any 'am' / 'pm' tokens. In this case, wxStrftime would 
 929     // assert, even though it is a perfectly legal use. 
 932         if (wxStrftime(buffer
, sizeof buffer
, _T("%p"), &tm
) > 0) 
 933             *am 
= wxString(buffer
); 
 940         if (wxStrftime(buffer
, sizeof buffer
, _T("%p"), &tm
) > 0) 
 941             *pm 
= wxString(buffer
); 
 947 // ---------------------------------------------------------------------------- 
 948 // Country stuff: date calculations depend on the country (DST, work days, 
 949 // ...), so we need to know which rules to follow. 
 950 // ---------------------------------------------------------------------------- 
 953 wxDateTime::Country 
wxDateTime::GetCountry() 
 955     // TODO use LOCALE_ICOUNTRY setting under Win32 
 957     if ( ms_country 
== Country_Unknown 
) 
 959         // try to guess from the time zone name 
 960         time_t t 
= time(NULL
); 
 961         struct tm 
*tm 
= localtime(&t
); 
 963         wxString tz 
= CallStrftime(_T("%Z"), tm
); 
 964         if ( tz 
== _T("WET") || tz 
== _T("WEST") ) 
 968         else if ( tz 
== _T("CET") || tz 
== _T("CEST") ) 
 970             ms_country 
= Country_EEC
; 
 972         else if ( tz 
== _T("MSK") || tz 
== _T("MSD") ) 
 976         else if ( tz 
== _T("AST") || tz 
== _T("ADT") || 
 977                   tz 
== _T("EST") || tz 
== _T("EDT") || 
 978                   tz 
== _T("CST") || tz 
== _T("CDT") || 
 979                   tz 
== _T("MST") || tz 
== _T("MDT") || 
 980                   tz 
== _T("PST") || tz 
== _T("PDT") ) 
 986             // well, choose a default one 
 998 void wxDateTime::SetCountry(wxDateTime::Country country
) 
1000     ms_country 
= country
; 
1004 bool wxDateTime::IsWestEuropeanCountry(Country country
) 
1006     if ( country 
== Country_Default 
) 
1008         country 
= GetCountry(); 
1011     return (Country_WesternEurope_Start 
<= country
) && 
1012            (country 
<= Country_WesternEurope_End
); 
1015 // ---------------------------------------------------------------------------- 
1016 // DST calculations: we use 3 different rules for the West European countries, 
1017 // USA and for the rest of the world. This is undoubtedly false for many 
1018 // countries, but I lack the necessary info (and the time to gather it), 
1019 // please add the other rules here! 
1020 // ---------------------------------------------------------------------------- 
1023 bool wxDateTime::IsDSTApplicable(int year
, Country country
) 
1025     if ( year 
== Inv_Year 
) 
1027         // take the current year if none given 
1028         year 
= GetCurrentYear(); 
1031     if ( country 
== Country_Default 
) 
1033         country 
= GetCountry(); 
1040             // DST was first observed in the US and UK during WWI, reused 
1041             // during WWII and used again since 1966 
1042             return year 
>= 1966 || 
1043                    (year 
>= 1942 && year 
<= 1945) || 
1044                    (year 
== 1918 || year 
== 1919); 
1047             // assume that it started after WWII 
1053 wxDateTime 
wxDateTime::GetBeginDST(int year
, Country country
) 
1055     if ( year 
== Inv_Year 
) 
1057         // take the current year if none given 
1058         year 
= GetCurrentYear(); 
1061     if ( country 
== Country_Default 
) 
1063         country 
= GetCountry(); 
1066     if ( !IsDSTApplicable(year
, country
) ) 
1068         return wxInvalidDateTime
; 
1073     if ( IsWestEuropeanCountry(country
) || (country 
== Russia
) ) 
1075         // DST begins at 1 a.m. GMT on the last Sunday of March 
1076         if ( !dt
.SetToLastWeekDay(Sun
, Mar
, year
) ) 
1079             wxFAIL_MSG( _T("no last Sunday in March?") ); 
1082         dt 
+= wxTimeSpan::Hours(1); 
1084         // disable DST tests because it could result in an infinite recursion! 
1087     else switch ( country 
) 
1094                     // don't know for sure - assume it was in effect all year 
1099                     dt
.Set(1, Jan
, year
); 
1103                     // DST was installed Feb 2, 1942 by the Congress 
1104                     dt
.Set(2, Feb
, year
); 
1107                     // Oil embargo changed the DST period in the US 
1109                     dt
.Set(6, Jan
, 1974); 
1113                     dt
.Set(23, Feb
, 1975); 
1117                     // before 1986, DST begun on the last Sunday of April, but 
1118                     // in 1986 Reagan changed it to begin at 2 a.m. of the 
1119                     // first Sunday in April 
1122                         if ( !dt
.SetToLastWeekDay(Sun
, Apr
, year
) ) 
1125                             wxFAIL_MSG( _T("no first Sunday in April?") ); 
1130                         if ( !dt
.SetToWeekDay(Sun
, 1, Apr
, year
) ) 
1133                             wxFAIL_MSG( _T("no first Sunday in April?") ); 
1137                     dt 
+= wxTimeSpan::Hours(2); 
1139                     // TODO what about timezone?? 
1145             // assume Mar 30 as the start of the DST for the rest of the world 
1146             // - totally bogus, of course 
1147             dt
.Set(30, Mar
, year
); 
1154 wxDateTime 
wxDateTime::GetEndDST(int year
, Country country
) 
1156     if ( year 
== Inv_Year 
) 
1158         // take the current year if none given 
1159         year 
= GetCurrentYear(); 
1162     if ( country 
== Country_Default 
) 
1164         country 
= GetCountry(); 
1167     if ( !IsDSTApplicable(year
, country
) ) 
1169         return wxInvalidDateTime
; 
1174     if ( IsWestEuropeanCountry(country
) || (country 
== Russia
) ) 
1176         // DST ends at 1 a.m. GMT on the last Sunday of October 
1177         if ( !dt
.SetToLastWeekDay(Sun
, Oct
, year
) ) 
1179             // weirder and weirder... 
1180             wxFAIL_MSG( _T("no last Sunday in October?") ); 
1183         dt 
+= wxTimeSpan::Hours(1); 
1185         // disable DST tests because it could result in an infinite recursion! 
1188     else switch ( country 
) 
1195                     // don't know for sure - assume it was in effect all year 
1199                     dt
.Set(31, Dec
, year
); 
1203                     // the time was reset after the end of the WWII 
1204                     dt
.Set(30, Sep
, year
); 
1208                     // DST ends at 2 a.m. on the last Sunday of October 
1209                     if ( !dt
.SetToLastWeekDay(Sun
, Oct
, year
) ) 
1211                         // weirder and weirder... 
1212                         wxFAIL_MSG( _T("no last Sunday in October?") ); 
1215                     dt 
+= wxTimeSpan::Hours(2); 
1217                     // TODO what about timezone?? 
1222             // assume October 26th as the end of the DST - totally bogus too 
1223             dt
.Set(26, Oct
, year
); 
1229 // ---------------------------------------------------------------------------- 
1230 // constructors and assignment operators 
1231 // ---------------------------------------------------------------------------- 
1233 // return the current time with ms precision 
1234 /* static */ wxDateTime 
wxDateTime::UNow() 
1236     return wxDateTime(wxGetLocalTimeMillis()); 
1239 // the values in the tm structure contain the local time 
1240 wxDateTime
& wxDateTime::Set(const struct tm
& tm
) 
1243     time_t timet 
= mktime(&tm2
); 
1245     if ( timet 
== (time_t)-1 ) 
1247         // mktime() rather unintuitively fails for Jan 1, 1970 if the hour is 
1248         // less than timezone - try to make it work for this case 
1249         if ( tm2
.tm_year 
== 70 && tm2
.tm_mon 
== 0 && tm2
.tm_mday 
== 1 ) 
1251             return Set((time_t)( 
1253                        tm2
.tm_hour 
* MIN_PER_HOUR 
* SEC_PER_MIN 
+ 
1254                        tm2
.tm_min 
* SEC_PER_MIN 
+ 
1258         wxFAIL_MSG( _T("mktime() failed") ); 
1260         *this = wxInvalidDateTime
; 
1270 wxDateTime
& wxDateTime::Set(wxDateTime_t hour
, 
1271                             wxDateTime_t minute
, 
1272                             wxDateTime_t second
, 
1273                             wxDateTime_t millisec
) 
1275     // we allow seconds to be 61 to account for the leap seconds, even if we 
1276     // don't use them really 
1277     wxDATETIME_CHECK( hour 
< 24 && 
1281                       _T("Invalid time in wxDateTime::Set()") ); 
1283     // get the current date from system 
1284     struct tm 
*tm 
= GetTmNow(); 
1286     wxDATETIME_CHECK( tm
, _T("localtime() failed") ); 
1290     tm
->tm_min 
= minute
; 
1291     tm
->tm_sec 
= second
; 
1293     // and the DST in case it changes on this date 
1296     if ( tm2
.tm_isdst 
!= tm
->tm_isdst 
) 
1297         tm
->tm_isdst 
= tm2
.tm_isdst
; 
1301     // and finally adjust milliseconds 
1302     return SetMillisecond(millisec
); 
1305 wxDateTime
& wxDateTime::Set(wxDateTime_t day
, 
1309                             wxDateTime_t minute
, 
1310                             wxDateTime_t second
, 
1311                             wxDateTime_t millisec
) 
1313     wxDATETIME_CHECK( hour 
< 24 && 
1317                       _T("Invalid time in wxDateTime::Set()") ); 
1319     ReplaceDefaultYearMonthWithCurrent(&year
, &month
); 
1321     wxDATETIME_CHECK( (0 < day
) && (day 
<= GetNumberOfDays(month
, year
)), 
1322                       _T("Invalid date in wxDateTime::Set()") ); 
1324     // the range of time_t type (inclusive) 
1325     static const int yearMinInRange 
= 1970; 
1326     static const int yearMaxInRange 
= 2037; 
1328     // test only the year instead of testing for the exact end of the Unix 
1329     // time_t range - it doesn't bring anything to do more precise checks 
1330     if ( year 
>= yearMinInRange 
&& year 
<= yearMaxInRange 
) 
1332         // use the standard library version if the date is in range - this is 
1333         // probably more efficient than our code 
1335         tm
.tm_year 
= year 
- 1900; 
1341         tm
.tm_isdst 
= -1;       // mktime() will guess it 
1345         // and finally adjust milliseconds 
1347             SetMillisecond(millisec
); 
1353         // do time calculations ourselves: we want to calculate the number of 
1354         // milliseconds between the given date and the epoch 
1356         // get the JDN for the midnight of this day 
1357         m_time 
= GetTruncatedJDN(day
, month
, year
); 
1358         m_time 
-= EPOCH_JDN
; 
1359         m_time 
*= SECONDS_PER_DAY 
* TIME_T_FACTOR
; 
1361         // JDN corresponds to GMT, we take localtime 
1362         Add(wxTimeSpan(hour
, minute
, second 
+ GetTimeZone(), millisec
)); 
1368 wxDateTime
& wxDateTime::Set(double jdn
) 
1370     // so that m_time will be 0 for the midnight of Jan 1, 1970 which is jdn 
1372     jdn 
-= EPOCH_JDN 
+ 0.5; 
1374     jdn 
*= MILLISECONDS_PER_DAY
; 
1376     // JDNs always suppose an UTC date, so bring it back to local time zone 
1377     // (also see GetJulianDayNumber() implementation) 
1378     long tzDiff 
= GetTimeZone(); 
1381         // FIXME: again, we suppose that DST is always one hour 
1385     jdn 
+= tzDiff
*1000; // tzDiff is in seconds 
1392 wxDateTime
& wxDateTime::ResetTime() 
1396     if ( tm
.hour 
|| tm
.min 
|| tm
.sec 
|| tm
.msec 
) 
1409 // ---------------------------------------------------------------------------- 
1410 // DOS Date and Time Format functions 
1411 // ---------------------------------------------------------------------------- 
1412 // the dos date and time value is an unsigned 32 bit value in the format: 
1413 // YYYYYYYMMMMDDDDDhhhhhmmmmmmsssss 
1415 // Y = year offset from 1980 (0-127) 
1417 // D = day of month (1-31) 
1419 // m = minute (0-59) 
1420 // s = bisecond (0-29) each bisecond indicates two seconds 
1421 // ---------------------------------------------------------------------------- 
1423 wxDateTime
& wxDateTime::SetFromDOS(unsigned long ddt
) 
1428     long year 
= ddt 
& 0xFE000000; 
1433     long month 
= ddt 
& 0x1E00000; 
1438     long day 
= ddt 
& 0x1F0000; 
1442     long hour 
= ddt 
& 0xF800; 
1446     long minute 
= ddt 
& 0x7E0; 
1450     long second 
= ddt 
& 0x1F; 
1451     tm
.tm_sec 
= second 
* 2; 
1453     return Set(mktime(&tm
)); 
1456 unsigned long wxDateTime::GetAsDOS() const 
1459     time_t ticks 
= GetTicks(); 
1460     struct tm 
*tm 
= localtime(&ticks
); 
1462     long year 
= tm
->tm_year
; 
1466     long month 
= tm
->tm_mon
; 
1470     long day 
= tm
->tm_mday
; 
1473     long hour 
= tm
->tm_hour
; 
1476     long minute 
= tm
->tm_min
; 
1479     long second 
= tm
->tm_sec
; 
1482     ddt 
= year 
| month 
| day 
| hour 
| minute 
| second
; 
1486 // ---------------------------------------------------------------------------- 
1487 // time_t <-> broken down time conversions 
1488 // ---------------------------------------------------------------------------- 
1490 wxDateTime::Tm 
wxDateTime::GetTm(const TimeZone
& tz
) const 
1492     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1494     time_t time 
= GetTicks(); 
1495     if ( time 
!= (time_t)-1 ) 
1497         // use C RTL functions 
1499         if ( tz
.GetOffset() == -GetTimeZone() ) 
1501             // we are working with local time 
1502             tm 
= localtime(&time
); 
1504             // should never happen 
1505             wxCHECK_MSG( tm
, Tm(), _T("localtime() failed") ); 
1509             time 
+= (time_t)tz
.GetOffset(); 
1510 #if defined(__VMS__) || defined(__WATCOMC__) // time is unsigned so avoid warning 
1511             int time2 
= (int) time
; 
1519                 // should never happen 
1520                 wxCHECK_MSG( tm
, Tm(), _T("gmtime() failed") ); 
1524                 tm 
= (struct tm 
*)NULL
; 
1530             // adjust the milliseconds 
1532             long timeOnly 
= (m_time 
% MILLISECONDS_PER_DAY
).ToLong(); 
1533             tm2
.msec 
= (wxDateTime_t
)(timeOnly 
% 1000); 
1536         //else: use generic code below 
1539     // remember the time and do the calculations with the date only - this 
1540     // eliminates rounding errors of the floating point arithmetics 
1542     wxLongLong timeMidnight 
= m_time 
+ tz
.GetOffset() * 1000; 
1544     long timeOnly 
= (timeMidnight 
% MILLISECONDS_PER_DAY
).ToLong(); 
1546     // we want to always have positive time and timeMidnight to be really 
1547     // the midnight before it 
1550         timeOnly 
= MILLISECONDS_PER_DAY 
+ timeOnly
; 
1553     timeMidnight 
-= timeOnly
; 
1555     // calculate the Gregorian date from JDN for the midnight of our date: 
1556     // this will yield day, month (in 1..12 range) and year 
1558     // actually, this is the JDN for the noon of the previous day 
1559     long jdn 
= (timeMidnight 
/ MILLISECONDS_PER_DAY
).ToLong() + EPOCH_JDN
; 
1561     // CREDIT: code below is by Scott E. Lee (but bugs are mine) 
1563     wxASSERT_MSG( jdn 
> -2, _T("JDN out of range") ); 
1565     // calculate the century 
1566     long temp 
= (jdn 
+ JDN_OFFSET
) * 4 - 1; 
1567     long century 
= temp 
/ DAYS_PER_400_YEARS
; 
1569     // then the year and day of year (1 <= dayOfYear <= 366) 
1570     temp 
= ((temp 
% DAYS_PER_400_YEARS
) / 4) * 4 + 3; 
1571     long year 
= (century 
* 100) + (temp 
/ DAYS_PER_4_YEARS
); 
1572     long dayOfYear 
= (temp 
% DAYS_PER_4_YEARS
) / 4 + 1; 
1574     // and finally the month and day of the month 
1575     temp 
= dayOfYear 
* 5 - 3; 
1576     long month 
= temp 
/ DAYS_PER_5_MONTHS
; 
1577     long day 
= (temp 
% DAYS_PER_5_MONTHS
) / 5 + 1; 
1579     // month is counted from March - convert to normal 
1590     // year is offset by 4800 
1593     // check that the algorithm gave us something reasonable 
1594     wxASSERT_MSG( (0 < month
) && (month 
<= 12), _T("invalid month") ); 
1595     wxASSERT_MSG( (1 <= day
) && (day 
< 32), _T("invalid day") ); 
1597     // construct Tm from these values 
1599     tm
.year 
= (int)year
; 
1600     tm
.mon 
= (Month
)(month 
- 1); // algorithm yields 1 for January, not 0 
1601     tm
.mday 
= (wxDateTime_t
)day
; 
1602     tm
.msec 
= (wxDateTime_t
)(timeOnly 
% 1000); 
1603     timeOnly 
-= tm
.msec
; 
1604     timeOnly 
/= 1000;               // now we have time in seconds 
1606     tm
.sec 
= (wxDateTime_t
)(timeOnly 
% 60); 
1608     timeOnly 
/= 60;                 // now we have time in minutes 
1610     tm
.min 
= (wxDateTime_t
)(timeOnly 
% 60); 
1613     tm
.hour 
= (wxDateTime_t
)(timeOnly 
/ 60); 
1618 wxDateTime
& wxDateTime::SetYear(int year
) 
1620     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1629 wxDateTime
& wxDateTime::SetMonth(Month month
) 
1631     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1640 wxDateTime
& wxDateTime::SetDay(wxDateTime_t mday
) 
1642     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1651 wxDateTime
& wxDateTime::SetHour(wxDateTime_t hour
) 
1653     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1662 wxDateTime
& wxDateTime::SetMinute(wxDateTime_t min
) 
1664     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1673 wxDateTime
& wxDateTime::SetSecond(wxDateTime_t sec
) 
1675     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1684 wxDateTime
& wxDateTime::SetMillisecond(wxDateTime_t millisecond
) 
1686     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1688     // we don't need to use GetTm() for this one 
1689     m_time 
-= m_time 
% 1000l; 
1690     m_time 
+= millisecond
; 
1695 // ---------------------------------------------------------------------------- 
1696 // wxDateTime arithmetics 
1697 // ---------------------------------------------------------------------------- 
1699 wxDateTime
& wxDateTime::Add(const wxDateSpan
& diff
) 
1703     tm
.year 
+= diff
.GetYears(); 
1704     tm
.AddMonths(diff
.GetMonths()); 
1706     // check that the resulting date is valid 
1707     if ( tm
.mday 
> GetNumOfDaysInMonth(tm
.year
, tm
.mon
) ) 
1709         // We suppose that when adding one month to Jan 31 we want to get Feb 
1710         // 28 (or 29), i.e. adding a month to the last day of the month should 
1711         // give the last day of the next month which is quite logical. 
1713         // Unfortunately, there is no logic way to understand what should 
1714         // Jan 30 + 1 month be - Feb 28 too or Feb 27 (assuming non leap year)? 
1715         // We make it Feb 28 (last day too), but it is highly questionable. 
1716         tm
.mday 
= GetNumOfDaysInMonth(tm
.year
, tm
.mon
); 
1719     tm
.AddDays(diff
.GetTotalDays()); 
1723     wxASSERT_MSG( IsSameTime(tm
), 
1724                   _T("Add(wxDateSpan) shouldn't modify time") ); 
1729 // ---------------------------------------------------------------------------- 
1730 // Weekday and monthday stuff 
1731 // ---------------------------------------------------------------------------- 
1733 // convert Sun, Mon, ..., Sat into 6, 0, ..., 5 
1734 static inline int ConvertWeekDayToMondayBase(int wd
) 
1736     return wd 
== wxDateTime::Sun 
? 6 : wd 
- 1; 
1741 wxDateTime::SetToWeekOfYear(int year
, wxDateTime_t numWeek
, WeekDay wd
) 
1743     wxASSERT_MSG( numWeek 
> 0, 
1744                   _T("invalid week number: weeks are counted from 1") ); 
1746     // Jan 4 always lies in the 1st week of the year 
1747     wxDateTime 
dt(4, Jan
, year
); 
1748     dt
.SetToWeekDayInSameWeek(wd
); 
1749     dt 
+= wxDateSpan::Weeks(numWeek 
- 1); 
1754 // use a separate function to avoid warnings about using deprecated 
1755 // SetToTheWeek in GetWeek below 
1757 SetToTheWeek(int year
, 
1758              wxDateTime::wxDateTime_t numWeek
, 
1759              wxDateTime::WeekDay weekday
, 
1760              wxDateTime::WeekFlags flags
) 
1762     // Jan 4 always lies in the 1st week of the year 
1763     wxDateTime 
dt(4, wxDateTime::Jan
, year
); 
1764     dt
.SetToWeekDayInSameWeek(weekday
, flags
); 
1765     dt 
+= wxDateSpan::Weeks(numWeek 
- 1); 
1770 bool wxDateTime::SetToTheWeek(wxDateTime_t numWeek
, 
1774     int year 
= GetYear(); 
1775     *this = ::SetToTheWeek(year
, numWeek
, weekday
, flags
); 
1776     if ( GetYear() != year 
) 
1778         // oops... numWeek was too big 
1785 wxDateTime 
wxDateTime::GetWeek(wxDateTime_t numWeek
, 
1787                                WeekFlags flags
) const 
1789     return ::SetToTheWeek(GetYear(), numWeek
, weekday
, flags
); 
1792 wxDateTime
& wxDateTime::SetToLastMonthDay(Month month
, 
1795     // take the current month/year if none specified 
1796     if ( year 
== Inv_Year 
) 
1798     if ( month 
== Inv_Month 
) 
1801     return Set(GetNumOfDaysInMonth(year
, month
), month
, year
); 
1804 wxDateTime
& wxDateTime::SetToWeekDayInSameWeek(WeekDay weekday
, WeekFlags flags
) 
1806     wxDATETIME_CHECK( weekday 
!= Inv_WeekDay
, _T("invalid weekday") ); 
1808     int wdayThis 
= GetWeekDay(); 
1809     if ( weekday 
== wdayThis 
) 
1815     if ( flags 
== Default_First 
) 
1817         flags 
= GetCountry() == USA 
? Sunday_First 
: Monday_First
; 
1820     // the logic below based on comparing weekday and wdayThis works if Sun (0) 
1821     // is the first day in the week, but breaks down for Monday_First case so 
1822     // we adjust the week days in this case 
1823     if( flags 
== Monday_First 
) 
1825         if ( wdayThis 
== Sun 
) 
1828     //else: Sunday_First, nothing to do 
1830     // go forward or back in time to the day we want 
1831     if ( weekday 
< wdayThis 
) 
1833         return Subtract(wxDateSpan::Days(wdayThis 
- weekday
)); 
1835     else // weekday > wdayThis 
1837         return Add(wxDateSpan::Days(weekday 
- wdayThis
)); 
1841 wxDateTime
& wxDateTime::SetToNextWeekDay(WeekDay weekday
) 
1843     wxDATETIME_CHECK( weekday 
!= Inv_WeekDay
, _T("invalid weekday") ); 
1846     WeekDay wdayThis 
= GetWeekDay(); 
1847     if ( weekday 
== wdayThis 
) 
1852     else if ( weekday 
< wdayThis 
) 
1854         // need to advance a week 
1855         diff 
= 7 - (wdayThis 
- weekday
); 
1857     else // weekday > wdayThis 
1859         diff 
= weekday 
- wdayThis
; 
1862     return Add(wxDateSpan::Days(diff
)); 
1865 wxDateTime
& wxDateTime::SetToPrevWeekDay(WeekDay weekday
) 
1867     wxDATETIME_CHECK( weekday 
!= Inv_WeekDay
, _T("invalid weekday") ); 
1870     WeekDay wdayThis 
= GetWeekDay(); 
1871     if ( weekday 
== wdayThis 
) 
1876     else if ( weekday 
> wdayThis 
) 
1878         // need to go to previous week 
1879         diff 
= 7 - (weekday 
- wdayThis
); 
1881     else // weekday < wdayThis 
1883         diff 
= wdayThis 
- weekday
; 
1886     return Subtract(wxDateSpan::Days(diff
)); 
1889 bool wxDateTime::SetToWeekDay(WeekDay weekday
, 
1894     wxCHECK_MSG( weekday 
!= Inv_WeekDay
, false, _T("invalid weekday") ); 
1896     // we don't check explicitly that -5 <= n <= 5 because we will return false 
1897     // anyhow in such case - but may be should still give an assert for it? 
1899     // take the current month/year if none specified 
1900     ReplaceDefaultYearMonthWithCurrent(&year
, &month
); 
1904     // TODO this probably could be optimised somehow... 
1908         // get the first day of the month 
1909         dt
.Set(1, month
, year
); 
1912         WeekDay wdayFirst 
= dt
.GetWeekDay(); 
1914         // go to the first weekday of the month 
1915         int diff 
= weekday 
- wdayFirst
; 
1919         // add advance n-1 weeks more 
1922         dt 
+= wxDateSpan::Days(diff
); 
1924     else // count from the end of the month 
1926         // get the last day of the month 
1927         dt
.SetToLastMonthDay(month
, year
); 
1930         WeekDay wdayLast 
= dt
.GetWeekDay(); 
1932         // go to the last weekday of the month 
1933         int diff 
= wdayLast 
- weekday
; 
1937         // and rewind n-1 weeks from there 
1940         dt 
-= wxDateSpan::Days(diff
); 
1943     // check that it is still in the same month 
1944     if ( dt
.GetMonth() == month 
) 
1952         // no such day in this month 
1958 wxDateTime::wxDateTime_t 
GetDayOfYearFromTm(const wxDateTime::Tm
& tm
) 
1960     return (wxDateTime::wxDateTime_t
)(gs_cumulatedDays
[wxDateTime::IsLeapYear(tm
.year
)][tm
.mon
] + tm
.mday
); 
1963 wxDateTime::wxDateTime_t 
wxDateTime::GetDayOfYear(const TimeZone
& tz
) const 
1965     return GetDayOfYearFromTm(GetTm(tz
)); 
1968 wxDateTime::wxDateTime_t
 
1969 wxDateTime::GetWeekOfYear(wxDateTime::WeekFlags flags
, const TimeZone
& tz
) const 
1971     if ( flags 
== Default_First 
) 
1973         flags 
= GetCountry() == USA 
? Sunday_First 
: Monday_First
; 
1977     wxDateTime_t nDayInYear 
= GetDayOfYearFromTm(tm
); 
1979     int wdTarget 
= GetWeekDay(tz
); 
1980     int wdYearStart 
= wxDateTime(1, Jan
, GetYear()).GetWeekDay(); 
1982     if ( flags 
== Sunday_First 
) 
1984         // FIXME: First week is not calculated correctly. 
1985         week 
= (nDayInYear 
- wdTarget 
+ 7) / 7; 
1986         if ( wdYearStart 
== Wed 
|| wdYearStart 
== Thu 
) 
1989     else // week starts with monday 
1991         // adjust the weekdays to non-US style. 
1992         wdYearStart 
= ConvertWeekDayToMondayBase(wdYearStart
); 
1993         wdTarget 
= ConvertWeekDayToMondayBase(wdTarget
); 
1995         // quoting from http://www.cl.cam.ac.uk/~mgk25/iso-time.html: 
1997         //      Week 01 of a year is per definition the first week that has the 
1998         //      Thursday in this year, which is equivalent to the week that 
1999         //      contains the fourth day of January. In other words, the first 
2000         //      week of a new year is the week that has the majority of its 
2001         //      days in the new year. Week 01 might also contain days from the 
2002         //      previous year and the week before week 01 of a year is the last 
2003         //      week (52 or 53) of the previous year even if it contains days 
2004         //      from the new year. A week starts with Monday (day 1) and ends 
2005         //      with Sunday (day 7). 
2008         // if Jan 1 is Thursday or less, it is in the first week of this year 
2009         if ( wdYearStart 
< 4 ) 
2011             // count the number of entire weeks between Jan 1 and this date 
2012             week 
= (nDayInYear 
+ wdYearStart 
+ 6 - wdTarget
)/7; 
2014             // be careful to check for overflow in the next year 
2015             if ( week 
== 53 && tm
.mday 
- wdTarget 
> 28 ) 
2018         else // Jan 1 is in the last week of the previous year 
2020             // check if we happen to be at the last week of previous year: 
2021             if ( tm
.mon 
== Jan 
&& tm
.mday 
< 8 - wdYearStart 
) 
2022                 week 
= wxDateTime(31, Dec
, GetYear()-1).GetWeekOfYear(); 
2024                 week 
= (nDayInYear 
+ wdYearStart 
- 1 - wdTarget
)/7; 
2028     return (wxDateTime::wxDateTime_t
)week
; 
2031 wxDateTime::wxDateTime_t 
wxDateTime::GetWeekOfMonth(wxDateTime::WeekFlags flags
, 
2032                                                     const TimeZone
& tz
) const 
2035     wxDateTime dtMonthStart 
= wxDateTime(1, tm
.mon
, tm
.year
); 
2036     int nWeek 
= GetWeekOfYear(flags
) - dtMonthStart
.GetWeekOfYear(flags
) + 1; 
2039         // this may happen for January when Jan, 1 is the last week of the 
2041         nWeek 
+= IsLeapYear(tm
.year 
- 1) ? 53 : 52; 
2044     return (wxDateTime::wxDateTime_t
)nWeek
; 
2047 wxDateTime
& wxDateTime::SetToYearDay(wxDateTime::wxDateTime_t yday
) 
2049     int year 
= GetYear(); 
2050     wxDATETIME_CHECK( (0 < yday
) && (yday 
<= GetNumberOfDays(year
)), 
2051                       _T("invalid year day") ); 
2053     bool isLeap 
= IsLeapYear(year
); 
2054     for ( Month mon 
= Jan
; mon 
< Inv_Month
; wxNextMonth(mon
) ) 
2056         // for Dec, we can't compare with gs_cumulatedDays[mon + 1], but we 
2057         // don't need it neither - because of the CHECK above we know that 
2058         // yday lies in December then 
2059         if ( (mon 
== Dec
) || (yday 
<= gs_cumulatedDays
[isLeap
][mon 
+ 1]) ) 
2061             Set((wxDateTime::wxDateTime_t
)(yday 
- gs_cumulatedDays
[isLeap
][mon
]), mon
, year
); 
2070 // ---------------------------------------------------------------------------- 
2071 // Julian day number conversion and related stuff 
2072 // ---------------------------------------------------------------------------- 
2074 double wxDateTime::GetJulianDayNumber() const 
2076     // JDN are always expressed for the UTC dates 
2077     Tm 
tm(ToTimezone(UTC
).GetTm(UTC
)); 
2079     double result 
= GetTruncatedJDN(tm
.mday
, tm
.mon
, tm
.year
); 
2081     // add the part GetTruncatedJDN() neglected 
2084     // and now add the time: 86400 sec = 1 JDN 
2085     return result 
+ ((double)(60*(60*tm
.hour 
+ tm
.min
) + tm
.sec
)) / 86400; 
2088 double wxDateTime::GetRataDie() const 
2090     // March 1 of the year 0 is Rata Die day -306 and JDN 1721119.5 
2091     return GetJulianDayNumber() - 1721119.5 - 306; 
2094 // ---------------------------------------------------------------------------- 
2095 // timezone and DST stuff 
2096 // ---------------------------------------------------------------------------- 
2098 int wxDateTime::IsDST(wxDateTime::Country country
) const 
2100     wxCHECK_MSG( country 
== Country_Default
, -1, 
2101                  _T("country support not implemented") ); 
2103     // use the C RTL for the dates in the standard range 
2104     time_t timet 
= GetTicks(); 
2105     if ( timet 
!= (time_t)-1 ) 
2107         tm 
*tm 
= localtime(&timet
); 
2109         wxCHECK_MSG( tm
, -1, _T("localtime() failed") ); 
2111         return tm
->tm_isdst
; 
2115         int year 
= GetYear(); 
2117         if ( !IsDSTApplicable(year
, country
) ) 
2119             // no DST time in this year in this country 
2123         return IsBetween(GetBeginDST(year
, country
), GetEndDST(year
, country
)); 
2127 wxDateTime
& wxDateTime::MakeTimezone(const TimeZone
& tz
, bool noDST
) 
2129     long secDiff 
= GetTimeZone() + tz
.GetOffset(); 
2131     // we need to know whether DST is or not in effect for this date unless 
2132     // the test disabled by the caller 
2133     if ( !noDST 
&& (IsDST() == 1) ) 
2135         // FIXME we assume that the DST is always shifted by 1 hour 
2139     return Subtract(wxTimeSpan::Seconds(secDiff
)); 
2142 // ---------------------------------------------------------------------------- 
2143 // wxDateTime to/from text representations 
2144 // ---------------------------------------------------------------------------- 
2146 wxString 
wxDateTime::Format(const wxChar 
*format
, const TimeZone
& tz
) const 
2148     wxCHECK_MSG( format
, wxEmptyString
, _T("NULL format in wxDateTime::Format") ); 
2150     // we have to use our own implementation if the date is out of range of 
2151     // strftime() or if we use non standard specificators 
2152     time_t time 
= GetTicks(); 
2153     if ( (time 
!= (time_t)-1) && !wxStrstr(format
, _T("%l")) ) 
2157         if ( tz
.GetOffset() == -GetTimeZone() ) 
2159             // we are working with local time 
2160             tm 
= localtime(&time
); 
2162             // should never happen 
2163             wxCHECK_MSG( tm
, wxEmptyString
, _T("localtime() failed") ); 
2167             time 
+= (int)tz
.GetOffset(); 
2169 #if defined(__VMS__) || defined(__WATCOMC__) // time is unsigned so avoid warning 
2170             int time2 
= (int) time
; 
2178                 // should never happen 
2179                 wxCHECK_MSG( tm
, wxEmptyString
, _T("gmtime() failed") ); 
2183                 tm 
= (struct tm 
*)NULL
; 
2187         //Windows CE doesn't support strftime or wcsftime, so we use the generic implementation 
2190             return CallStrftime(format
, tm
); 
2193         //else: use generic code below 
2196     // we only parse ANSI C format specifications here, no POSIX 2 
2197     // complications, no GNU extensions but we do add support for a "%l" format 
2198     // specifier allowing to get the number of milliseconds 
2201     // used for calls to strftime() when we only deal with time 
2202     struct tm tmTimeOnly
; 
2203     tmTimeOnly
.tm_hour 
= tm
.hour
; 
2204     tmTimeOnly
.tm_min 
= tm
.min
; 
2205     tmTimeOnly
.tm_sec 
= tm
.sec
; 
2206     tmTimeOnly
.tm_wday 
= 0; 
2207     tmTimeOnly
.tm_yday 
= 0; 
2208     tmTimeOnly
.tm_mday 
= 1;         // any date will do 
2209     tmTimeOnly
.tm_mon 
= 0; 
2210     tmTimeOnly
.tm_year 
= 76; 
2211     tmTimeOnly
.tm_isdst 
= 0;        // no DST, we adjust for tz ourselves 
2213     wxString tmp
, res
, fmt
; 
2214     for ( const wxChar 
*p 
= format
; *p
; p
++ ) 
2216         if ( *p 
!= _T('%') ) 
2224         // set the default format 
2227             case _T('Y'):               // year has 4 digits 
2231             case _T('j'):               // day of year has 3 digits 
2232             case _T('l'):               // milliseconds have 3 digits 
2236             case _T('w'):               // week day as number has only one 
2241                 // it's either another valid format specifier in which case 
2242                 // the format is "%02d" (for all the rest) or we have the 
2243                 // field width preceding the format in which case it will 
2244                 // override the default format anyhow 
2248         bool restart 
= true; 
2253             // start of the format specification 
2256                 case _T('a'):       // a weekday name 
2258                     // second parameter should be true for abbreviated names 
2259                     res 
+= GetWeekDayName(tm
.GetWeekDay(), 
2260                                           *p 
== _T('a') ? Name_Abbr 
: Name_Full
); 
2263                 case _T('b'):       // a month name 
2265                     res 
+= GetMonthName(tm
.mon
, 
2266                                         *p 
== _T('b') ? Name_Abbr 
: Name_Full
); 
2269                 case _T('c'):       // locale default date and time  representation 
2270                 case _T('x'):       // locale default date representation 
2273                     // the problem: there is no way to know what do these format 
2274                     // specifications correspond to for the current locale. 
2276                     // the solution: use a hack and still use strftime(): first 
2277                     // find the YEAR which is a year in the strftime() range (1970 
2278                     // - 2038) whose Jan 1 falls on the same week day as the Jan 1 
2279                     // of the real year. Then make a copy of the format and 
2280                     // replace all occurences of YEAR in it with some unique 
2281                     // string not appearing anywhere else in it, then use 
2282                     // strftime() to format the date in year YEAR and then replace 
2283                     // YEAR back by the real year and the unique replacement 
2284                     // string back with YEAR. Notice that "all occurences of YEAR" 
2285                     // means all occurences of 4 digit as well as 2 digit form! 
2287                     // the bugs: we assume that neither of %c nor %x contains any 
2288                     // fields which may change between the YEAR and real year. For 
2289                     // example, the week number (%U, %W) and the day number (%j) 
2290                     // will change if one of these years is leap and the other one 
2293                         // find the YEAR: normally, for any year X, Jan 1 or the 
2294                         // year X + 28 is the same weekday as Jan 1 of X (because 
2295                         // the weekday advances by 1 for each normal X and by 2 
2296                         // for each leap X, hence by 5 every 4 years or by 35 
2297                         // which is 0 mod 7 every 28 years) but this rule breaks 
2298                         // down if there are years between X and Y which are 
2299                         // divisible by 4 but not leap (i.e. divisible by 100 but 
2300                         // not 400), hence the correction. 
2302                         int yearReal 
= GetYear(tz
); 
2303                         int mod28 
= yearReal 
% 28; 
2305                         // be careful to not go too far - we risk to leave the 
2310                             year 
= 1988 + mod28
;      // 1988 == 0 (mod 28) 
2314                             year 
= 1970 + mod28 
- 10; // 1970 == 10 (mod 28) 
2317                         int nCentury 
= year 
/ 100, 
2318                             nCenturyReal 
= yearReal 
/ 100; 
2320                         // need to adjust for the years divisble by 400 which are 
2321                         // not leap but are counted like leap ones if we just take 
2322                         // the number of centuries in between for nLostWeekDays 
2323                         int nLostWeekDays 
= (nCentury 
- nCenturyReal
) - 
2324                                             (nCentury 
/ 4 - nCenturyReal 
/ 4); 
2326                         // we have to gain back the "lost" weekdays: note that the 
2327                         // effect of this loop is to not do anything to 
2328                         // nLostWeekDays (which we won't use any more), but to 
2329                         // (indirectly) set the year correctly 
2330                         while ( (nLostWeekDays 
% 7) != 0 ) 
2332                             nLostWeekDays 
+= year
++ % 4 ? 1 : 2; 
2335                         // at any rate, we couldn't go further than 1988 + 9 + 28! 
2336                         wxASSERT_MSG( year 
< 2030, 
2337                                       _T("logic error in wxDateTime::Format") ); 
2339                         wxString strYear
, strYear2
; 
2340                         strYear
.Printf(_T("%d"), year
); 
2341                         strYear2
.Printf(_T("%d"), year 
% 100); 
2343                         // find two strings not occuring in format (this is surely 
2344                         // not optimal way of doing it... improvements welcome!) 
2345                         wxString fmt 
= format
; 
2346                         wxString replacement 
= (wxChar
)-1; 
2347                         while ( fmt
.Find(replacement
) != wxNOT_FOUND 
) 
2349                             replacement 
<< (wxChar
)-1; 
2352                         wxString replacement2 
= (wxChar
)-2; 
2353                         while ( fmt
.Find(replacement
) != wxNOT_FOUND 
) 
2355                             replacement 
<< (wxChar
)-2; 
2358                         // replace all occurences of year with it 
2359                         bool wasReplaced 
= fmt
.Replace(strYear
, replacement
) > 0; 
2361                             wasReplaced 
= fmt
.Replace(strYear2
, replacement2
) > 0; 
2363                         // use strftime() to format the same date but in supported 
2366                         // NB: we assume that strftime() doesn't check for the 
2367                         //     date validity and will happily format the date 
2368                         //     corresponding to Feb 29 of a non leap year (which 
2369                         //     may happen if yearReal was leap and year is not) 
2370                         struct tm tmAdjusted
; 
2372                         tmAdjusted
.tm_hour 
= tm
.hour
; 
2373                         tmAdjusted
.tm_min 
= tm
.min
; 
2374                         tmAdjusted
.tm_sec 
= tm
.sec
; 
2375                         tmAdjusted
.tm_wday 
= tm
.GetWeekDay(); 
2376                         tmAdjusted
.tm_yday 
= GetDayOfYear(); 
2377                         tmAdjusted
.tm_mday 
= tm
.mday
; 
2378                         tmAdjusted
.tm_mon 
= tm
.mon
; 
2379                         tmAdjusted
.tm_year 
= year 
- 1900; 
2380                         tmAdjusted
.tm_isdst 
= 0; // no DST, already adjusted 
2381                         wxString str 
= CallStrftime(*p 
== _T('c') ? _T("%c") 
2385                         // now replace the occurence of 1999 with the real year 
2386                         wxString strYearReal
, strYearReal2
; 
2387                         strYearReal
.Printf(_T("%04d"), yearReal
); 
2388                         strYearReal2
.Printf(_T("%02d"), yearReal 
% 100); 
2389                         str
.Replace(strYear
, strYearReal
); 
2390                         str
.Replace(strYear2
, strYearReal2
); 
2392                         // and replace back all occurences of replacement string 
2395                             str
.Replace(replacement2
, strYear2
); 
2396                             str
.Replace(replacement
, strYear
); 
2402                                         //Use "%m/%d/%y %H:%M:%S" format instead 
2403                                         res 
+= wxString::Format(wxT("%02d/%02d/%04d %02d:%02d:%02d"), 
2404                                                         tm
.mon
+1,tm
.mday
, tm
.year
, tm
.hour
, tm
.min
, tm
.sec
); 
2408                 case _T('d'):       // day of a month (01-31) 
2409                     res 
+= wxString::Format(fmt
, tm
.mday
); 
2412                 case _T('H'):       // hour in 24h format (00-23) 
2413                     res 
+= wxString::Format(fmt
, tm
.hour
); 
2416                 case _T('I'):       // hour in 12h format (01-12) 
2418                         // 24h -> 12h, 0h -> 12h too 
2419                         int hour12 
= tm
.hour 
> 12 ? tm
.hour 
- 12 
2420                                                   : tm
.hour 
? tm
.hour 
: 12; 
2421                         res 
+= wxString::Format(fmt
, hour12
); 
2425                 case _T('j'):       // day of the year 
2426                     res 
+= wxString::Format(fmt
, GetDayOfYear(tz
)); 
2429                 case _T('l'):       // milliseconds (NOT STANDARD) 
2430                     res 
+= wxString::Format(fmt
, GetMillisecond(tz
)); 
2433                 case _T('m'):       // month as a number (01-12) 
2434                     res 
+= wxString::Format(fmt
, tm
.mon 
+ 1); 
2437                 case _T('M'):       // minute as a decimal number (00-59) 
2438                     res 
+= wxString::Format(fmt
, tm
.min
); 
2441                 case _T('p'):       // AM or PM string 
2443                     res 
+= CallStrftime(_T("%p"), &tmTimeOnly
); 
2445                                         res 
+= (tmTimeOnly
.tm_hour 
> 12) ? wxT("pm") : wxT("am"); 
2449                 case _T('S'):       // second as a decimal number (00-61) 
2450                     res 
+= wxString::Format(fmt
, tm
.sec
); 
2453                 case _T('U'):       // week number in the year (Sunday 1st week day) 
2454                     res 
+= wxString::Format(fmt
, GetWeekOfYear(Sunday_First
, tz
)); 
2457                 case _T('W'):       // week number in the year (Monday 1st week day) 
2458                     res 
+= wxString::Format(fmt
, GetWeekOfYear(Monday_First
, tz
)); 
2461                 case _T('w'):       // weekday as a number (0-6), Sunday = 0 
2462                     res 
+= wxString::Format(fmt
, tm
.GetWeekDay()); 
2465                 // case _T('x'): -- handled with "%c" 
2467                 case _T('X'):       // locale default time representation 
2468                     // just use strftime() to format the time for us 
2470                     res 
+= CallStrftime(_T("%X"), &tmTimeOnly
); 
2472                                         res 
+= wxString::Format(wxT("%02d:%02d:%02d"),tm
.hour
, tm
.min
, tm
.sec
); 
2476                 case _T('y'):       // year without century (00-99) 
2477                     res 
+= wxString::Format(fmt
, tm
.year 
% 100); 
2480                 case _T('Y'):       // year with century 
2481                     res 
+= wxString::Format(fmt
, tm
.year
); 
2484                 case _T('Z'):       // timezone name 
2486                     res 
+= CallStrftime(_T("%Z"), &tmTimeOnly
); 
2491                     // is it the format width? 
2493                     while ( *p 
== _T('-') || *p 
== _T('+') || 
2494                             *p 
== _T(' ') || wxIsdigit(*p
) ) 
2501                         // we've only got the flags and width so far in fmt 
2502                         fmt
.Prepend(_T('%')); 
2503                         fmt
.Append(_T('d')); 
2510                     // no, it wasn't the width 
2511                     wxFAIL_MSG(_T("unknown format specificator")); 
2513                     // fall through and just copy it nevertheless 
2515                 case _T('%'):       // a percent sign 
2519                 case 0:             // the end of string 
2520                     wxFAIL_MSG(_T("missing format at the end of string")); 
2522                     // just put the '%' which was the last char in format 
2532 // this function parses a string in (strict) RFC 822 format: see the section 5 
2533 // of the RFC for the detailed description, but briefly it's something of the 
2534 // form "Sat, 18 Dec 1999 00:48:30 +0100" 
2536 // this function is "strict" by design - it must reject anything except true 
2537 // RFC822 time specs. 
2539 // TODO a great candidate for using reg exps 
2540 const wxChar 
*wxDateTime::ParseRfc822Date(const wxChar
* date
) 
2542     wxCHECK_MSG( date
, (wxChar 
*)NULL
, _T("NULL pointer in wxDateTime::Parse") ); 
2544     const wxChar 
*p 
= date
; 
2545     const wxChar 
*comma 
= wxStrchr(p
, _T(',')); 
2548         // the part before comma is the weekday 
2550         // skip it for now - we don't use but might check that it really 
2551         // corresponds to the specfied date 
2554         if ( *p 
!= _T(' ') ) 
2556             wxLogDebug(_T("no space after weekday in RFC822 time spec")); 
2558             return (wxChar 
*)NULL
; 
2564     // the following 1 or 2 digits are the day number 
2565     if ( !wxIsdigit(*p
) ) 
2567         wxLogDebug(_T("day number expected in RFC822 time spec, none found")); 
2569         return (wxChar 
*)NULL
; 
2572     wxDateTime_t day 
= (wxDateTime_t
)(*p
++ - _T('0')); 
2573     if ( wxIsdigit(*p
) ) 
2576         day 
= (wxDateTime_t
)(day 
+ (*p
++ - _T('0'))); 
2579     if ( *p
++ != _T(' ') ) 
2581         return (wxChar 
*)NULL
; 
2584     // the following 3 letters specify the month 
2585     wxString 
monName(p
, 3); 
2587     if ( monName 
== _T("Jan") ) 
2589     else if ( monName 
== _T("Feb") ) 
2591     else if ( monName 
== _T("Mar") ) 
2593     else if ( monName 
== _T("Apr") ) 
2595     else if ( monName 
== _T("May") ) 
2597     else if ( monName 
== _T("Jun") ) 
2599     else if ( monName 
== _T("Jul") ) 
2601     else if ( monName 
== _T("Aug") ) 
2603     else if ( monName 
== _T("Sep") ) 
2605     else if ( monName 
== _T("Oct") ) 
2607     else if ( monName 
== _T("Nov") ) 
2609     else if ( monName 
== _T("Dec") ) 
2613         wxLogDebug(_T("Invalid RFC 822 month name '%s'"), monName
.c_str()); 
2615         return (wxChar 
*)NULL
; 
2620     if ( *p
++ != _T(' ') ) 
2622         return (wxChar 
*)NULL
; 
2626     if ( !wxIsdigit(*p
) ) 
2629         return (wxChar 
*)NULL
; 
2632     int year 
= *p
++ - _T('0'); 
2634     if ( !wxIsdigit(*p
) ) 
2636         // should have at least 2 digits in the year 
2637         return (wxChar 
*)NULL
; 
2641     year 
+= *p
++ - _T('0'); 
2643     // is it a 2 digit year (as per original RFC 822) or a 4 digit one? 
2644     if ( wxIsdigit(*p
) ) 
2647         year 
+= *p
++ - _T('0'); 
2649         if ( !wxIsdigit(*p
) ) 
2651             // no 3 digit years please 
2652             return (wxChar 
*)NULL
; 
2656         year 
+= *p
++ - _T('0'); 
2659     if ( *p
++ != _T(' ') ) 
2661         return (wxChar 
*)NULL
; 
2664     // time is in the format hh:mm:ss and seconds are optional 
2665     if ( !wxIsdigit(*p
) ) 
2667         return (wxChar 
*)NULL
; 
2670     wxDateTime_t hour 
= (wxDateTime_t
)(*p
++ - _T('0')); 
2672     if ( !wxIsdigit(*p
) ) 
2674         return (wxChar 
*)NULL
; 
2678     hour 
= (wxDateTime_t
)(hour 
+ (*p
++ - _T('0'))); 
2680     if ( *p
++ != _T(':') ) 
2682         return (wxChar 
*)NULL
; 
2685     if ( !wxIsdigit(*p
) ) 
2687         return (wxChar 
*)NULL
; 
2690     wxDateTime_t min 
= (wxDateTime_t
)(*p
++ - _T('0')); 
2692     if ( !wxIsdigit(*p
) ) 
2694         return (wxChar 
*)NULL
; 
2698     min 
= (wxDateTime_t
)(min 
+ *p
++ - _T('0')); 
2700     wxDateTime_t sec 
= 0; 
2701     if ( *p
++ == _T(':') ) 
2703         if ( !wxIsdigit(*p
) ) 
2705             return (wxChar 
*)NULL
; 
2708         sec 
= (wxDateTime_t
)(*p
++ - _T('0')); 
2710         if ( !wxIsdigit(*p
) ) 
2712             return (wxChar 
*)NULL
; 
2716         sec 
= (wxDateTime_t
)(sec 
+ *p
++ - _T('0')); 
2719     if ( *p
++ != _T(' ') ) 
2721         return (wxChar 
*)NULL
; 
2724     // and now the interesting part: the timezone 
2726     if ( *p 
== _T('-') || *p 
== _T('+') ) 
2728         // the explicit offset given: it has the form of hhmm 
2729         bool plus 
= *p
++ == _T('+'); 
2731         if ( !wxIsdigit(*p
) || !wxIsdigit(*(p 
+ 1)) ) 
2733             return (wxChar 
*)NULL
; 
2737         offset 
= 60*(10*(*p 
- _T('0')) + (*(p 
+ 1) - _T('0'))); 
2741         if ( !wxIsdigit(*p
) || !wxIsdigit(*(p 
+ 1)) ) 
2743             return (wxChar 
*)NULL
; 
2747         offset 
+= 10*(*p 
- _T('0')) + (*(p 
+ 1) - _T('0')); 
2758         // the symbolic timezone given: may be either military timezone or one 
2759         // of standard abbreviations 
2762             // military: Z = UTC, J unused, A = -1, ..., Y = +12 
2763             static const int offsets
[26] = 
2765                 //A  B   C   D   E   F   G   H   I    J    K    L    M 
2766                 -1, -2, -3, -4, -5, -6, -7, -8, -9,   0, -10, -11, -12, 
2767                 //N  O   P   R   Q   S   T   U   V    W    Z    Y    Z 
2768                 +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, 0 
2771             if ( *p 
< _T('A') || *p 
> _T('Z') || *p 
== _T('J') ) 
2773                 wxLogDebug(_T("Invalid militaty timezone '%c'"), *p
); 
2775                 return (wxChar 
*)NULL
; 
2778             offset 
= offsets
[*p
++ - _T('A')]; 
2784             if ( tz 
== _T("UT") || tz 
== _T("UTC") || tz 
== _T("GMT") ) 
2786             else if ( tz 
== _T("AST") ) 
2787                 offset 
= AST 
- GMT0
; 
2788             else if ( tz 
== _T("ADT") ) 
2789                 offset 
= ADT 
- GMT0
; 
2790             else if ( tz 
== _T("EST") ) 
2791                 offset 
= EST 
- GMT0
; 
2792             else if ( tz 
== _T("EDT") ) 
2793                 offset 
= EDT 
- GMT0
; 
2794             else if ( tz 
== _T("CST") ) 
2795                 offset 
= CST 
- GMT0
; 
2796             else if ( tz 
== _T("CDT") ) 
2797                 offset 
= CDT 
- GMT0
; 
2798             else if ( tz 
== _T("MST") ) 
2799                 offset 
= MST 
- GMT0
; 
2800             else if ( tz 
== _T("MDT") ) 
2801                 offset 
= MDT 
- GMT0
; 
2802             else if ( tz 
== _T("PST") ) 
2803                 offset 
= PST 
- GMT0
; 
2804             else if ( tz 
== _T("PDT") ) 
2805                 offset 
= PDT 
- GMT0
; 
2808                 wxLogDebug(_T("Unknown RFC 822 timezone '%s'"), p
); 
2810                 return (wxChar 
*)NULL
; 
2820     // the spec was correct 
2821     Set(day
, mon
, year
, hour
, min
, sec
); 
2822     MakeTimezone((wxDateTime_t
)(60*offset
)); 
2827 const wxChar 
*wxDateTime::ParseFormat(const wxChar 
*date
, 
2828                                       const wxChar 
*format
, 
2829                                       const wxDateTime
& dateDef
) 
2831     wxCHECK_MSG( date 
&& format
, (wxChar 
*)NULL
, 
2832                  _T("NULL pointer in wxDateTime::ParseFormat()") ); 
2837     // what fields have we found? 
2838     bool haveWDay 
= false, 
2847     bool hourIsIn12hFormat 
= false, // or in 24h one? 
2848          isPM 
= false;              // AM by default 
2850     // and the value of the items we have (init them to get rid of warnings) 
2851     wxDateTime_t sec 
= 0, 
2854     WeekDay wday 
= Inv_WeekDay
; 
2855     wxDateTime_t yday 
= 0, 
2857     wxDateTime::Month mon 
= Inv_Month
; 
2860     const wxChar 
*input 
= date
; 
2861     for ( const wxChar 
*fmt 
= format
; *fmt
; fmt
++ ) 
2863         if ( *fmt 
!= _T('%') ) 
2865             if ( wxIsspace(*fmt
) ) 
2867                 // a white space in the format string matches 0 or more white 
2868                 // spaces in the input 
2869                 while ( wxIsspace(*input
) ) 
2876                 // any other character (not whitespace, not '%') must be 
2877                 // matched by itself in the input 
2878                 if ( *input
++ != *fmt 
) 
2881                     return (wxChar 
*)NULL
; 
2885             // done with this format char 
2889         // start of a format specification 
2891         // parse the optional width 
2893         while ( wxIsdigit(*++fmt
) ) 
2896             width 
+= *fmt 
- _T('0'); 
2899         // the default widths for the various fields 
2904                 case _T('Y'):               // year has 4 digits 
2908                 case _T('j'):               // day of year has 3 digits 
2909                 case _T('l'):               // milliseconds have 3 digits 
2913                 case _T('w'):               // week day as number has only one 
2918                     // default for all other fields 
2923         // then the format itself 
2926             case _T('a'):       // a weekday name 
2929                     int flag 
= *fmt 
== _T('a') ? Name_Abbr 
: Name_Full
; 
2930                     wday 
= GetWeekDayFromName(GetAlphaToken(input
), flag
); 
2931                     if ( wday 
== Inv_WeekDay 
) 
2934                         return (wxChar 
*)NULL
; 
2940             case _T('b'):       // a month name 
2943                     int flag 
= *fmt 
== _T('b') ? Name_Abbr 
: Name_Full
; 
2944                     mon 
= GetMonthFromName(GetAlphaToken(input
), flag
); 
2945                     if ( mon 
== Inv_Month 
) 
2948                         return (wxChar 
*)NULL
; 
2954             case _T('c'):       // locale default date and time  representation 
2958                     // this is the format which corresponds to ctime() output 
2959                     // and strptime("%c") should parse it, so try it first 
2960                     static const wxChar 
*fmtCtime 
= _T("%a %b %d %H:%M:%S %Y"); 
2962                     const wxChar 
*result 
= dt
.ParseFormat(input
, fmtCtime
); 
2965                         result 
= dt
.ParseFormat(input
, _T("%x %X")); 
2970                         result 
= dt
.ParseFormat(input
, _T("%X %x")); 
2975                         // we've tried everything and still no match 
2976                         return (wxChar 
*)NULL
; 
2981                     haveDay 
= haveMon 
= haveYear 
= 
2982                     haveHour 
= haveMin 
= haveSec 
= true; 
2996             case _T('d'):       // day of a month (01-31) 
2997                 if ( !GetNumericToken(width
, input
, &num
) || 
2998                         (num 
> 31) || (num 
< 1) ) 
3001                     return (wxChar 
*)NULL
; 
3004                 // we can't check whether the day range is correct yet, will 
3005                 // do it later - assume ok for now 
3007                 mday 
= (wxDateTime_t
)num
; 
3010             case _T('H'):       // hour in 24h format (00-23) 
3011                 if ( !GetNumericToken(width
, input
, &num
) || (num 
> 23) ) 
3014                     return (wxChar 
*)NULL
; 
3018                 hour 
= (wxDateTime_t
)num
; 
3021             case _T('I'):       // hour in 12h format (01-12) 
3022                 if ( !GetNumericToken(width
, input
, &num
) || !num 
|| (num 
> 12) ) 
3025                     return (wxChar 
*)NULL
; 
3029                 hourIsIn12hFormat 
= true; 
3030                 hour 
= (wxDateTime_t
)(num 
% 12);        // 12 should be 0 
3033             case _T('j'):       // day of the year 
3034                 if ( !GetNumericToken(width
, input
, &num
) || !num 
|| (num 
> 366) ) 
3037                     return (wxChar 
*)NULL
; 
3041                 yday 
= (wxDateTime_t
)num
; 
3044             case _T('m'):       // month as a number (01-12) 
3045                 if ( !GetNumericToken(width
, input
, &num
) || !num 
|| (num 
> 12) ) 
3048                     return (wxChar 
*)NULL
; 
3052                 mon 
= (Month
)(num 
- 1); 
3055             case _T('M'):       // minute as a decimal number (00-59) 
3056                 if ( !GetNumericToken(width
, input
, &num
) || (num 
> 59) ) 
3059                     return (wxChar 
*)NULL
; 
3063                 min 
= (wxDateTime_t
)num
; 
3066             case _T('p'):       // AM or PM string 
3068                     wxString am
, pm
, token 
= GetAlphaToken(input
); 
3070                     GetAmPmStrings(&am
, &pm
); 
3071                     if (am
.empty() && pm
.empty()) 
3072                         return (wxChar 
*)NULL
;  // no am/pm strings defined 
3073                     if ( token
.CmpNoCase(pm
) == 0 ) 
3077                     else if ( token
.CmpNoCase(am
) != 0 ) 
3080                         return (wxChar 
*)NULL
; 
3085             case _T('r'):       // time as %I:%M:%S %p 
3088                     input 
= dt
.ParseFormat(input
, _T("%I:%M:%S %p")); 
3092                         return (wxChar 
*)NULL
; 
3095                     haveHour 
= haveMin 
= haveSec 
= true; 
3104             case _T('R'):       // time as %H:%M 
3107                     input 
= dt
.ParseFormat(input
, _T("%H:%M")); 
3111                         return (wxChar 
*)NULL
; 
3114                     haveHour 
= haveMin 
= true; 
3121             case _T('S'):       // second as a decimal number (00-61) 
3122                 if ( !GetNumericToken(width
, input
, &num
) || (num 
> 61) ) 
3125                     return (wxChar 
*)NULL
; 
3129                 sec 
= (wxDateTime_t
)num
; 
3132             case _T('T'):       // time as %H:%M:%S 
3135                     input 
= dt
.ParseFormat(input
, _T("%H:%M:%S")); 
3139                         return (wxChar 
*)NULL
; 
3142                     haveHour 
= haveMin 
= haveSec 
= true; 
3151             case _T('w'):       // weekday as a number (0-6), Sunday = 0 
3152                 if ( !GetNumericToken(width
, input
, &num
) || (wday 
> 6) ) 
3155                     return (wxChar 
*)NULL
; 
3159                 wday 
= (WeekDay
)num
; 
3162             case _T('x'):       // locale default date representation 
3163 #ifdef HAVE_STRPTIME 
3164                 // try using strptime() -- it may fail even if the input is 
3165                 // correct but the date is out of range, so we will fall back 
3166                 // to our generic code anyhow 
3170                     const wxChar 
*result 
= CallStrptime(input
, "%x", &tm
); 
3175                         haveDay 
= haveMon 
= haveYear 
= true; 
3177                         year 
= 1900 + tm
.tm_year
; 
3178                         mon 
= (Month
)tm
.tm_mon
; 
3184 #endif // HAVE_STRPTIME 
3186                 // TODO query the LOCALE_IDATE setting under Win32 
3190                     wxString fmtDate
, fmtDateAlt
; 
3191                     if ( IsWestEuropeanCountry(GetCountry()) || 
3192                          GetCountry() == Russia 
) 
3194                         fmtDate 
= _T("%d/%m/%y"); 
3195                         fmtDateAlt 
= _T("%m/%d/%y"); 
3199                         fmtDate 
= _T("%m/%d/%y"); 
3200                         fmtDateAlt 
= _T("%d/%m/%y"); 
3203                     const wxChar 
*result 
= dt
.ParseFormat(input
, fmtDate
); 
3207                         // ok, be nice and try another one 
3208                         result 
= dt
.ParseFormat(input
, fmtDateAlt
); 
3214                         return (wxChar 
*)NULL
; 
3219                     haveDay 
= haveMon 
= haveYear 
= true; 
3230             case _T('X'):       // locale default time representation 
3231 #ifdef HAVE_STRPTIME 
3233                     // use strptime() to do it for us (FIXME !Unicode friendly) 
3235                     input 
= CallStrptime(input
, "%X", &tm
); 
3238                         return (wxChar 
*)NULL
; 
3241                     haveHour 
= haveMin 
= haveSec 
= true; 
3247 #else // !HAVE_STRPTIME 
3248                 // TODO under Win32 we can query the LOCALE_ITIME system 
3249                 //      setting which says whether the default time format is 
3252                     // try to parse what follows as "%H:%M:%S" and, if this 
3253                     // fails, as "%I:%M:%S %p" - this should catch the most 
3257                     const wxChar 
*result 
= dt
.ParseFormat(input
, _T("%T")); 
3260                         result 
= dt
.ParseFormat(input
, _T("%r")); 
3266                         return (wxChar 
*)NULL
; 
3269                     haveHour 
= haveMin 
= haveSec 
= true; 
3278 #endif // HAVE_STRPTIME/!HAVE_STRPTIME 
3281             case _T('y'):       // year without century (00-99) 
3282                 if ( !GetNumericToken(width
, input
, &num
) || (num 
> 99) ) 
3285                     return (wxChar 
*)NULL
; 
3290                 // TODO should have an option for roll over date instead of 
3291                 //      hard coding it here 
3292                 year 
= (num 
> 30 ? 1900 : 2000) + (wxDateTime_t
)num
; 
3295             case _T('Y'):       // year with century 
3296                 if ( !GetNumericToken(width
, input
, &num
) ) 
3299                     return (wxChar 
*)NULL
; 
3303                 year 
= (wxDateTime_t
)num
; 
3306             case _T('Z'):       // timezone name 
3307                 wxFAIL_MSG(_T("TODO")); 
3310             case _T('%'):       // a percent sign 
3311                 if ( *input
++ != _T('%') ) 
3314                     return (wxChar 
*)NULL
; 
3318             case 0:             // the end of string 
3319                 wxFAIL_MSG(_T("unexpected format end")); 
3323             default:            // not a known format spec 
3324                 return (wxChar 
*)NULL
; 
3328     // format matched, try to construct a date from what we have now 
3330     if ( dateDef
.IsValid() ) 
3332         // take this date as default 
3333         tmDef 
= dateDef
.GetTm(); 
3335     else if ( IsValid() ) 
3337         // if this date is valid, don't change it 
3342         // no default and this date is invalid - fall back to Today() 
3343         tmDef 
= Today().GetTm(); 
3354     // TODO we don't check here that the values are consistent, if both year 
3355     //      day and month/day were found, we just ignore the year day and we 
3356     //      also always ignore the week day 
3357     if ( haveMon 
&& haveDay 
) 
3359         if ( mday 
> GetNumOfDaysInMonth(tm
.year
, mon
) ) 
3361             wxLogDebug(_T("bad month day in wxDateTime::ParseFormat")); 
3363             return (wxChar 
*)NULL
; 
3369     else if ( haveYDay 
) 
3371         if ( yday 
> GetNumberOfDays(tm
.year
) ) 
3373             wxLogDebug(_T("bad year day in wxDateTime::ParseFormat")); 
3375             return (wxChar 
*)NULL
; 
3378         Tm tm2 
= wxDateTime(1, Jan
, tm
.year
).SetToYearDay(yday
).GetTm(); 
3385     if ( haveHour 
&& hourIsIn12hFormat 
&& isPM 
) 
3387         // translate to 24hour format 
3390     //else: either already in 24h format or no translation needed 
3410     // finally check that the week day is consistent -- if we had it 
3411     if ( haveWDay 
&& GetWeekDay() != wday 
) 
3413         wxLogDebug(_T("inconsistsnet week day in wxDateTime::ParseFormat()")); 
3421 const wxChar 
*wxDateTime::ParseDateTime(const wxChar 
*date
) 
3423     wxCHECK_MSG( date
, (wxChar 
*)NULL
, _T("NULL pointer in wxDateTime::Parse") ); 
3425     // Set to current day and hour, so strings like '14:00' becomes today at 
3426     // 14, not some other random date 
3427     wxDateTime dtDate 
= wxDateTime::Today(); 
3428     wxDateTime dtTime 
= wxDateTime::Today(); 
3430     const wxChar
* pchTime
; 
3432     // Try to parse the beginning of the string as a date 
3433     const wxChar
* pchDate 
= dtDate
.ParseDate(date
); 
3435     // We got a date in the beginning, see if there is a time specified after the date 
3438         // Skip spaces, as the ParseTime() function fails on spaces 
3439         while ( wxIsspace(*pchDate
) ) 
3442         pchTime 
= dtTime
.ParseTime(pchDate
); 
3444     else // no date in the beginning 
3446         // check and see if we have a time followed by a date 
3447         pchTime 
= dtTime
.ParseTime(date
); 
3450             while ( wxIsspace(*pchTime
) ) 
3453             pchDate 
= dtDate
.ParseDate(pchTime
); 
3457     // If we have a date specified, set our own data to the same date 
3458     if ( !pchDate 
|| !pchTime 
) 
3461     Set(dtDate
.GetDay(), dtDate
.GetMonth(), dtDate
.GetYear(), 
3462         dtTime
.GetHour(), dtTime
.GetMinute(), dtTime
.GetSecond(), 
3463         dtTime
.GetMillisecond()); 
3465     // Return endpoint of scan 
3466     return pchDate 
> pchTime 
? pchDate 
: pchTime
; 
3469 const wxChar 
*wxDateTime::ParseDate(const wxChar 
*date
) 
3471     // this is a simplified version of ParseDateTime() which understands only 
3472     // "today" (for wxDate compatibility) and digits only otherwise (and not 
3473     // all esoteric constructions ParseDateTime() knows about) 
3475     wxCHECK_MSG( date
, (wxChar 
*)NULL
, _T("NULL pointer in wxDateTime::Parse") ); 
3477     const wxChar 
*p 
= date
; 
3478     while ( wxIsspace(*p
) ) 
3481     // some special cases 
3485         int dayDiffFromToday
; 
3488         { wxTRANSLATE("today"),             0 }, 
3489         { wxTRANSLATE("yesterday"),        -1 }, 
3490         { wxTRANSLATE("tomorrow"),          1 }, 
3493     for ( size_t n 
= 0; n 
< WXSIZEOF(literalDates
); n
++ ) 
3495         wxString date 
= wxGetTranslation(literalDates
[n
].str
); 
3496         size_t len 
= date
.length(); 
3497         if ( wxStrlen(p
) >= len 
) 
3499             wxString 
str(p
, len
); 
3500             if ( str
.CmpNoCase(date
) == 0 ) 
3502                 // nothing can follow this, so stop here 
3505                 int dayDiffFromToday 
= literalDates
[n
].dayDiffFromToday
; 
3507                 if ( dayDiffFromToday 
) 
3509                     *this += wxDateSpan::Days(dayDiffFromToday
); 
3517     // We try to guess what we have here: for each new (numeric) token, we 
3518     // determine if it can be a month, day or a year. Of course, there is an 
3519     // ambiguity as some numbers may be days as well as months, so we also 
3520     // have the ability to back track. 
3523     bool haveDay 
= false,       // the months day? 
3524          haveWDay 
= false,      // the day of week? 
3525          haveMon 
= false,       // the month? 
3526          haveYear 
= false;      // the year? 
3528     // and the value of the items we have (init them to get rid of warnings) 
3529     WeekDay wday 
= Inv_WeekDay
; 
3530     wxDateTime_t day 
= 0; 
3531     wxDateTime::Month mon 
= Inv_Month
; 
3534     // tokenize the string 
3536     static const wxChar 
*dateDelimiters 
= _T(".,/-\t\r\n "); 
3537     wxStringTokenizer 
tok(p
, dateDelimiters
); 
3538     while ( tok
.HasMoreTokens() ) 
3540         wxString token 
= tok
.GetNextToken(); 
3546         if ( token
.ToULong(&val
) ) 
3548             // guess what this number is 
3554             if ( !haveMon 
&& val 
> 0 && val 
<= 12 ) 
3556                 // assume it is month 
3559             else // not the month 
3563                     // this can only be the year 
3566                 else // may be either day or year 
3568                     wxDateTime_t max_days 
= (wxDateTime_t
)( 
3570                         ? GetNumOfDaysInMonth(haveYear 
? year 
: Inv_Year
, mon
) 
3575                     if ( (val 
== 0) || (val 
> (unsigned long)max_days
) ) 
3580                     else // yes, suppose it's the day 
3594                 year 
= (wxDateTime_t
)val
; 
3603                 day 
= (wxDateTime_t
)val
; 
3609                 mon 
= (Month
)(val 
- 1); 
3612         else // not a number 
3614             // be careful not to overwrite the current mon value 
3615             Month mon2 
= GetMonthFromName(token
, Name_Full 
| Name_Abbr
); 
3616             if ( mon2 
!= Inv_Month 
) 
3621                     // but we already have a month - maybe we guessed wrong? 
3624                         // no need to check in month range as always < 12, but 
3625                         // the days are counted from 1 unlike the months 
3626                         day 
= (wxDateTime_t
)(mon 
+ 1); 
3631                         // could possible be the year (doesn't the year come 
3632                         // before the month in the japanese format?) (FIXME) 
3641             else // not a valid month name 
3643                 wday 
= GetWeekDayFromName(token
, Name_Full 
| Name_Abbr
); 
3644                 if ( wday 
!= Inv_WeekDay 
) 
3654                 else // not a valid weekday name 
3657                     static const wxChar 
*ordinals
[] = 
3659                         wxTRANSLATE("first"), 
3660                         wxTRANSLATE("second"), 
3661                         wxTRANSLATE("third"), 
3662                         wxTRANSLATE("fourth"), 
3663                         wxTRANSLATE("fifth"), 
3664                         wxTRANSLATE("sixth"), 
3665                         wxTRANSLATE("seventh"), 
3666                         wxTRANSLATE("eighth"), 
3667                         wxTRANSLATE("ninth"), 
3668                         wxTRANSLATE("tenth"), 
3669                         wxTRANSLATE("eleventh"), 
3670                         wxTRANSLATE("twelfth"), 
3671                         wxTRANSLATE("thirteenth"), 
3672                         wxTRANSLATE("fourteenth"), 
3673                         wxTRANSLATE("fifteenth"), 
3674                         wxTRANSLATE("sixteenth"), 
3675                         wxTRANSLATE("seventeenth"), 
3676                         wxTRANSLATE("eighteenth"), 
3677                         wxTRANSLATE("nineteenth"), 
3678                         wxTRANSLATE("twentieth"), 
3679                         // that's enough - otherwise we'd have problems with 
3680                         // composite (or not) ordinals 
3684                     for ( n 
= 0; n 
< WXSIZEOF(ordinals
); n
++ ) 
3686                         if ( token
.CmpNoCase(ordinals
[n
]) == 0 ) 
3692                     if ( n 
== WXSIZEOF(ordinals
) ) 
3694                         // stop here - something unknown 
3701                         // don't try anything here (as in case of numeric day 
3702                         // above) - the symbolic day spec should always 
3703                         // precede the month/year 
3709                     day 
= (wxDateTime_t
)(n 
+ 1); 
3714         nPosCur 
= tok
.GetPosition(); 
3717     // either no more tokens or the scan was stopped by something we couldn't 
3718     // parse - in any case, see if we can construct a date from what we have 
3719     if ( !haveDay 
&& !haveWDay 
) 
3721         wxLogDebug(_T("ParseDate: no day, no weekday hence no date.")); 
3723         return (wxChar 
*)NULL
; 
3726     if ( haveWDay 
&& (haveMon 
|| haveYear 
|| haveDay
) && 
3727          !(haveDay 
&& haveMon 
&& haveYear
) ) 
3729         // without adjectives (which we don't support here) the week day only 
3730         // makes sense completely separately or with the full date 
3731         // specification (what would "Wed 1999" mean?) 
3732         return (wxChar 
*)NULL
; 
3735     if ( !haveWDay 
&& haveYear 
&& !(haveDay 
&& haveMon
) ) 
3737         // may be we have month and day instead of day and year? 
3738         if ( haveDay 
&& !haveMon 
) 
3742                 // exchange day and month 
3743                 mon 
= (wxDateTime::Month
)(day 
- 1); 
3745                 // we're in the current year then 
3746                 if ( (year 
> 0) && (year 
<= (int)GetNumOfDaysInMonth(Inv_Year
, mon
)) ) 
3748                     day 
= (wxDateTime_t
)year
; 
3753                 //else: no, can't exchange, leave haveMon == false 
3759             // if we give the year, month and day must be given too 
3760             wxLogDebug(_T("ParseDate: day and month should be specified if year is.")); 
3762             return (wxChar 
*)NULL
; 
3768         mon 
= GetCurrentMonth(); 
3773         year 
= GetCurrentYear(); 
3778         Set(day
, mon
, year
); 
3782             // check that it is really the same 
3783             if ( GetWeekDay() != wday 
) 
3785                 // inconsistency detected 
3786                 wxLogDebug(_T("ParseDate: inconsistent day/weekday.")); 
3788                 return (wxChar 
*)NULL
; 
3796         SetToWeekDayInSameWeek(wday
); 
3799     // return the pointer to the first unparsed char 
3801     if ( nPosCur 
&& wxStrchr(dateDelimiters
, *(p 
- 1)) ) 
3803         // if we couldn't parse the token after the delimiter, put back the 
3804         // delimiter as well 
3811 const wxChar 
*wxDateTime::ParseTime(const wxChar 
*time
) 
3813     wxCHECK_MSG( time
, (wxChar 
*)NULL
, _T("NULL pointer in wxDateTime::Parse") ); 
3815     // first try some extra things 
3822         { wxTRANSLATE("noon"),      12 }, 
3823         { wxTRANSLATE("midnight"),  00 }, 
3827     for ( size_t n 
= 0; n 
< WXSIZEOF(stdTimes
); n
++ ) 
3829         wxString timeString 
= wxGetTranslation(stdTimes
[n
].name
); 
3830         size_t len 
= timeString
.length(); 
3831         if ( timeString
.CmpNoCase(wxString(time
, len
)) == 0 ) 
3833             // casts required by DigitalMars 
3834             Set(stdTimes
[n
].hour
, wxDateTime_t(0), wxDateTime_t(0)); 
3840     // try all time formats we may think about in the order from longest to 
3843     // 12hour with AM/PM? 
3844     const wxChar 
*result 
= ParseFormat(time
, _T("%I:%M:%S %p")); 
3848         // normally, it's the same, but why not try it? 
3849         result 
= ParseFormat(time
, _T("%H:%M:%S")); 
3854         // 12hour with AM/PM but without seconds? 
3855         result 
= ParseFormat(time
, _T("%I:%M %p")); 
3861         result 
= ParseFormat(time
, _T("%H:%M")); 
3866         // just the hour and AM/PM? 
3867         result 
= ParseFormat(time
, _T("%I %p")); 
3873         result 
= ParseFormat(time
, _T("%H")); 
3878         // parse the standard format: normally it is one of the formats above 
3879         // but it may be set to something completely different by the user 
3880         result 
= ParseFormat(time
, _T("%X")); 
3883     // TODO: parse timezones 
3888 // ---------------------------------------------------------------------------- 
3889 // Workdays and holidays support 
3890 // ---------------------------------------------------------------------------- 
3892 bool wxDateTime::IsWorkDay(Country 
WXUNUSED(country
)) const 
3894     return !wxDateTimeHolidayAuthority::IsHoliday(*this); 
3897 // ============================================================================ 
3899 // ============================================================================ 
3901 wxDateSpan WXDLLIMPEXP_BASE 
operator*(int n
, const wxDateSpan
& ds
) 
3904     return ds1
.Multiply(n
); 
3907 // ============================================================================ 
3909 // ============================================================================ 
3911 wxTimeSpan WXDLLIMPEXP_BASE 
operator*(int n
, const wxTimeSpan
& ts
) 
3913     return wxTimeSpan(ts
).Multiply(n
); 
3916 // this enum is only used in wxTimeSpan::Format() below but we can't declare 
3917 // it locally to the method as it provokes an internal compiler error in egcs 
3918 // 2.91.60 when building with -O2 
3929 // not all strftime(3) format specifiers make sense here because, for example, 
3930 // a time span doesn't have a year nor a timezone 
3932 // Here are the ones which are supported (all of them are supported by strftime 
3934 //  %H          hour in 24 hour format 
3935 //  %M          minute (00 - 59) 
3936 //  %S          second (00 - 59) 
3939 // Also, for MFC CTimeSpan compatibility, we support 
3940 //  %D          number of days 
3942 // And, to be better than MFC :-), we also have 
3943 //  %E          number of wEeks 
3944 //  %l          milliseconds (000 - 999) 
3945 wxString 
wxTimeSpan::Format(const wxChar 
*format
) const 
3947     wxCHECK_MSG( format
, wxEmptyString
, _T("NULL format in wxTimeSpan::Format") ); 
3950     str
.Alloc(wxStrlen(format
)); 
3952     // Suppose we have wxTimeSpan ts(1 /* hour */, 2 /* min */, 3 /* sec */) 
3954     // Then, of course, ts.Format("%H:%M:%S") must return "01:02:03", but the 
3955     // question is what should ts.Format("%S") do? The code here returns "3273" 
3956     // in this case (i.e. the total number of seconds, not just seconds % 60) 
3957     // because, for me, this call means "give me entire time interval in 
3958     // seconds" and not "give me the seconds part of the time interval" 
3960     // If we agree that it should behave like this, it is clear that the 
3961     // interpretation of each format specifier depends on the presence of the 
3962     // other format specs in the string: if there was "%H" before "%M", we 
3963     // should use GetMinutes() % 60, otherwise just GetMinutes() &c 
3965     // we remember the most important unit found so far 
3966     TimeSpanPart partBiggest 
= Part_MSec
; 
3968     for ( const wxChar 
*pch 
= format
; *pch
; pch
++ ) 
3972         if ( ch 
== _T('%') ) 
3974             // the start of the format specification of the printf() below 
3975             wxString fmtPrefix 
= _T('%'); 
3980             ch 
= *++pch
;    // get the format spec char 
3984                     wxFAIL_MSG( _T("invalid format character") ); 
3990                     // skip the part below switch 
3995                     if ( partBiggest 
< Part_Day 
) 
4001                         partBiggest 
= Part_Day
; 
4006                     partBiggest 
= Part_Week
; 
4012                     if ( partBiggest 
< Part_Hour 
) 
4018                         partBiggest 
= Part_Hour
; 
4021                     fmtPrefix 
+= _T("02"); 
4025                     n 
= GetMilliseconds().ToLong(); 
4026                     if ( partBiggest 
< Part_MSec 
) 
4030                     //else: no need to reset partBiggest to Part_MSec, it is 
4031                     //      the least significant one anyhow 
4033                     fmtPrefix 
+= _T("03"); 
4038                     if ( partBiggest 
< Part_Min 
) 
4044                         partBiggest 
= Part_Min
; 
4047                     fmtPrefix 
+= _T("02"); 
4051                     n 
= GetSeconds().ToLong(); 
4052                     if ( partBiggest 
< Part_Sec 
) 
4058                         partBiggest 
= Part_Sec
; 
4061                     fmtPrefix 
+= _T("02"); 
4065             str 
+= wxString::Format(fmtPrefix 
+ _T("ld"), n
); 
4069             // normal character, just copy 
4077 // ============================================================================ 
4078 // wxDateTimeHolidayAuthority and related classes 
4079 // ============================================================================ 
4081 #include "wx/arrimpl.cpp" 
4083 WX_DEFINE_OBJARRAY(wxDateTimeArray
); 
4085 static int wxCMPFUNC_CONV
 
4086 wxDateTimeCompareFunc(wxDateTime 
**first
, wxDateTime 
**second
) 
4088     wxDateTime dt1 
= **first
, 
4091     return dt1 
== dt2 
? 0 : dt1 
< dt2 
? -1 : +1; 
4094 // ---------------------------------------------------------------------------- 
4095 // wxDateTimeHolidayAuthority 
4096 // ---------------------------------------------------------------------------- 
4098 wxHolidayAuthoritiesArray 
wxDateTimeHolidayAuthority::ms_authorities
; 
4101 bool wxDateTimeHolidayAuthority::IsHoliday(const wxDateTime
& dt
) 
4103     size_t count 
= ms_authorities
.size(); 
4104     for ( size_t n 
= 0; n 
< count
; n
++ ) 
4106         if ( ms_authorities
[n
]->DoIsHoliday(dt
) ) 
4117 wxDateTimeHolidayAuthority::GetHolidaysInRange(const wxDateTime
& dtStart
, 
4118                                                const wxDateTime
& dtEnd
, 
4119                                                wxDateTimeArray
& holidays
) 
4121     wxDateTimeArray hol
; 
4125     size_t count 
= ms_authorities
.size(); 
4126     for ( size_t nAuth 
= 0; nAuth 
< count
; nAuth
++ ) 
4128         ms_authorities
[nAuth
]->DoGetHolidaysInRange(dtStart
, dtEnd
, hol
); 
4130         WX_APPEND_ARRAY(holidays
, hol
); 
4133     holidays
.Sort(wxDateTimeCompareFunc
); 
4135     return holidays
.size(); 
4139 void wxDateTimeHolidayAuthority::ClearAllAuthorities() 
4141     WX_CLEAR_ARRAY(ms_authorities
); 
4145 void wxDateTimeHolidayAuthority::AddAuthority(wxDateTimeHolidayAuthority 
*auth
) 
4147     ms_authorities
.push_back(auth
); 
4150 wxDateTimeHolidayAuthority::~wxDateTimeHolidayAuthority() 
4152     // required here for Darwin 
4155 // ---------------------------------------------------------------------------- 
4156 // wxDateTimeWorkDays 
4157 // ---------------------------------------------------------------------------- 
4159 bool wxDateTimeWorkDays::DoIsHoliday(const wxDateTime
& dt
) const 
4161     wxDateTime::WeekDay wd 
= dt
.GetWeekDay(); 
4163     return (wd 
== wxDateTime::Sun
) || (wd 
== wxDateTime::Sat
); 
4166 size_t wxDateTimeWorkDays::DoGetHolidaysInRange(const wxDateTime
& dtStart
, 
4167                                                 const wxDateTime
& dtEnd
, 
4168                                                 wxDateTimeArray
& holidays
) const 
4170     if ( dtStart 
> dtEnd 
) 
4172         wxFAIL_MSG( _T("invalid date range in GetHolidaysInRange") ); 
4179     // instead of checking all days, start with the first Sat after dtStart and 
4180     // end with the last Sun before dtEnd 
4181     wxDateTime dtSatFirst 
= dtStart
.GetNextWeekDay(wxDateTime::Sat
), 
4182                dtSatLast 
= dtEnd
.GetPrevWeekDay(wxDateTime::Sat
), 
4183                dtSunFirst 
= dtStart
.GetNextWeekDay(wxDateTime::Sun
), 
4184                dtSunLast 
= dtEnd
.GetPrevWeekDay(wxDateTime::Sun
), 
4187     for ( dt 
= dtSatFirst
; dt 
<= dtSatLast
; dt 
+= wxDateSpan::Week() ) 
4192     for ( dt 
= dtSunFirst
; dt 
<= dtSunLast
; dt 
+= wxDateSpan::Week() ) 
4197     return holidays
.GetCount(); 
4200 // ============================================================================ 
4201 // other helper functions 
4202 // ============================================================================ 
4204 // ---------------------------------------------------------------------------- 
4205 // iteration helpers: can be used to write a for loop over enum variable like 
4207 //  for ( m = wxDateTime::Jan; m < wxDateTime::Inv_Month; wxNextMonth(m) ) 
4208 // ---------------------------------------------------------------------------- 
4210 WXDLLIMPEXP_BASE 
void wxNextMonth(wxDateTime::Month
& m
) 
4212     wxASSERT_MSG( m 
< wxDateTime::Inv_Month
, _T("invalid month") ); 
4214     // no wrapping or the for loop above would never end! 
4215     m 
= (wxDateTime::Month
)(m 
+ 1); 
4218 WXDLLIMPEXP_BASE 
void wxPrevMonth(wxDateTime::Month
& m
) 
4220     wxASSERT_MSG( m 
< wxDateTime::Inv_Month
, _T("invalid month") ); 
4222     m 
= m 
== wxDateTime::Jan 
? wxDateTime::Inv_Month
 
4223                              : (wxDateTime::Month
)(m 
- 1); 
4226 WXDLLIMPEXP_BASE 
void wxNextWDay(wxDateTime::WeekDay
& wd
) 
4228     wxASSERT_MSG( wd 
< wxDateTime::Inv_WeekDay
, _T("invalid week day") ); 
4230     // no wrapping or the for loop above would never end! 
4231     wd 
= (wxDateTime::WeekDay
)(wd 
+ 1); 
4234 WXDLLIMPEXP_BASE 
void wxPrevWDay(wxDateTime::WeekDay
& wd
) 
4236     wxASSERT_MSG( wd 
< wxDateTime::Inv_WeekDay
, _T("invalid week day") ); 
4238     wd 
= wd 
== wxDateTime::Sun 
? wxDateTime::Inv_WeekDay
 
4239                                : (wxDateTime::WeekDay
)(wd 
- 1); 
4242 #endif // wxUSE_DATETIME