1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/common/datetime.cpp 
   3 // Purpose:     implementation of time/date related classes 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 
   9 //              parts of code taken from sndcal library by Scott E. Lee: 
  11 //               Copyright 1993-1995, Scott E. Lee, all rights reserved. 
  12 //               Permission granted to use, copy, modify, distribute and sell 
  13 //               so long as the above copyright and this permission statement 
  14 //               are retained in all copies. 
  16 // Licence:     wxWindows licence 
  17 /////////////////////////////////////////////////////////////////////////////// 
  19 // TODO: for $DEITY sake, someone please fix the #ifdef __WXWINCE__ everywhere, 
  20 //       the proper way to do it is to implement (subset of) wxStrftime() for 
  21 //       CE instead of this horror!! 
  24  * Implementation notes: 
  26  * 1. the time is stored as a 64bit integer containing the signed number of 
  27  *    milliseconds since Jan 1. 1970 (the Unix Epoch) - so it is always 
  30  * 2. the range is thus something about 580 million years, but due to current 
  31  *    algorithms limitations, only dates from Nov 24, 4714BC are handled 
  33  * 3. standard ANSI C functions are used to do time calculations whenever 
  34  *    possible, i.e. when the date is in the range Jan 1, 1970 to 2038 
  36  * 4. otherwise, the calculations are done by converting the date to/from JDN 
  37  *    first (the range limitation mentioned above comes from here: the 
  38  *    algorithm used by Scott E. Lee's code only works for positive JDNs, more 
  41  * 5. the object constructed for the given DD-MM-YYYY HH:MM:SS corresponds to 
  42  *    this moment in local time and may be converted to the object 
  43  *    corresponding to the same date/time in another time zone by using 
  46  * 6. the conversions to the current (or any other) timezone are done when the 
  47  *    internal time representation is converted to the broken-down one in 
  51 // ============================================================================ 
  53 // ============================================================================ 
  55 // ---------------------------------------------------------------------------- 
  57 // ---------------------------------------------------------------------------- 
  59 // 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" 
  81     #include "wx/msw/wrapwin.h" 
  88 #include "wx/datetime.h" 
  89 #include "wx/stopwatch.h"           // for wxGetLocalTimeMillis() 
  91 const long wxDateTime::TIME_T_FACTOR 
= 1000l; 
  93 #if wxUSE_EXTENDED_RTTI 
  95 template<> void wxStringReadValue(const wxString 
&s 
, wxDateTime 
&data 
) 
  97     data
.ParseFormat(s
,wxT("%Y-%m-%d %H:%M:%S")) ; 
 100 template<> void wxStringWriteValue(wxString 
&s 
, const wxDateTime 
&data 
) 
 102     s 
= data
.Format(wxT("%Y-%m-%d %H:%M:%S")) ; 
 105 wxCUSTOM_TYPE_INFO(wxDateTime
, wxToStringConverter
<wxDateTime
> , wxFromStringConverter
<wxDateTime
>) 
 110 // ---------------------------------------------------------------------------- 
 111 // conditional compilation 
 112 // ---------------------------------------------------------------------------- 
 114 #if defined(HAVE_STRPTIME) && defined(__GLIBC__) && \ 
 115         ((__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0)) 
 116     // glibc 2.0.7 strptime() is broken - the following snippet causes it to 
 117     // crash (instead of just failing): 
 119     //      strncpy(buf, "Tue Dec 21 20:25:40 1999", 128); 
 120     //      strptime(buf, "%x", &tm); 
 124 #endif // broken strptime() 
 126 #if defined(HAVE_STRPTIME) && defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS 
 127     // configure detects strptime as linkable because it's in the OS X 
 128     // System library but MSL headers don't declare it. 
 130 //    char *strptime(const char *, const char *, struct tm *); 
 131     // However, we DON'T want to just provide it here because we would 
 132     // crash and/or overwrite data when strptime from OS X tries 
 133     // to fill in MW's struct tm which is two fields shorter (no TZ stuff) 
 134     // So for now let's just say we don't have strptime 
 138 #if defined(__MWERKS__) && wxUSE_UNICODE 
 142 #if !defined(WX_TIMEZONE) && !defined(WX_GMTOFF_IN_TM) 
 143     #if defined(__WXPALMOS__) 
 144         #define WX_GMTOFF_IN_TM 
 145     #elif defined(__BORLANDC__) || defined(__MINGW32__) || defined(__VISAGECPP__) 
 146         #define WX_TIMEZONE _timezone 
 147     #elif defined(__MWERKS__) 
 148         long wxmw_timezone 
= 28800; 
 149         #define WX_TIMEZONE wxmw_timezone 
 150     #elif defined(__DJGPP__) || defined(__WINE__) 
 151         #include <sys/timeb.h> 
 153         static long wxGetTimeZone() 
 155             static long timezone 
= MAXLONG
; // invalid timezone 
 156             if (timezone 
== MAXLONG
) 
 160                 timezone 
= tb
.timezone
; 
 164         #define WX_TIMEZONE wxGetTimeZone() 
 165     #elif defined(__DARWIN__) 
 166         #define WX_GMTOFF_IN_TM 
 167     #else // unknown platform - try timezone 
 168         #define WX_TIMEZONE timezone 
 170 #endif // !WX_TIMEZONE && !WX_GMTOFF_IN_TM 
 172 #if (!defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)) && wxUSE_THREADS && !defined(__WINDOWS__) 
 173 static wxMutex timeLock
; 
 176 #ifndef HAVE_LOCALTIME_R 
 177 struct tm 
*wxLocaltime_r(const time_t* ticks
, struct tm
* temp
) 
 179 #if wxUSE_THREADS && !defined(__WINDOWS__) 
 180   // No need to waste time with a mutex on windows since it's using 
 181   // thread local storage for localtime anyway. 
 182   wxMutexLocker 
locker(timeLock
); 
 184   memcpy(temp
, localtime(ticks
), sizeof(struct tm
)); 
 189 #ifndef HAVE_GMTIME_R 
 190 struct tm 
*wxGmtime_r(const time_t* ticks
, struct tm
* temp
) 
 192 #if wxUSE_THREADS && !defined(__WINDOWS__) 
 193   // No need to waste time with a mutex on windows since it's 
 194   // using thread local storage for gmtime anyway. 
 195   wxMutexLocker 
locker(timeLock
); 
 197   memcpy(temp
, gmtime(ticks
), sizeof(struct tm
)); 
 202 // ---------------------------------------------------------------------------- 
 204 // ---------------------------------------------------------------------------- 
 206 // debugging helper: just a convenient replacement of wxCHECK() 
 207 #define wxDATETIME_CHECK(expr, msg) \ 
 208     wxCHECK2_MSG(expr, *this = wxInvalidDateTime; return *this, msg) 
 210 // ---------------------------------------------------------------------------- 
 212 // ---------------------------------------------------------------------------- 
 214 class wxDateTimeHolidaysModule 
: public wxModule
 
 217     virtual bool OnInit() 
 219         wxDateTimeHolidayAuthority::AddAuthority(new wxDateTimeWorkDays
); 
 224     virtual void OnExit() 
 226         wxDateTimeHolidayAuthority::ClearAllAuthorities(); 
 227         wxDateTimeHolidayAuthority::ms_authorities
.clear(); 
 231     DECLARE_DYNAMIC_CLASS(wxDateTimeHolidaysModule
) 
 234 IMPLEMENT_DYNAMIC_CLASS(wxDateTimeHolidaysModule
, wxModule
) 
 236 // ---------------------------------------------------------------------------- 
 238 // ---------------------------------------------------------------------------- 
 241 static const int MONTHS_IN_YEAR 
= 12; 
 243 static const int SEC_PER_MIN 
= 60; 
 245 static const int MIN_PER_HOUR 
= 60; 
 247 static const int HOURS_PER_DAY 
= 24; 
 249 static const long SECONDS_PER_DAY 
= 86400l; 
 251 static const int DAYS_PER_WEEK 
= 7; 
 253 static const long MILLISECONDS_PER_DAY 
= 86400000l; 
 255 // this is the integral part of JDN of the midnight of Jan 1, 1970 
 256 // (i.e. JDN(Jan 1, 1970) = 2440587.5) 
 257 static const long EPOCH_JDN 
= 2440587l; 
 259 // used only in asserts 
 261 // the date of JDN -0.5 (as we don't work with fractional parts, this is the 
 262 // reference date for us) is Nov 24, 4714BC 
 263 static const int JDN_0_YEAR 
= -4713; 
 264 static const int JDN_0_MONTH 
= wxDateTime::Nov
; 
 265 static const int JDN_0_DAY 
= 24; 
 266 #endif // __WXDEBUG__ 
 268 // the constants used for JDN calculations 
 269 static const long JDN_OFFSET         
= 32046l; 
 270 static const long DAYS_PER_5_MONTHS  
= 153l; 
 271 static const long DAYS_PER_4_YEARS   
= 1461l; 
 272 static const long DAYS_PER_400_YEARS 
= 146097l; 
 274 // this array contains the cumulated number of days in all previous months for 
 275 // normal and leap years 
 276 static const wxDateTime::wxDateTime_t gs_cumulatedDays
[2][MONTHS_IN_YEAR
] = 
 278     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }, 
 279     { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 } 
 282 // ---------------------------------------------------------------------------- 
 284 // ---------------------------------------------------------------------------- 
 286 const wxChar 
* wxDefaultDateTimeFormat 
= wxT("%c"); 
 287 const wxChar 
* wxDefaultTimeSpanFormat 
= wxT("%H:%M:%S"); 
 289 // in the fine tradition of ANSI C we use our equivalent of (time_t)-1 to 
 290 // indicate an invalid wxDateTime object 
 291 const wxDateTime wxDefaultDateTime
; 
 293 wxDateTime::Country 
wxDateTime::ms_country 
= wxDateTime::Country_Unknown
; 
 295 // ---------------------------------------------------------------------------- 
 297 // ---------------------------------------------------------------------------- 
 299 // debugger helper: shows what the date really is 
 301 extern const wxChar 
*wxDumpDate(const wxDateTime
* dt
) 
 303     static wxChar buf
[128]; 
 305     wxStrcpy(buf
, dt
->Format(_T("%Y-%m-%d (%a) %H:%M:%S"))); 
 311 // get the number of days in the given month of the given year 
 313 wxDateTime::wxDateTime_t 
GetNumOfDaysInMonth(int year
, wxDateTime::Month month
) 
 315     // the number of days in month in Julian/Gregorian calendar: the first line 
 316     // is for normal years, the second one is for the leap ones 
 317     static wxDateTime::wxDateTime_t daysInMonth
[2][MONTHS_IN_YEAR
] = 
 319         { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 
 320         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 
 323     return daysInMonth
[wxDateTime::IsLeapYear(year
)][month
]; 
 326 // returns the time zone in the C sense, i.e. the difference UTC - local 
 328 static int GetTimeZone() 
 330 #ifdef WX_GMTOFF_IN_TM 
 331     // set to true when the timezone is set 
 332     static bool s_timezoneSet 
= false; 
 333     static long gmtoffset 
= LONG_MAX
; // invalid timezone 
 335     // ensure that the timezone variable is set by calling wxLocaltime_r 
 336     if ( !s_timezoneSet 
) 
 338         // just call wxLocaltime_r() instead of figuring out whether this 
 339         // system supports tzset(), _tzset() or something else 
 344         tm 
= wxLocaltime_r(&t
, &tmstruct
); 
 345         s_timezoneSet 
= true; 
 347         // note that GMT offset is the opposite of time zone and so to return 
 348         // consistent results in both WX_GMTOFF_IN_TM and !WX_GMTOFF_IN_TM 
 349         // cases we have to negate it 
 350         gmtoffset 
= -tm
->tm_gmtoff
; 
 353     return (int)gmtoffset
; 
 354 #else // !WX_GMTOFF_IN_TM 
 355     return (int)WX_TIMEZONE
; 
 356 #endif // WX_GMTOFF_IN_TM/!WX_GMTOFF_IN_TM 
 359 // return the integral part of the JDN for the midnight of the given date (to 
 360 // get the real JDN you need to add 0.5, this is, in fact, JDN of the 
 361 // noon of the previous day) 
 362 static long GetTruncatedJDN(wxDateTime::wxDateTime_t day
, 
 363                             wxDateTime::Month mon
, 
 366     // CREDIT: code below is by Scott E. Lee (but bugs are mine) 
 368     // check the date validity 
 370       (year 
> JDN_0_YEAR
) || 
 371       ((year 
== JDN_0_YEAR
) && (mon 
> JDN_0_MONTH
)) || 
 372       ((year 
== JDN_0_YEAR
) && (mon 
== JDN_0_MONTH
) && (day 
>= JDN_0_DAY
)), 
 373       _T("date out of range - can't convert to JDN") 
 376     // make the year positive to avoid problems with negative numbers division 
 379     // months are counted from March here 
 381     if ( mon 
>= wxDateTime::Mar 
) 
 391     // now we can simply add all the contributions together 
 392     return ((year 
/ 100) * DAYS_PER_400_YEARS
) / 4 
 393             + ((year 
% 100) * DAYS_PER_4_YEARS
) / 4 
 394             + (month 
* DAYS_PER_5_MONTHS 
+ 2) / 5 
 400 // this function is a wrapper around strftime(3) adding error checking 
 401 static wxString 
CallStrftime(const wxChar 
*format
, const tm
* tm
) 
 404     // Create temp wxString here to work around mingw/cygwin bug 1046059 
 405     // http://sourceforge.net/tracker/?func=detail&atid=102435&aid=1046059&group_id=2435 
 408     if ( !wxStrftime(buf
, WXSIZEOF(buf
), format
, tm
) ) 
 410         // buffer is too small? 
 411         wxFAIL_MSG(_T("strftime() failed")); 
 421 #if wxUSE_UNIX && !defined(HAVE_STRPTIME_DECL) 
 422     // configure detected that we had strptime() but not its declaration, 
 423     // provide it ourselves 
 424     extern "C" char *strptime(const char *, const char *, struct tm 
*); 
 427 // Unicode-friendly strptime() wrapper 
 428 static const wxChar 
* 
 429 CallStrptime(const wxChar 
*input
, const char *fmt
, tm 
*tm
) 
 431     // the problem here is that strptime() returns pointer into the string we 
 432     // passed to it while we're really interested in the pointer into the 
 433     // original, Unicode, string so we try to transform the pointer back 
 435     wxCharBuffer 
inputMB(wxConvertWX2MB(input
)); 
 437     const char * const inputMB 
= input
; 
 438 #endif // Unicode/Ascii 
 440     const char *result 
= strptime(inputMB
, fmt
, tm
); 
 445     // FIXME: this is wrong in presence of surrogates &c 
 446     return input 
+ (result 
- inputMB
.data()); 
 449 #endif // Unicode/Ascii 
 452 #endif // HAVE_STRPTIME 
 454 // if year and/or month have invalid values, replace them with the current ones 
 455 static void ReplaceDefaultYearMonthWithCurrent(int *year
, 
 456                                                wxDateTime::Month 
*month
) 
 458     struct tm 
*tmNow 
= NULL
; 
 461     if ( *year 
== wxDateTime::Inv_Year 
) 
 463         tmNow 
= wxDateTime::GetTmNow(&tmstruct
); 
 465         *year 
= 1900 + tmNow
->tm_year
; 
 468     if ( *month 
== wxDateTime::Inv_Month 
) 
 471             tmNow 
= wxDateTime::GetTmNow(&tmstruct
); 
 473         *month 
= (wxDateTime::Month
)tmNow
->tm_mon
; 
 477 // fll the struct tm with default values 
 478 static void InitTm(struct tm
& tm
) 
 480     // struct tm may have etxra fields (undocumented and with unportable 
 481     // names) which, nevertheless, must be set to 0 
 482     memset(&tm
, 0, sizeof(struct tm
)); 
 484     tm
.tm_mday 
= 1;   // mday 0 is invalid 
 485     tm
.tm_year 
= 76;  // any valid year 
 486     tm
.tm_isdst 
= -1; // auto determine 
 492 // return the month if the string is a month name or Inv_Month otherwise 
 493 static wxDateTime::Month 
GetMonthFromName(const wxString
& name
, int flags
) 
 495     wxDateTime::Month mon
; 
 496     for ( mon 
= wxDateTime::Jan
; mon 
< wxDateTime::Inv_Month
; wxNextMonth(mon
) ) 
 498         // case-insensitive comparison either one of or with both abbreviated 
 500         if ( flags 
& wxDateTime::Name_Full 
) 
 502             if ( name
.CmpNoCase(wxDateTime:: 
 503                         GetMonthName(mon
, wxDateTime::Name_Full
)) == 0 ) 
 509         if ( flags 
& wxDateTime::Name_Abbr 
) 
 511             if ( name
.CmpNoCase(wxDateTime:: 
 512                         GetMonthName(mon
, wxDateTime::Name_Abbr
)) == 0 ) 
 522 // return the weekday if the string is a weekday name or Inv_WeekDay otherwise 
 523 static wxDateTime::WeekDay 
GetWeekDayFromName(const wxString
& name
, int flags
) 
 525     wxDateTime::WeekDay wd
; 
 526     for ( wd 
= wxDateTime::Sun
; wd 
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) ) 
 528         // case-insensitive comparison either one of or with both abbreviated 
 530         if ( flags 
& wxDateTime::Name_Full 
) 
 532             if ( name
.CmpNoCase(wxDateTime:: 
 533                         GetWeekDayName(wd
, wxDateTime::Name_Full
)) == 0 ) 
 539         if ( flags 
& wxDateTime::Name_Abbr 
) 
 541             if ( name
.CmpNoCase(wxDateTime:: 
 542                         GetWeekDayName(wd
, wxDateTime::Name_Abbr
)) == 0 ) 
 553 struct tm 
*wxDateTime::GetTmNow(struct tm 
*tmstruct
) 
 555     time_t t 
= GetTimeNow(); 
 556     return wxLocaltime_r(&t
, tmstruct
); 
 559 // scans all digits (but no more than len) and returns the resulting number 
 560 static bool GetNumericToken(size_t len
, const wxChar
*& p
, unsigned long *number
) 
 564     while ( wxIsdigit(*p
) ) 
 568         if ( len 
&& ++n 
> len 
) 
 572     return !s
.empty() && s
.ToULong(number
); 
 575 // scans all alphabetic characters and returns the resulting string 
 576 static wxString 
GetAlphaToken(const wxChar
*& p
) 
 579     while ( wxIsalpha(*p
) ) 
 587 // ============================================================================ 
 588 // implementation of wxDateTime 
 589 // ============================================================================ 
 591 // ---------------------------------------------------------------------------- 
 593 // ---------------------------------------------------------------------------- 
 597     year 
= (wxDateTime_t
)wxDateTime::Inv_Year
; 
 598     mon 
= wxDateTime::Inv_Month
; 
 600     hour 
= min 
= sec 
= msec 
= 0; 
 601     wday 
= wxDateTime::Inv_WeekDay
; 
 604 wxDateTime::Tm::Tm(const struct tm
& tm
, const TimeZone
& tz
) 
 608     sec 
= (wxDateTime::wxDateTime_t
)tm
.tm_sec
; 
 609     min 
= (wxDateTime::wxDateTime_t
)tm
.tm_min
; 
 610     hour 
= (wxDateTime::wxDateTime_t
)tm
.tm_hour
; 
 611     mday 
= (wxDateTime::wxDateTime_t
)tm
.tm_mday
; 
 612     mon 
= (wxDateTime::Month
)tm
.tm_mon
; 
 613     year 
= 1900 + tm
.tm_year
; 
 614     wday 
= (wxDateTime::wxDateTime_t
)tm
.tm_wday
; 
 615     yday 
= (wxDateTime::wxDateTime_t
)tm
.tm_yday
; 
 618 bool wxDateTime::Tm::IsValid() const 
 620     // we allow for the leap seconds, although we don't use them (yet) 
 621     return (year 
!= wxDateTime::Inv_Year
) && (mon 
!= wxDateTime::Inv_Month
) && 
 622            (mday 
<= GetNumOfDaysInMonth(year
, mon
)) && 
 623            (hour 
< 24) && (min 
< 60) && (sec 
< 62) && (msec 
< 1000); 
 626 void wxDateTime::Tm::ComputeWeekDay() 
 628     // compute the week day from day/month/year: we use the dumbest algorithm 
 629     // possible: just compute our JDN and then use the (simple to derive) 
 630     // formula: weekday = (JDN + 1.5) % 7 
 631     wday 
= (wxDateTime::wxDateTime_t
)((wxDateTime::WeekDay
)(GetTruncatedJDN(mday
, mon
, year
) + 2) % 7); 
 634 void wxDateTime::Tm::AddMonths(int monDiff
) 
 636     // normalize the months field 
 637     while ( monDiff 
< -mon 
) 
 641         monDiff 
+= MONTHS_IN_YEAR
; 
 644     while ( monDiff 
+ mon 
>= MONTHS_IN_YEAR 
) 
 648         monDiff 
-= MONTHS_IN_YEAR
; 
 651     mon 
= (wxDateTime::Month
)(mon 
+ monDiff
); 
 653     wxASSERT_MSG( mon 
>= 0 && mon 
< MONTHS_IN_YEAR
, _T("logic error") ); 
 655     // NB: we don't check here that the resulting date is valid, this function 
 656     //     is private and the caller must check it if needed 
 659 void wxDateTime::Tm::AddDays(int dayDiff
) 
 661     // normalize the days field 
 662     while ( dayDiff 
+ mday 
< 1 ) 
 666         dayDiff 
+= GetNumOfDaysInMonth(year
, mon
); 
 669     mday 
= (wxDateTime::wxDateTime_t
)( mday 
+ dayDiff 
); 
 670     while ( mday 
> GetNumOfDaysInMonth(year
, mon
) ) 
 672         mday 
-= GetNumOfDaysInMonth(year
, mon
); 
 677     wxASSERT_MSG( mday 
> 0 && mday 
<= GetNumOfDaysInMonth(year
, mon
), 
 681 // ---------------------------------------------------------------------------- 
 683 // ---------------------------------------------------------------------------- 
 685 wxDateTime::TimeZone::TimeZone(wxDateTime::TZ tz
) 
 689         case wxDateTime::Local
: 
 690             // get the offset from C RTL: it returns the difference GMT-local 
 691             // while we want to have the offset _from_ GMT, hence the '-' 
 692             m_offset 
= -GetTimeZone(); 
 695         case wxDateTime::GMT_12
: 
 696         case wxDateTime::GMT_11
: 
 697         case wxDateTime::GMT_10
: 
 698         case wxDateTime::GMT_9
: 
 699         case wxDateTime::GMT_8
: 
 700         case wxDateTime::GMT_7
: 
 701         case wxDateTime::GMT_6
: 
 702         case wxDateTime::GMT_5
: 
 703         case wxDateTime::GMT_4
: 
 704         case wxDateTime::GMT_3
: 
 705         case wxDateTime::GMT_2
: 
 706         case wxDateTime::GMT_1
: 
 707             m_offset 
= -3600*(wxDateTime::GMT0 
- tz
); 
 710         case wxDateTime::GMT0
: 
 711         case wxDateTime::GMT1
: 
 712         case wxDateTime::GMT2
: 
 713         case wxDateTime::GMT3
: 
 714         case wxDateTime::GMT4
: 
 715         case wxDateTime::GMT5
: 
 716         case wxDateTime::GMT6
: 
 717         case wxDateTime::GMT7
: 
 718         case wxDateTime::GMT8
: 
 719         case wxDateTime::GMT9
: 
 720         case wxDateTime::GMT10
: 
 721         case wxDateTime::GMT11
: 
 722         case wxDateTime::GMT12
: 
 723             m_offset 
= 3600*(tz 
- wxDateTime::GMT0
); 
 726         case wxDateTime::A_CST
: 
 727             // Central Standard Time in use in Australia = UTC + 9.5 
 728             m_offset 
= 60l*(9*MIN_PER_HOUR 
+ MIN_PER_HOUR
/2); 
 732             wxFAIL_MSG( _T("unknown time zone") ); 
 736 // ---------------------------------------------------------------------------- 
 738 // ---------------------------------------------------------------------------- 
 741 bool wxDateTime::IsLeapYear(int year
, wxDateTime::Calendar cal
) 
 743     if ( year 
== Inv_Year 
) 
 744         year 
= GetCurrentYear(); 
 746     if ( cal 
== Gregorian 
) 
 748         // in Gregorian calendar leap years are those divisible by 4 except 
 749         // those divisible by 100 unless they're also divisible by 400 
 750         // (in some countries, like Russia and Greece, additional corrections 
 751         // exist, but they won't manifest themselves until 2700) 
 752         return (year 
% 4 == 0) && ((year 
% 100 != 0) || (year 
% 400 == 0)); 
 754     else if ( cal 
== Julian 
) 
 756         // in Julian calendar the rule is simpler 
 757         return year 
% 4 == 0; 
 761         wxFAIL_MSG(_T("unknown calendar")); 
 768 int wxDateTime::GetCentury(int year
) 
 770     return year 
> 0 ? year 
/ 100 : year 
/ 100 - 1; 
 774 int wxDateTime::ConvertYearToBC(int year
) 
 777     return year 
> 0 ? year 
: year 
- 1; 
 781 int wxDateTime::GetCurrentYear(wxDateTime::Calendar cal
) 
 786             return Now().GetYear(); 
 789             wxFAIL_MSG(_T("TODO")); 
 793             wxFAIL_MSG(_T("unsupported calendar")); 
 801 wxDateTime::Month 
wxDateTime::GetCurrentMonth(wxDateTime::Calendar cal
) 
 806             return Now().GetMonth(); 
 809             wxFAIL_MSG(_T("TODO")); 
 813             wxFAIL_MSG(_T("unsupported calendar")); 
 821 wxDateTime::wxDateTime_t 
wxDateTime::GetNumberOfDays(int year
, Calendar cal
) 
 823     if ( year 
== Inv_Year 
) 
 825         // take the current year if none given 
 826         year 
= GetCurrentYear(); 
 833             return IsLeapYear(year
) ? 366 : 365; 
 836             wxFAIL_MSG(_T("unsupported calendar")); 
 844 wxDateTime::wxDateTime_t 
wxDateTime::GetNumberOfDays(wxDateTime::Month month
, 
 846                                                      wxDateTime::Calendar cal
) 
 848     wxCHECK_MSG( month 
< MONTHS_IN_YEAR
, 0, _T("invalid month") ); 
 850     if ( cal 
== Gregorian 
|| cal 
== Julian 
) 
 852         if ( year 
== Inv_Year 
) 
 854             // take the current year if none given 
 855             year 
= GetCurrentYear(); 
 858         return GetNumOfDaysInMonth(year
, month
); 
 862         wxFAIL_MSG(_T("unsupported calendar")); 
 869 wxString 
wxDateTime::GetMonthName(wxDateTime::Month month
, 
 870                                   wxDateTime::NameFlags flags
) 
 872     wxCHECK_MSG( month 
!= Inv_Month
, wxEmptyString
, _T("invalid month") ); 
 874     // notice that we must set all the fields to avoid confusing libc (GNU one 
 875     // gets confused to a crash if we don't do this) 
 880     return CallStrftime(flags 
== Name_Abbr 
? _T("%b") : _T("%B"), &tm
); 
 886             ret 
= (flags 
== Name_Abbr 
? wxT("Jan"): wxT("January")); 
 889             ret 
= (flags 
== Name_Abbr 
? wxT("Feb"): wxT("Febuary")); 
 892             ret 
= (flags 
== Name_Abbr 
? wxT("Mar"): wxT("March")); 
 895             ret 
= (flags 
== Name_Abbr 
? wxT("Apr"): wxT("April")); 
 898             ret 
= (flags 
== Name_Abbr 
? wxT("May"): wxT("May")); 
 901             ret 
= (flags 
== Name_Abbr 
? wxT("Jun"): wxT("June")); 
 904             ret 
= (flags 
== Name_Abbr 
? wxT("Jul"): wxT("July")); 
 907             ret 
= (flags 
== Name_Abbr 
? wxT("Aug"): wxT("August")); 
 910             ret 
= (flags 
== Name_Abbr 
? wxT("Sep"): wxT("September")); 
 913             ret 
= (flags 
== Name_Abbr 
? wxT("Oct"): wxT("October")); 
 916             ret 
= (flags 
== Name_Abbr 
? wxT("Nov"): wxT("November")); 
 919             ret 
= (flags 
== Name_Abbr 
? wxT("Dec"): wxT("December")); 
 927 wxString 
wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday
, 
 928                                     wxDateTime::NameFlags flags
) 
 930     wxCHECK_MSG( wday 
!= Inv_WeekDay
, wxEmptyString
, _T("invalid weekday") ); 
 932     // take some arbitrary Sunday (but notice that the day should be such that 
 933     // after adding wday to it below we still have a valid date, e.g. don't 
 941     // and offset it by the number of days needed to get the correct wday 
 944     // call mktime() to normalize it... 
 947     // ... and call strftime() 
 948     return CallStrftime(flags 
== Name_Abbr 
? _T("%a") : _T("%A"), &tm
); 
 954             ret 
= (flags 
== Name_Abbr 
? wxT("Sun") : wxT("Sunday")); 
 957             ret 
= (flags 
== Name_Abbr 
? wxT("Mon") : wxT("Monday")); 
 960             ret 
= (flags 
== Name_Abbr 
? wxT("Tue") : wxT("Tuesday")); 
 963             ret 
= (flags 
== Name_Abbr 
? wxT("Wed") : wxT("Wednesday")); 
 966             ret 
= (flags 
== Name_Abbr 
? wxT("Thu") : wxT("Thursday")); 
 969             ret 
= (flags 
== Name_Abbr 
? wxT("Fri") : wxT("Friday")); 
 972             ret 
= (flags 
== Name_Abbr 
? wxT("Sat") : wxT("Saturday")); 
 981 void wxDateTime::GetAmPmStrings(wxString 
*am
, wxString 
*pm
) 
 986     // @Note: Do not call 'CallStrftime' here! CallStrftime checks the return code 
 987     // and causes an assertion failed if the buffer is to small (which is good) - OR - 
 988     // if strftime does not return anything because the format string is invalid - OR - 
 989     // if there are no 'am' / 'pm' tokens defined for the current locale (which is not good). 
 990     // wxDateTime::ParseTime will try several different formats to parse the time. 
 991     // As a result, GetAmPmStrings might get called, even if the current locale 
 992     // does not define any 'am' / 'pm' tokens. In this case, wxStrftime would 
 993     // assert, even though it is a perfectly legal use. 
 996         if (wxStrftime(buffer
, sizeof(buffer
)/sizeof(wxChar
), _T("%p"), &tm
) > 0) 
 997             *am 
= wxString(buffer
); 
1004         if (wxStrftime(buffer
, sizeof(buffer
)/sizeof(wxChar
), _T("%p"), &tm
) > 0) 
1005             *pm 
= wxString(buffer
); 
1011 // ---------------------------------------------------------------------------- 
1012 // Country stuff: date calculations depend on the country (DST, work days, 
1013 // ...), so we need to know which rules to follow. 
1014 // ---------------------------------------------------------------------------- 
1017 wxDateTime::Country 
wxDateTime::GetCountry() 
1019     // TODO use LOCALE_ICOUNTRY setting under Win32 
1021     if ( ms_country 
== Country_Unknown 
) 
1023         // try to guess from the time zone name 
1024         time_t t 
= time(NULL
); 
1026         struct tm 
*tm 
= wxLocaltime_r(&t
, &tmstruct
); 
1028         wxString tz 
= CallStrftime(_T("%Z"), tm
); 
1029         if ( tz 
== _T("WET") || tz 
== _T("WEST") ) 
1033         else if ( tz 
== _T("CET") || tz 
== _T("CEST") ) 
1035             ms_country 
= Country_EEC
; 
1037         else if ( tz 
== _T("MSK") || tz 
== _T("MSD") ) 
1039             ms_country 
= Russia
; 
1041         else if ( tz 
== _T("AST") || tz 
== _T("ADT") || 
1042                   tz 
== _T("EST") || tz 
== _T("EDT") || 
1043                   tz 
== _T("CST") || tz 
== _T("CDT") || 
1044                   tz 
== _T("MST") || tz 
== _T("MDT") || 
1045                   tz 
== _T("PST") || tz 
== _T("PDT") ) 
1051             // well, choose a default one 
1063 void wxDateTime::SetCountry(wxDateTime::Country country
) 
1065     ms_country 
= country
; 
1069 bool wxDateTime::IsWestEuropeanCountry(Country country
) 
1071     if ( country 
== Country_Default 
) 
1073         country 
= GetCountry(); 
1076     return (Country_WesternEurope_Start 
<= country
) && 
1077            (country 
<= Country_WesternEurope_End
); 
1080 // ---------------------------------------------------------------------------- 
1081 // DST calculations: we use 3 different rules for the West European countries, 
1082 // USA and for the rest of the world. This is undoubtedly false for many 
1083 // countries, but I lack the necessary info (and the time to gather it), 
1084 // please add the other rules here! 
1085 // ---------------------------------------------------------------------------- 
1088 bool wxDateTime::IsDSTApplicable(int year
, Country country
) 
1090     if ( year 
== Inv_Year 
) 
1092         // take the current year if none given 
1093         year 
= GetCurrentYear(); 
1096     if ( country 
== Country_Default 
) 
1098         country 
= GetCountry(); 
1105             // DST was first observed in the US and UK during WWI, reused 
1106             // during WWII and used again since 1966 
1107             return year 
>= 1966 || 
1108                    (year 
>= 1942 && year 
<= 1945) || 
1109                    (year 
== 1918 || year 
== 1919); 
1112             // assume that it started after WWII 
1118 wxDateTime 
wxDateTime::GetBeginDST(int year
, Country country
) 
1120     if ( year 
== Inv_Year 
) 
1122         // take the current year if none given 
1123         year 
= GetCurrentYear(); 
1126     if ( country 
== Country_Default 
) 
1128         country 
= GetCountry(); 
1131     if ( !IsDSTApplicable(year
, country
) ) 
1133         return wxInvalidDateTime
; 
1138     if ( IsWestEuropeanCountry(country
) || (country 
== Russia
) ) 
1140         // DST begins at 1 a.m. GMT on the last Sunday of March 
1141         if ( !dt
.SetToLastWeekDay(Sun
, Mar
, year
) ) 
1144             wxFAIL_MSG( _T("no last Sunday in March?") ); 
1147         dt 
+= wxTimeSpan::Hours(1); 
1149         // disable DST tests because it could result in an infinite recursion! 
1152     else switch ( country 
) 
1159                     // don't know for sure - assume it was in effect all year 
1164                     dt
.Set(1, Jan
, year
); 
1168                     // DST was installed Feb 2, 1942 by the Congress 
1169                     dt
.Set(2, Feb
, year
); 
1172                     // Oil embargo changed the DST period in the US 
1174                     dt
.Set(6, Jan
, 1974); 
1178                     dt
.Set(23, Feb
, 1975); 
1182                     // before 1986, DST begun on the last Sunday of April, but 
1183                     // in 1986 Reagan changed it to begin at 2 a.m. of the 
1184                     // first Sunday in April 
1187                         if ( !dt
.SetToLastWeekDay(Sun
, Apr
, year
) ) 
1190                             wxFAIL_MSG( _T("no first Sunday in April?") ); 
1195                         if ( !dt
.SetToWeekDay(Sun
, 1, Apr
, year
) ) 
1198                             wxFAIL_MSG( _T("no first Sunday in April?") ); 
1202                     dt 
+= wxTimeSpan::Hours(2); 
1204                     // TODO what about timezone?? 
1210             // assume Mar 30 as the start of the DST for the rest of the world 
1211             // - totally bogus, of course 
1212             dt
.Set(30, Mar
, year
); 
1219 wxDateTime 
wxDateTime::GetEndDST(int year
, Country country
) 
1221     if ( year 
== Inv_Year 
) 
1223         // take the current year if none given 
1224         year 
= GetCurrentYear(); 
1227     if ( country 
== Country_Default 
) 
1229         country 
= GetCountry(); 
1232     if ( !IsDSTApplicable(year
, country
) ) 
1234         return wxInvalidDateTime
; 
1239     if ( IsWestEuropeanCountry(country
) || (country 
== Russia
) ) 
1241         // DST ends at 1 a.m. GMT on the last Sunday of October 
1242         if ( !dt
.SetToLastWeekDay(Sun
, Oct
, year
) ) 
1244             // weirder and weirder... 
1245             wxFAIL_MSG( _T("no last Sunday in October?") ); 
1248         dt 
+= wxTimeSpan::Hours(1); 
1250         // disable DST tests because it could result in an infinite recursion! 
1253     else switch ( country 
) 
1260                     // don't know for sure - assume it was in effect all year 
1264                     dt
.Set(31, Dec
, year
); 
1268                     // the time was reset after the end of the WWII 
1269                     dt
.Set(30, Sep
, year
); 
1273                     // DST ends at 2 a.m. on the last Sunday of October 
1274                     if ( !dt
.SetToLastWeekDay(Sun
, Oct
, year
) ) 
1276                         // weirder and weirder... 
1277                         wxFAIL_MSG( _T("no last Sunday in October?") ); 
1280                     dt 
+= wxTimeSpan::Hours(2); 
1282                     // TODO what about timezone?? 
1287             // assume October 26th as the end of the DST - totally bogus too 
1288             dt
.Set(26, Oct
, year
); 
1294 // ---------------------------------------------------------------------------- 
1295 // constructors and assignment operators 
1296 // ---------------------------------------------------------------------------- 
1298 // return the current time with ms precision 
1299 /* static */ wxDateTime 
wxDateTime::UNow() 
1301     return wxDateTime(wxGetLocalTimeMillis()); 
1304 // the values in the tm structure contain the local time 
1305 wxDateTime
& wxDateTime::Set(const struct tm
& tm
) 
1308     time_t timet 
= mktime(&tm2
); 
1310     if ( timet 
== (time_t)-1 ) 
1312         // mktime() rather unintuitively fails for Jan 1, 1970 if the hour is 
1313         // less than timezone - try to make it work for this case 
1314         if ( tm2
.tm_year 
== 70 && tm2
.tm_mon 
== 0 && tm2
.tm_mday 
== 1 ) 
1316             return Set((time_t)( 
1318                        tm2
.tm_hour 
* MIN_PER_HOUR 
* SEC_PER_MIN 
+ 
1319                        tm2
.tm_min 
* SEC_PER_MIN 
+ 
1323         wxFAIL_MSG( _T("mktime() failed") ); 
1325         *this = wxInvalidDateTime
; 
1335 wxDateTime
& wxDateTime::Set(wxDateTime_t hour
, 
1336                             wxDateTime_t minute
, 
1337                             wxDateTime_t second
, 
1338                             wxDateTime_t millisec
) 
1340     // we allow seconds to be 61 to account for the leap seconds, even if we 
1341     // don't use them really 
1342     wxDATETIME_CHECK( hour 
< 24 && 
1346                       _T("Invalid time in wxDateTime::Set()") ); 
1348     // get the current date from system 
1350     struct tm 
*tm 
= GetTmNow(&tmstruct
); 
1352     wxDATETIME_CHECK( tm
, _T("wxLocaltime_r() failed") ); 
1354     // make a copy so it isn't clobbered by the call to mktime() below 
1359     tm1
.tm_min 
= minute
; 
1360     tm1
.tm_sec 
= second
; 
1362     // and the DST in case it changes on this date 
1365     if ( tm2
.tm_isdst 
!= tm1
.tm_isdst 
) 
1366         tm1
.tm_isdst 
= tm2
.tm_isdst
; 
1370     // and finally adjust milliseconds 
1371     return SetMillisecond(millisec
); 
1374 wxDateTime
& wxDateTime::Set(wxDateTime_t day
, 
1378                             wxDateTime_t minute
, 
1379                             wxDateTime_t second
, 
1380                             wxDateTime_t millisec
) 
1382     wxDATETIME_CHECK( hour 
< 24 && 
1386                       _T("Invalid time in wxDateTime::Set()") ); 
1388     ReplaceDefaultYearMonthWithCurrent(&year
, &month
); 
1390     wxDATETIME_CHECK( (0 < day
) && (day 
<= GetNumberOfDays(month
, year
)), 
1391                       _T("Invalid date in wxDateTime::Set()") ); 
1393     // the range of time_t type (inclusive) 
1394     static const int yearMinInRange 
= 1970; 
1395     static const int yearMaxInRange 
= 2037; 
1397     // test only the year instead of testing for the exact end of the Unix 
1398     // time_t range - it doesn't bring anything to do more precise checks 
1399     if ( year 
>= yearMinInRange 
&& year 
<= yearMaxInRange 
) 
1401         // use the standard library version if the date is in range - this is 
1402         // probably more efficient than our code 
1404         tm
.tm_year 
= year 
- 1900; 
1410         tm
.tm_isdst 
= -1;       // mktime() will guess it 
1414         // and finally adjust milliseconds 
1416             SetMillisecond(millisec
); 
1422         // do time calculations ourselves: we want to calculate the number of 
1423         // milliseconds between the given date and the epoch 
1425         // get the JDN for the midnight of this day 
1426         m_time 
= GetTruncatedJDN(day
, month
, year
); 
1427         m_time 
-= EPOCH_JDN
; 
1428         m_time 
*= SECONDS_PER_DAY 
* TIME_T_FACTOR
; 
1430         // JDN corresponds to GMT, we take localtime 
1431         Add(wxTimeSpan(hour
, minute
, second 
+ GetTimeZone(), millisec
)); 
1437 wxDateTime
& wxDateTime::Set(double jdn
) 
1439     // so that m_time will be 0 for the midnight of Jan 1, 1970 which is jdn 
1441     jdn 
-= EPOCH_JDN 
+ 0.5; 
1443     m_time
.Assign(jdn
*MILLISECONDS_PER_DAY
); 
1445     // JDNs always are in UTC, so we don't need any adjustments for time zone 
1450 wxDateTime
& wxDateTime::ResetTime() 
1454     if ( tm
.hour 
|| tm
.min 
|| tm
.sec 
|| tm
.msec 
) 
1467 // ---------------------------------------------------------------------------- 
1468 // DOS Date and Time Format functions 
1469 // ---------------------------------------------------------------------------- 
1470 // the dos date and time value is an unsigned 32 bit value in the format: 
1471 // YYYYYYYMMMMDDDDDhhhhhmmmmmmsssss 
1473 // Y = year offset from 1980 (0-127) 
1475 // D = day of month (1-31) 
1477 // m = minute (0-59) 
1478 // s = bisecond (0-29) each bisecond indicates two seconds 
1479 // ---------------------------------------------------------------------------- 
1481 wxDateTime
& wxDateTime::SetFromDOS(unsigned long ddt
) 
1486     long year 
= ddt 
& 0xFE000000; 
1491     long month 
= ddt 
& 0x1E00000; 
1496     long day 
= ddt 
& 0x1F0000; 
1500     long hour 
= ddt 
& 0xF800; 
1504     long minute 
= ddt 
& 0x7E0; 
1508     long second 
= ddt 
& 0x1F; 
1509     tm
.tm_sec 
= second 
* 2; 
1511     return Set(mktime(&tm
)); 
1514 unsigned long wxDateTime::GetAsDOS() const 
1517     time_t ticks 
= GetTicks(); 
1519     struct tm 
*tm 
= wxLocaltime_r(&ticks
, &tmstruct
); 
1521     long year 
= tm
->tm_year
; 
1525     long month 
= tm
->tm_mon
; 
1529     long day 
= tm
->tm_mday
; 
1532     long hour 
= tm
->tm_hour
; 
1535     long minute 
= tm
->tm_min
; 
1538     long second 
= tm
->tm_sec
; 
1541     ddt 
= year 
| month 
| day 
| hour 
| minute 
| second
; 
1545 // ---------------------------------------------------------------------------- 
1546 // time_t <-> broken down time conversions 
1547 // ---------------------------------------------------------------------------- 
1549 wxDateTime::Tm 
wxDateTime::GetTm(const TimeZone
& tz
) const 
1551     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1553     time_t time 
= GetTicks(); 
1554     if ( time 
!= (time_t)-1 ) 
1556         // use C RTL functions 
1559         if ( tz
.GetOffset() == -GetTimeZone() ) 
1561             // we are working with local time 
1562             tm 
= wxLocaltime_r(&time
, &tmstruct
); 
1564             // should never happen 
1565             wxCHECK_MSG( tm
, Tm(), _T("wxLocaltime_r() failed") ); 
1569             time 
+= (time_t)tz
.GetOffset(); 
1570 #if defined(__VMS__) || defined(__WATCOMC__) // time is unsigned so avoid warning 
1571             int time2 
= (int) time
; 
1577                 tm 
= wxGmtime_r(&time
, &tmstruct
); 
1579                 // should never happen 
1580                 wxCHECK_MSG( tm
, Tm(), _T("wxGmtime_r() failed") ); 
1584                 tm 
= (struct tm 
*)NULL
; 
1590             // adjust the milliseconds 
1592             long timeOnly 
= (m_time 
% MILLISECONDS_PER_DAY
).ToLong(); 
1593             tm2
.msec 
= (wxDateTime_t
)(timeOnly 
% 1000); 
1596         //else: use generic code below 
1599     // remember the time and do the calculations with the date only - this 
1600     // eliminates rounding errors of the floating point arithmetics 
1602     wxLongLong timeMidnight 
= m_time 
+ tz
.GetOffset() * 1000; 
1604     long timeOnly 
= (timeMidnight 
% MILLISECONDS_PER_DAY
).ToLong(); 
1606     // we want to always have positive time and timeMidnight to be really 
1607     // the midnight before it 
1610         timeOnly 
= MILLISECONDS_PER_DAY 
+ timeOnly
; 
1613     timeMidnight 
-= timeOnly
; 
1615     // calculate the Gregorian date from JDN for the midnight of our date: 
1616     // this will yield day, month (in 1..12 range) and year 
1618     // actually, this is the JDN for the noon of the previous day 
1619     long jdn 
= (timeMidnight 
/ MILLISECONDS_PER_DAY
).ToLong() + EPOCH_JDN
; 
1621     // CREDIT: code below is by Scott E. Lee (but bugs are mine) 
1623     wxASSERT_MSG( jdn 
> -2, _T("JDN out of range") ); 
1625     // calculate the century 
1626     long temp 
= (jdn 
+ JDN_OFFSET
) * 4 - 1; 
1627     long century 
= temp 
/ DAYS_PER_400_YEARS
; 
1629     // then the year and day of year (1 <= dayOfYear <= 366) 
1630     temp 
= ((temp 
% DAYS_PER_400_YEARS
) / 4) * 4 + 3; 
1631     long year 
= (century 
* 100) + (temp 
/ DAYS_PER_4_YEARS
); 
1632     long dayOfYear 
= (temp 
% DAYS_PER_4_YEARS
) / 4 + 1; 
1634     // and finally the month and day of the month 
1635     temp 
= dayOfYear 
* 5 - 3; 
1636     long month 
= temp 
/ DAYS_PER_5_MONTHS
; 
1637     long day 
= (temp 
% DAYS_PER_5_MONTHS
) / 5 + 1; 
1639     // month is counted from March - convert to normal 
1650     // year is offset by 4800 
1653     // check that the algorithm gave us something reasonable 
1654     wxASSERT_MSG( (0 < month
) && (month 
<= 12), _T("invalid month") ); 
1655     wxASSERT_MSG( (1 <= day
) && (day 
< 32), _T("invalid day") ); 
1657     // construct Tm from these values 
1659     tm
.year 
= (int)year
; 
1660     tm
.mon 
= (Month
)(month 
- 1); // algorithm yields 1 for January, not 0 
1661     tm
.mday 
= (wxDateTime_t
)day
; 
1662     tm
.msec 
= (wxDateTime_t
)(timeOnly 
% 1000); 
1663     timeOnly 
-= tm
.msec
; 
1664     timeOnly 
/= 1000;               // now we have time in seconds 
1666     tm
.sec 
= (wxDateTime_t
)(timeOnly 
% SEC_PER_MIN
); 
1668     timeOnly 
/= SEC_PER_MIN
;        // now we have time in minutes 
1670     tm
.min 
= (wxDateTime_t
)(timeOnly 
% MIN_PER_HOUR
); 
1673     tm
.hour 
= (wxDateTime_t
)(timeOnly 
/ MIN_PER_HOUR
); 
1678 wxDateTime
& wxDateTime::SetYear(int year
) 
1680     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1689 wxDateTime
& wxDateTime::SetMonth(Month month
) 
1691     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1700 wxDateTime
& wxDateTime::SetDay(wxDateTime_t mday
) 
1702     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1711 wxDateTime
& wxDateTime::SetHour(wxDateTime_t hour
) 
1713     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1722 wxDateTime
& wxDateTime::SetMinute(wxDateTime_t min
) 
1724     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1733 wxDateTime
& wxDateTime::SetSecond(wxDateTime_t sec
) 
1735     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1744 wxDateTime
& wxDateTime::SetMillisecond(wxDateTime_t millisecond
) 
1746     wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); 
1748     // we don't need to use GetTm() for this one 
1749     m_time 
-= m_time 
% 1000l; 
1750     m_time 
+= millisecond
; 
1755 // ---------------------------------------------------------------------------- 
1756 // wxDateTime arithmetics 
1757 // ---------------------------------------------------------------------------- 
1759 wxDateTime
& wxDateTime::Add(const wxDateSpan
& diff
) 
1763     tm
.year 
+= diff
.GetYears(); 
1764     tm
.AddMonths(diff
.GetMonths()); 
1766     // check that the resulting date is valid 
1767     if ( tm
.mday 
> GetNumOfDaysInMonth(tm
.year
, tm
.mon
) ) 
1769         // We suppose that when adding one month to Jan 31 we want to get Feb 
1770         // 28 (or 29), i.e. adding a month to the last day of the month should 
1771         // give the last day of the next month which is quite logical. 
1773         // Unfortunately, there is no logic way to understand what should 
1774         // Jan 30 + 1 month be - Feb 28 too or Feb 27 (assuming non leap year)? 
1775         // We make it Feb 28 (last day too), but it is highly questionable. 
1776         tm
.mday 
= GetNumOfDaysInMonth(tm
.year
, tm
.mon
); 
1779     tm
.AddDays(diff
.GetTotalDays()); 
1783     wxASSERT_MSG( IsSameTime(tm
), 
1784                   _T("Add(wxDateSpan) shouldn't modify time") ); 
1789 // ---------------------------------------------------------------------------- 
1790 // Weekday and monthday stuff 
1791 // ---------------------------------------------------------------------------- 
1793 // convert Sun, Mon, ..., Sat into 6, 0, ..., 5 
1794 static inline int ConvertWeekDayToMondayBase(int wd
) 
1796     return wd 
== wxDateTime::Sun 
? 6 : wd 
- 1; 
1801 wxDateTime::SetToWeekOfYear(int year
, wxDateTime_t numWeek
, WeekDay wd
) 
1803     wxASSERT_MSG( numWeek 
> 0, 
1804                   _T("invalid week number: weeks are counted from 1") ); 
1806     // Jan 4 always lies in the 1st week of the year 
1807     wxDateTime 
dt(4, Jan
, year
); 
1808     dt
.SetToWeekDayInSameWeek(wd
); 
1809     dt 
+= wxDateSpan::Weeks(numWeek 
- 1); 
1814 // use a separate function to avoid warnings about using deprecated 
1815 // SetToTheWeek in GetWeek below 
1817 SetToTheWeek(int year
, 
1818              wxDateTime::wxDateTime_t numWeek
, 
1819              wxDateTime::WeekDay weekday
, 
1820              wxDateTime::WeekFlags flags
) 
1822     // Jan 4 always lies in the 1st week of the year 
1823     wxDateTime 
dt(4, wxDateTime::Jan
, year
); 
1824     dt
.SetToWeekDayInSameWeek(weekday
, flags
); 
1825     dt 
+= wxDateSpan::Weeks(numWeek 
- 1); 
1830 bool wxDateTime::SetToTheWeek(wxDateTime_t numWeek
, 
1834     int year 
= GetYear(); 
1835     *this = ::SetToTheWeek(year
, numWeek
, weekday
, flags
); 
1836     if ( GetYear() != year 
) 
1838         // oops... numWeek was too big 
1845 wxDateTime 
wxDateTime::GetWeek(wxDateTime_t numWeek
, 
1847                                WeekFlags flags
) const 
1849     return ::SetToTheWeek(GetYear(), numWeek
, weekday
, flags
); 
1852 wxDateTime
& wxDateTime::SetToLastMonthDay(Month month
, 
1855     // take the current month/year if none specified 
1856     if ( year 
== Inv_Year 
) 
1858     if ( month 
== Inv_Month 
) 
1861     return Set(GetNumOfDaysInMonth(year
, month
), month
, year
); 
1864 wxDateTime
& wxDateTime::SetToWeekDayInSameWeek(WeekDay weekday
, WeekFlags flags
) 
1866     wxDATETIME_CHECK( weekday 
!= Inv_WeekDay
, _T("invalid weekday") ); 
1868     int wdayDst 
= weekday
, 
1869         wdayThis 
= GetWeekDay(); 
1870     if ( wdayDst 
== wdayThis 
) 
1876     if ( flags 
== Default_First 
) 
1878         flags 
= GetCountry() == USA 
? Sunday_First 
: Monday_First
; 
1881     // the logic below based on comparing weekday and wdayThis works if Sun (0) 
1882     // is the first day in the week, but breaks down for Monday_First case so 
1883     // we adjust the week days in this case 
1884     if ( flags 
== Monday_First 
) 
1886         if ( wdayThis 
== Sun 
) 
1888         if ( wdayDst 
== Sun 
) 
1891     //else: Sunday_First, nothing to do 
1893     // go forward or back in time to the day we want 
1894     if ( wdayDst 
< wdayThis 
) 
1896         return Subtract(wxDateSpan::Days(wdayThis 
- wdayDst
)); 
1898     else // weekday > wdayThis 
1900         return Add(wxDateSpan::Days(wdayDst 
- wdayThis
)); 
1904 wxDateTime
& wxDateTime::SetToNextWeekDay(WeekDay weekday
) 
1906     wxDATETIME_CHECK( weekday 
!= Inv_WeekDay
, _T("invalid weekday") ); 
1909     WeekDay wdayThis 
= GetWeekDay(); 
1910     if ( weekday 
== wdayThis 
) 
1915     else if ( weekday 
< wdayThis 
) 
1917         // need to advance a week 
1918         diff 
= 7 - (wdayThis 
- weekday
); 
1920     else // weekday > wdayThis 
1922         diff 
= weekday 
- wdayThis
; 
1925     return Add(wxDateSpan::Days(diff
)); 
1928 wxDateTime
& wxDateTime::SetToPrevWeekDay(WeekDay weekday
) 
1930     wxDATETIME_CHECK( weekday 
!= Inv_WeekDay
, _T("invalid weekday") ); 
1933     WeekDay wdayThis 
= GetWeekDay(); 
1934     if ( weekday 
== wdayThis 
) 
1939     else if ( weekday 
> wdayThis 
) 
1941         // need to go to previous week 
1942         diff 
= 7 - (weekday 
- wdayThis
); 
1944     else // weekday < wdayThis 
1946         diff 
= wdayThis 
- weekday
; 
1949     return Subtract(wxDateSpan::Days(diff
)); 
1952 bool wxDateTime::SetToWeekDay(WeekDay weekday
, 
1957     wxCHECK_MSG( weekday 
!= Inv_WeekDay
, false, _T("invalid weekday") ); 
1959     // we don't check explicitly that -5 <= n <= 5 because we will return false 
1960     // anyhow in such case - but may be should still give an assert for it? 
1962     // take the current month/year if none specified 
1963     ReplaceDefaultYearMonthWithCurrent(&year
, &month
); 
1967     // TODO this probably could be optimised somehow... 
1971         // get the first day of the month 
1972         dt
.Set(1, month
, year
); 
1975         WeekDay wdayFirst 
= dt
.GetWeekDay(); 
1977         // go to the first weekday of the month 
1978         int diff 
= weekday 
- wdayFirst
; 
1982         // add advance n-1 weeks more 
1985         dt 
+= wxDateSpan::Days(diff
); 
1987     else // count from the end of the month 
1989         // get the last day of the month 
1990         dt
.SetToLastMonthDay(month
, year
); 
1993         WeekDay wdayLast 
= dt
.GetWeekDay(); 
1995         // go to the last weekday of the month 
1996         int diff 
= wdayLast 
- weekday
; 
2000         // and rewind n-1 weeks from there 
2003         dt 
-= wxDateSpan::Days(diff
); 
2006     // check that it is still in the same month 
2007     if ( dt
.GetMonth() == month 
) 
2015         // no such day in this month 
2021 wxDateTime::wxDateTime_t 
GetDayOfYearFromTm(const wxDateTime::Tm
& tm
) 
2023     return (wxDateTime::wxDateTime_t
)(gs_cumulatedDays
[wxDateTime::IsLeapYear(tm
.year
)][tm
.mon
] + tm
.mday
); 
2026 wxDateTime::wxDateTime_t 
wxDateTime::GetDayOfYear(const TimeZone
& tz
) const 
2028     return GetDayOfYearFromTm(GetTm(tz
)); 
2031 wxDateTime::wxDateTime_t
 
2032 wxDateTime::GetWeekOfYear(wxDateTime::WeekFlags flags
, const TimeZone
& tz
) const 
2034     if ( flags 
== Default_First 
) 
2036         flags 
= GetCountry() == USA 
? Sunday_First 
: Monday_First
; 
2040     wxDateTime_t nDayInYear 
= GetDayOfYearFromTm(tm
); 
2042     int wdTarget 
= GetWeekDay(tz
); 
2043     int wdYearStart 
= wxDateTime(1, Jan
, GetYear()).GetWeekDay(); 
2045     if ( flags 
== Sunday_First 
) 
2047         // FIXME: First week is not calculated correctly. 
2048         week 
= (nDayInYear 
- wdTarget 
+ 7) / 7; 
2049         if ( wdYearStart 
== Wed 
|| wdYearStart 
== Thu 
) 
2052     else // week starts with monday 
2054         // adjust the weekdays to non-US style. 
2055         wdYearStart 
= ConvertWeekDayToMondayBase(wdYearStart
); 
2056         wdTarget 
= ConvertWeekDayToMondayBase(wdTarget
); 
2058         // quoting from http://www.cl.cam.ac.uk/~mgk25/iso-time.html: 
2060         //      Week 01 of a year is per definition the first week that has the 
2061         //      Thursday in this year, which is equivalent to the week that 
2062         //      contains the fourth day of January. In other words, the first 
2063         //      week of a new year is the week that has the majority of its 
2064         //      days in the new year. Week 01 might also contain days from the 
2065         //      previous year and the week before week 01 of a year is the last 
2066         //      week (52 or 53) of the previous year even if it contains days 
2067         //      from the new year. A week starts with Monday (day 1) and ends 
2068         //      with Sunday (day 7). 
2071         // if Jan 1 is Thursday or less, it is in the first week of this year 
2072         if ( wdYearStart 
< 4 ) 
2074             // count the number of entire weeks between Jan 1 and this date 
2075             week 
= (nDayInYear 
+ wdYearStart 
+ 6 - wdTarget
)/7; 
2077             // be careful to check for overflow in the next year 
2078             if ( week 
== 53 && tm
.mday 
- wdTarget 
> 28 ) 
2081         else // Jan 1 is in the last week of the previous year 
2083             // check if we happen to be at the last week of previous year: 
2084             if ( tm
.mon 
== Jan 
&& tm
.mday 
< 8 - wdYearStart 
) 
2085                 week 
= wxDateTime(31, Dec
, GetYear()-1).GetWeekOfYear(); 
2087                 week 
= (nDayInYear 
+ wdYearStart 
- 1 - wdTarget
)/7; 
2091     return (wxDateTime::wxDateTime_t
)week
; 
2094 wxDateTime::wxDateTime_t 
wxDateTime::GetWeekOfMonth(wxDateTime::WeekFlags flags
, 
2095                                                     const TimeZone
& tz
) const 
2098     wxDateTime dtMonthStart 
= wxDateTime(1, tm
.mon
, tm
.year
); 
2099     int nWeek 
= GetWeekOfYear(flags
) - dtMonthStart
.GetWeekOfYear(flags
) + 1; 
2102         // this may happen for January when Jan, 1 is the last week of the 
2104         nWeek 
+= IsLeapYear(tm
.year 
- 1) ? 53 : 52; 
2107     return (wxDateTime::wxDateTime_t
)nWeek
; 
2110 wxDateTime
& wxDateTime::SetToYearDay(wxDateTime::wxDateTime_t yday
) 
2112     int year 
= GetYear(); 
2113     wxDATETIME_CHECK( (0 < yday
) && (yday 
<= GetNumberOfDays(year
)), 
2114                       _T("invalid year day") ); 
2116     bool isLeap 
= IsLeapYear(year
); 
2117     for ( Month mon 
= Jan
; mon 
< Inv_Month
; wxNextMonth(mon
) ) 
2119         // for Dec, we can't compare with gs_cumulatedDays[mon + 1], but we 
2120         // don't need it neither - because of the CHECK above we know that 
2121         // yday lies in December then 
2122         if ( (mon 
== Dec
) || (yday 
<= gs_cumulatedDays
[isLeap
][mon 
+ 1]) ) 
2124             Set((wxDateTime::wxDateTime_t
)(yday 
- gs_cumulatedDays
[isLeap
][mon
]), mon
, year
); 
2133 // ---------------------------------------------------------------------------- 
2134 // Julian day number conversion and related stuff 
2135 // ---------------------------------------------------------------------------- 
2137 double wxDateTime::GetJulianDayNumber() const 
2139     return m_time
.ToDouble() / MILLISECONDS_PER_DAY 
+ EPOCH_JDN 
+ 0.5; 
2142 double wxDateTime::GetRataDie() const 
2144     // March 1 of the year 0 is Rata Die day -306 and JDN 1721119.5 
2145     return GetJulianDayNumber() - 1721119.5 - 306; 
2148 // ---------------------------------------------------------------------------- 
2149 // timezone and DST stuff 
2150 // ---------------------------------------------------------------------------- 
2152 int wxDateTime::IsDST(wxDateTime::Country country
) const 
2154     wxCHECK_MSG( country 
== Country_Default
, -1, 
2155                  _T("country support not implemented") ); 
2157     // use the C RTL for the dates in the standard range 
2158     time_t timet 
= GetTicks(); 
2159     if ( timet 
!= (time_t)-1 ) 
2162         tm 
*tm 
= wxLocaltime_r(&timet
, &tmstruct
); 
2164         wxCHECK_MSG( tm
, -1, _T("wxLocaltime_r() failed") ); 
2166         return tm
->tm_isdst
; 
2170         int year 
= GetYear(); 
2172         if ( !IsDSTApplicable(year
, country
) ) 
2174             // no DST time in this year in this country 
2178         return IsBetween(GetBeginDST(year
, country
), GetEndDST(year
, country
)); 
2182 wxDateTime
& wxDateTime::MakeTimezone(const TimeZone
& tz
, bool noDST
) 
2184     long secDiff 
= GetTimeZone() + tz
.GetOffset(); 
2186     // we need to know whether DST is or not in effect for this date unless 
2187     // the test disabled by the caller 
2188     if ( !noDST 
&& (IsDST() == 1) ) 
2190         // FIXME we assume that the DST is always shifted by 1 hour 
2194     return Add(wxTimeSpan::Seconds(secDiff
)); 
2197 wxDateTime
& wxDateTime::MakeFromTimezone(const TimeZone
& tz
, bool noDST
) 
2199     long secDiff 
= GetTimeZone() + tz
.GetOffset(); 
2201     // we need to know whether DST is or not in effect for this date unless 
2202     // the test disabled by the caller 
2203     if ( !noDST 
&& (IsDST() == 1) ) 
2205         // FIXME we assume that the DST is always shifted by 1 hour 
2209     return Subtract(wxTimeSpan::Seconds(secDiff
)); 
2212 // ---------------------------------------------------------------------------- 
2213 // wxDateTime to/from text representations 
2214 // ---------------------------------------------------------------------------- 
2216 wxString 
wxDateTime::Format(const wxChar 
*format
, const TimeZone
& tz
) const 
2218     wxCHECK_MSG( format
, wxEmptyString
, _T("NULL format in wxDateTime::Format") ); 
2220     // we have to use our own implementation if the date is out of range of 
2221     // strftime() or if we use non standard specificators 
2222     time_t time 
= GetTicks(); 
2223     if ( (time 
!= (time_t)-1) && !wxStrstr(format
, _T("%l")) ) 
2228         if ( tz
.GetOffset() == -GetTimeZone() ) 
2230             // we are working with local time 
2231             tm 
= wxLocaltime_r(&time
, &tmstruct
); 
2233             // should never happen 
2234             wxCHECK_MSG( tm
, wxEmptyString
, _T("wxLocaltime_r() failed") ); 
2238             time 
+= (int)tz
.GetOffset(); 
2240 #if defined(__VMS__) || defined(__WATCOMC__) // time is unsigned so avoid warning 
2241             int time2 
= (int) time
; 
2247                 tm 
= wxGmtime_r(&time
, &tmstruct
); 
2249                 // should never happen 
2250                 wxCHECK_MSG( tm
, wxEmptyString
, _T("wxGmtime_r() failed") ); 
2254                 tm 
= (struct tm 
*)NULL
; 
2258     //Windows CE doesn't support strftime or wcsftime, so we use the generic implementation 
2261             return CallStrftime(format
, tm
); 
2264         //else: use generic code below 
2267     // we only parse ANSI C format specifications here, no POSIX 2 
2268     // complications, no GNU extensions but we do add support for a "%l" format 
2269     // specifier allowing to get the number of milliseconds 
2272     // used for calls to strftime() when we only deal with time 
2273     struct tm tmTimeOnly
; 
2274     tmTimeOnly
.tm_hour 
= tm
.hour
; 
2275     tmTimeOnly
.tm_min 
= tm
.min
; 
2276     tmTimeOnly
.tm_sec 
= tm
.sec
; 
2277     tmTimeOnly
.tm_wday 
= 0; 
2278     tmTimeOnly
.tm_yday 
= 0; 
2279     tmTimeOnly
.tm_mday 
= 1;         // any date will do 
2280     tmTimeOnly
.tm_mon 
= 0; 
2281     tmTimeOnly
.tm_year 
= 76; 
2282     tmTimeOnly
.tm_isdst 
= 0;        // no DST, we adjust for tz ourselves 
2284     wxString tmp
, res
, fmt
; 
2285     for ( const wxChar 
*p 
= format
; *p
; p
++ ) 
2287         if ( *p 
!= _T('%') ) 
2295         // set the default format 
2298             case _T('Y'):               // year has 4 digits 
2302             case _T('j'):               // day of year has 3 digits 
2303             case _T('l'):               // milliseconds have 3 digits 
2307             case _T('w'):               // week day as number has only one 
2312                 // it's either another valid format specifier in which case 
2313                 // the format is "%02d" (for all the rest) or we have the 
2314                 // field width preceding the format in which case it will 
2315                 // override the default format anyhow 
2319         bool restart 
= true; 
2324             // start of the format specification 
2327                 case _T('a'):       // a weekday name 
2329                     // second parameter should be true for abbreviated names 
2330                     res 
+= GetWeekDayName(tm
.GetWeekDay(), 
2331                                           *p 
== _T('a') ? Name_Abbr 
: Name_Full
); 
2334                 case _T('b'):       // a month name 
2336                     res 
+= GetMonthName(tm
.mon
, 
2337                                         *p 
== _T('b') ? Name_Abbr 
: Name_Full
); 
2340                 case _T('c'):       // locale default date and time  representation 
2341                 case _T('x'):       // locale default date representation 
2344                     // the problem: there is no way to know what do these format 
2345                     // specifications correspond to for the current locale. 
2347                     // the solution: use a hack and still use strftime(): first 
2348                     // find the YEAR which is a year in the strftime() range (1970 
2349                     // - 2038) whose Jan 1 falls on the same week day as the Jan 1 
2350                     // of the real year. Then make a copy of the format and 
2351                     // replace all occurrences of YEAR in it with some unique 
2352                     // string not appearing anywhere else in it, then use 
2353                     // strftime() to format the date in year YEAR and then replace 
2354                     // YEAR back by the real year and the unique replacement 
2355                     // string back with YEAR. Notice that "all occurrences of YEAR" 
2356                     // means all occurrences of 4 digit as well as 2 digit form! 
2358                     // the bugs: we assume that neither of %c nor %x contains any 
2359                     // fields which may change between the YEAR and real year. For 
2360                     // example, the week number (%U, %W) and the day number (%j) 
2361                     // will change if one of these years is leap and the other one 
2364                         // find the YEAR: normally, for any year X, Jan 1 or the 
2365                         // year X + 28 is the same weekday as Jan 1 of X (because 
2366                         // the weekday advances by 1 for each normal X and by 2 
2367                         // for each leap X, hence by 5 every 4 years or by 35 
2368                         // which is 0 mod 7 every 28 years) but this rule breaks 
2369                         // down if there are years between X and Y which are 
2370                         // divisible by 4 but not leap (i.e. divisible by 100 but 
2371                         // not 400), hence the correction. 
2373                         int yearReal 
= GetYear(tz
); 
2374                         int mod28 
= yearReal 
% 28; 
2376                         // be careful to not go too far - we risk to leave the 
2381                             year 
= 1988 + mod28
;      // 1988 == 0 (mod 28) 
2385                             year 
= 1970 + mod28 
- 10; // 1970 == 10 (mod 28) 
2388                         int nCentury 
= year 
/ 100, 
2389                             nCenturyReal 
= yearReal 
/ 100; 
2391                         // need to adjust for the years divisble by 400 which are 
2392                         // not leap but are counted like leap ones if we just take 
2393                         // the number of centuries in between for nLostWeekDays 
2394                         int nLostWeekDays 
= (nCentury 
- nCenturyReal
) - 
2395                                             (nCentury 
/ 4 - nCenturyReal 
/ 4); 
2397                         // we have to gain back the "lost" weekdays: note that the 
2398                         // effect of this loop is to not do anything to 
2399                         // nLostWeekDays (which we won't use any more), but to 
2400                         // (indirectly) set the year correctly 
2401                         while ( (nLostWeekDays 
% 7) != 0 ) 
2403                             nLostWeekDays 
+= year
++ % 4 ? 1 : 2; 
2406                         // Keep year below 2000 so the 2digit year number 
2407                         // can never match the month or day of the month 
2408                         if (year
>=2000) year
-=28; 
2409                         // at any rate, we couldn't go further than 1988 + 9 + 28! 
2410                         wxASSERT_MSG( year 
< 2030, 
2411                                       _T("logic error in wxDateTime::Format") ); 
2413                         wxString strYear
, strYear2
; 
2414                         strYear
.Printf(_T("%d"), year
); 
2415                         strYear2
.Printf(_T("%d"), year 
% 100); 
2417                         // find four strings not occurring in format (this is surely 
2418                         // not the optimal way of doing it... improvements welcome!) 
2419                         wxString fmt2 
= format
; 
2420                         wxString replacement
,replacement2
,replacement3
,replacement4
; 
2421                         for (int rnr
=1; rnr
<5 ; rnr
++) { 
2422                                 wxString r 
= (wxChar
)-rnr
; 
2423                                 while ( fmt2
.Find(r
) != wxNOT_FOUND 
) 
2429                                         case 1: replacement
=r
; break; 
2430                                         case 2: replacement2
=r
; break; 
2431                                         case 3: replacement3
=r
; break; 
2432                                         case 4: replacement4
=r
; break; 
2435                         // replace all occurrences of year with it 
2436                         bool wasReplaced 
= fmt2
.Replace(strYear
, replacement
) > 0; 
2437                         // evaluation order ensures we always attempt the replacement. 
2438                         wasReplaced 
= (fmt2
.Replace(strYear2
, replacement2
) > 0) | wasReplaced 
; 
2440                         // use strftime() to format the same date but in supported 
2443                         // NB: we assume that strftime() doesn't check for the 
2444                         //     date validity and will happily format the date 
2445                         //     corresponding to Feb 29 of a non leap year (which 
2446                         //     may happen if yearReal was leap and year is not) 
2447                         struct tm tmAdjusted
; 
2449                         tmAdjusted
.tm_hour 
= tm
.hour
; 
2450                         tmAdjusted
.tm_min 
= tm
.min
; 
2451                         tmAdjusted
.tm_sec 
= tm
.sec
; 
2452                         tmAdjusted
.tm_wday 
= tm
.GetWeekDay(); 
2453                         tmAdjusted
.tm_yday 
= GetDayOfYear(); 
2454                         tmAdjusted
.tm_mday 
= tm
.mday
; 
2455                         tmAdjusted
.tm_mon 
= tm
.mon
; 
2456                         tmAdjusted
.tm_year 
= year 
- 1900; 
2457                         tmAdjusted
.tm_isdst 
= 0; // no DST, already adjusted 
2458                         wxString str 
= CallStrftime(*p 
== _T('c') ? _T("%c") 
2462                         // now replace the occurrence of 1999 with the real year 
2463                         // we do this in two stages to stop the 2 digit year 
2464                         // matching any substring of the 4 digit year. 
2465                         // Any day,month hours and minutes components should be safe due 
2466                         // to ensuring the range of the years. 
2467                         wxString strYearReal
, strYearReal2
; 
2468                         strYearReal
.Printf(_T("%04d"), yearReal
); 
2469                         strYearReal2
.Printf(_T("%02d"), yearReal 
% 100); 
2470                         str
.Replace(strYear
, replacement3
); 
2471                         str
.Replace(strYear2
,replacement4
); 
2472                         str
.Replace(replacement3
, strYearReal
); 
2473                         str
.Replace(replacement4
, strYearReal2
); 
2475                         // and replace back all occurrences of replacement string 
2478                             str
.Replace(replacement2
, strYear2
); 
2479                             str
.Replace(replacement
, strYear
); 
2485                     //Use "%m/%d/%y %H:%M:%S" format instead 
2486                     res 
+= wxString::Format(wxT("%02d/%02d/%04d %02d:%02d:%02d"), 
2487                             tm
.mon
+1,tm
.mday
, tm
.year
, tm
.hour
, tm
.min
, tm
.sec
); 
2491                 case _T('d'):       // day of a month (01-31) 
2492                     res 
+= wxString::Format(fmt
, tm
.mday
); 
2495                 case _T('H'):       // hour in 24h format (00-23) 
2496                     res 
+= wxString::Format(fmt
, tm
.hour
); 
2499                 case _T('I'):       // hour in 12h format (01-12) 
2501                         // 24h -> 12h, 0h -> 12h too 
2502                         int hour12 
= tm
.hour 
> 12 ? tm
.hour 
- 12 
2503                                                   : tm
.hour 
? tm
.hour 
: 12; 
2504                         res 
+= wxString::Format(fmt
, hour12
); 
2508                 case _T('j'):       // day of the year 
2509                     res 
+= wxString::Format(fmt
, GetDayOfYear(tz
)); 
2512                 case _T('l'):       // milliseconds (NOT STANDARD) 
2513                     res 
+= wxString::Format(fmt
, GetMillisecond(tz
)); 
2516                 case _T('m'):       // month as a number (01-12) 
2517                     res 
+= wxString::Format(fmt
, tm
.mon 
+ 1); 
2520                 case _T('M'):       // minute as a decimal number (00-59) 
2521                     res 
+= wxString::Format(fmt
, tm
.min
); 
2524                 case _T('p'):       // AM or PM string 
2526                     res 
+= CallStrftime(_T("%p"), &tmTimeOnly
); 
2528                     res 
+= (tmTimeOnly
.tm_hour 
> 12) ? wxT("pm") : wxT("am"); 
2532                 case _T('S'):       // second as a decimal number (00-61) 
2533                     res 
+= wxString::Format(fmt
, tm
.sec
); 
2536                 case _T('U'):       // week number in the year (Sunday 1st week day) 
2537                     res 
+= wxString::Format(fmt
, GetWeekOfYear(Sunday_First
, tz
)); 
2540                 case _T('W'):       // week number in the year (Monday 1st week day) 
2541                     res 
+= wxString::Format(fmt
, GetWeekOfYear(Monday_First
, tz
)); 
2544                 case _T('w'):       // weekday as a number (0-6), Sunday = 0 
2545                     res 
+= wxString::Format(fmt
, tm
.GetWeekDay()); 
2548                 // case _T('x'): -- handled with "%c" 
2550                 case _T('X'):       // locale default time representation 
2551                     // just use strftime() to format the time for us 
2553                     res 
+= CallStrftime(_T("%X"), &tmTimeOnly
); 
2555                     res 
+= wxString::Format(wxT("%02d:%02d:%02d"),tm
.hour
, tm
.min
, tm
.sec
); 
2559                 case _T('y'):       // year without century (00-99) 
2560                     res 
+= wxString::Format(fmt
, tm
.year 
% 100); 
2563                 case _T('Y'):       // year with century 
2564                     res 
+= wxString::Format(fmt
, tm
.year
); 
2567                 case _T('Z'):       // timezone name 
2569                     res 
+= CallStrftime(_T("%Z"), &tmTimeOnly
); 
2574                     // is it the format width? 
2576                     while ( *p 
== _T('-') || *p 
== _T('+') || 
2577                             *p 
== _T(' ') || wxIsdigit(*p
) ) 
2584                         // we've only got the flags and width so far in fmt 
2585                         fmt
.Prepend(_T('%')); 
2586                         fmt
.Append(_T('d')); 
2593                     // no, it wasn't the width 
2594                     wxFAIL_MSG(_T("unknown format specificator")); 
2596                     // fall through and just copy it nevertheless 
2598                 case _T('%'):       // a percent sign 
2602                 case 0:             // the end of string 
2603                     wxFAIL_MSG(_T("missing format at the end of string")); 
2605                     // just put the '%' which was the last char in format 
2615 // this function parses a string in (strict) RFC 822 format: see the section 5 
2616 // of the RFC for the detailed description, but briefly it's something of the 
2617 // form "Sat, 18 Dec 1999 00:48:30 +0100" 
2619 // this function is "strict" by design - it must reject anything except true 
2620 // RFC822 time specs. 
2622 // TODO a great candidate for using reg exps 
2623 const wxChar 
*wxDateTime::ParseRfc822Date(const wxChar
* date
) 
2625     wxCHECK_MSG( date
, (wxChar 
*)NULL
, _T("NULL pointer in wxDateTime::Parse") ); 
2627     const wxChar 
*p 
= date
; 
2628     const wxChar 
*comma 
= wxStrchr(p
, _T(',')); 
2631         // the part before comma is the weekday 
2633         // skip it for now - we don't use but might check that it really 
2634         // corresponds to the specfied date 
2637         if ( *p 
!= _T(' ') ) 
2639             wxLogDebug(_T("no space after weekday in RFC822 time spec")); 
2641             return (wxChar 
*)NULL
; 
2647     // the following 1 or 2 digits are the day number 
2648     if ( !wxIsdigit(*p
) ) 
2650         wxLogDebug(_T("day number expected in RFC822 time spec, none found")); 
2652         return (wxChar 
*)NULL
; 
2655     wxDateTime_t day 
= (wxDateTime_t
)(*p
++ - _T('0')); 
2656     if ( wxIsdigit(*p
) ) 
2659         day 
= (wxDateTime_t
)(day 
+ (*p
++ - _T('0'))); 
2662     if ( *p
++ != _T(' ') ) 
2664         return (wxChar 
*)NULL
; 
2667     // the following 3 letters specify the month 
2668     wxString 
monName(p
, 3); 
2670     if ( monName 
== _T("Jan") ) 
2672     else if ( monName 
== _T("Feb") ) 
2674     else if ( monName 
== _T("Mar") ) 
2676     else if ( monName 
== _T("Apr") ) 
2678     else if ( monName 
== _T("May") ) 
2680     else if ( monName 
== _T("Jun") ) 
2682     else if ( monName 
== _T("Jul") ) 
2684     else if ( monName 
== _T("Aug") ) 
2686     else if ( monName 
== _T("Sep") ) 
2688     else if ( monName 
== _T("Oct") ) 
2690     else if ( monName 
== _T("Nov") ) 
2692     else if ( monName 
== _T("Dec") ) 
2696         wxLogDebug(_T("Invalid RFC 822 month name '%s'"), monName
.c_str()); 
2698         return (wxChar 
*)NULL
; 
2703     if ( *p
++ != _T(' ') ) 
2705         return (wxChar 
*)NULL
; 
2709     if ( !wxIsdigit(*p
) ) 
2712         return (wxChar 
*)NULL
; 
2715     int year 
= *p
++ - _T('0'); 
2717     if ( !wxIsdigit(*p
) ) 
2719         // should have at least 2 digits in the year 
2720         return (wxChar 
*)NULL
; 
2724     year 
+= *p
++ - _T('0'); 
2726     // is it a 2 digit year (as per original RFC 822) or a 4 digit one? 
2727     if ( wxIsdigit(*p
) ) 
2730         year 
+= *p
++ - _T('0'); 
2732         if ( !wxIsdigit(*p
) ) 
2734             // no 3 digit years please 
2735             return (wxChar 
*)NULL
; 
2739         year 
+= *p
++ - _T('0'); 
2742     if ( *p
++ != _T(' ') ) 
2744         return (wxChar 
*)NULL
; 
2747     // time is in the format hh:mm:ss and seconds are optional 
2748     if ( !wxIsdigit(*p
) ) 
2750         return (wxChar 
*)NULL
; 
2753     wxDateTime_t hour 
= (wxDateTime_t
)(*p
++ - _T('0')); 
2755     if ( !wxIsdigit(*p
) ) 
2757         return (wxChar 
*)NULL
; 
2761     hour 
= (wxDateTime_t
)(hour 
+ (*p
++ - _T('0'))); 
2763     if ( *p
++ != _T(':') ) 
2765         return (wxChar 
*)NULL
; 
2768     if ( !wxIsdigit(*p
) ) 
2770         return (wxChar 
*)NULL
; 
2773     wxDateTime_t min 
= (wxDateTime_t
)(*p
++ - _T('0')); 
2775     if ( !wxIsdigit(*p
) ) 
2777         return (wxChar 
*)NULL
; 
2781     min 
= (wxDateTime_t
)(min 
+ *p
++ - _T('0')); 
2783     wxDateTime_t sec 
= 0; 
2784     if ( *p
++ == _T(':') ) 
2786         if ( !wxIsdigit(*p
) ) 
2788             return (wxChar 
*)NULL
; 
2791         sec 
= (wxDateTime_t
)(*p
++ - _T('0')); 
2793         if ( !wxIsdigit(*p
) ) 
2795             return (wxChar 
*)NULL
; 
2799         sec 
= (wxDateTime_t
)(sec 
+ *p
++ - _T('0')); 
2802     if ( *p
++ != _T(' ') ) 
2804         return (wxChar 
*)NULL
; 
2807     // and now the interesting part: the timezone 
2808     int offset 
wxDUMMY_INITIALIZE(0); 
2809     if ( *p 
== _T('-') || *p 
== _T('+') ) 
2811         // the explicit offset given: it has the form of hhmm 
2812         bool plus 
= *p
++ == _T('+'); 
2814         if ( !wxIsdigit(*p
) || !wxIsdigit(*(p 
+ 1)) ) 
2816             return (wxChar 
*)NULL
; 
2820         offset 
= MIN_PER_HOUR
*(10*(*p 
- _T('0')) + (*(p 
+ 1) - _T('0'))); 
2824         if ( !wxIsdigit(*p
) || !wxIsdigit(*(p 
+ 1)) ) 
2826             return (wxChar 
*)NULL
; 
2830         offset 
+= 10*(*p 
- _T('0')) + (*(p 
+ 1) - _T('0')); 
2841         // the symbolic timezone given: may be either military timezone or one 
2842         // of standard abbreviations 
2845             // military: Z = UTC, J unused, A = -1, ..., Y = +12 
2846             static const int offsets
[26] = 
2848                 //A  B   C   D   E   F   G   H   I    J    K    L    M 
2849                 -1, -2, -3, -4, -5, -6, -7, -8, -9,   0, -10, -11, -12, 
2850                 //N  O   P   R   Q   S   T   U   V    W    Z    Y    Z 
2851                 +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, 0 
2854             if ( *p 
< _T('A') || *p 
> _T('Z') || *p 
== _T('J') ) 
2856                 wxLogDebug(_T("Invalid militaty timezone '%c'"), *p
); 
2858                 return (wxChar 
*)NULL
; 
2861             offset 
= offsets
[*p
++ - _T('A')]; 
2867             if ( tz 
== _T("UT") || tz 
== _T("UTC") || tz 
== _T("GMT") ) 
2869             else if ( tz 
== _T("AST") ) 
2870                 offset 
= AST 
- GMT0
; 
2871             else if ( tz 
== _T("ADT") ) 
2872                 offset 
= ADT 
- GMT0
; 
2873             else if ( tz 
== _T("EST") ) 
2874                 offset 
= EST 
- GMT0
; 
2875             else if ( tz 
== _T("EDT") ) 
2876                 offset 
= EDT 
- GMT0
; 
2877             else if ( tz 
== _T("CST") ) 
2878                 offset 
= CST 
- GMT0
; 
2879             else if ( tz 
== _T("CDT") ) 
2880                 offset 
= CDT 
- GMT0
; 
2881             else if ( tz 
== _T("MST") ) 
2882                 offset 
= MST 
- GMT0
; 
2883             else if ( tz 
== _T("MDT") ) 
2884                 offset 
= MDT 
- GMT0
; 
2885             else if ( tz 
== _T("PST") ) 
2886                 offset 
= PST 
- GMT0
; 
2887             else if ( tz 
== _T("PDT") ) 
2888                 offset 
= PDT 
- GMT0
; 
2891                 wxLogDebug(_T("Unknown RFC 822 timezone '%s'"), p
); 
2893                 return (wxChar 
*)NULL
; 
2900         offset 
*= MIN_PER_HOUR
; 
2903     // the spec was correct, construct the date from the values we found 
2904     Set(day
, mon
, year
, hour
, min
, sec
); 
2905     MakeFromTimezone(TimeZone((wxDateTime_t
)(offset
*SEC_PER_MIN
))); 
2912 // returns the string containing strftime() format used for short dates in the 
2913 // current locale or an empty string 
2914 static wxString 
GetLocaleDateFormat() 
2918     // there is no setlocale() under Windows CE, so just always query the 
2921     if ( strcmp(setlocale(LC_ALL
, NULL
), "C") != 0 ) 
2924         // The locale was programatically set to non-C. We assume that this was 
2925         // done using wxLocale, in which case thread's current locale is also 
2926         // set to correct LCID value and we can use GetLocaleInfo to determine 
2927         // the correct formatting string: 
2929         LCID lcid 
= LOCALE_USER_DEFAULT
; 
2931         LCID lcid 
= GetThreadLocale(); 
2933         // according to MSDN 80 chars is max allowed for short date format 
2935         if ( ::GetLocaleInfo(lcid
, LOCALE_SSHORTDATE
, fmt
, WXSIZEOF(fmt
)) ) 
2937             wxChar chLast 
= _T('\0'); 
2938             size_t lastCount 
= 0; 
2939             for ( const wxChar 
*p 
= fmt
; /* NUL handled inside */; p
++ ) 
2949                     // these characters come in groups, start counting them 
2959                         // first deal with any special characters we have had 
2965                                     switch ( lastCount 
) 
2969                                             // these two are the same as we 
2970                                             // don't distinguish between 1 and 
2971                                             // 2 digits for days 
2984                                             wxFAIL_MSG( _T("too many 'd's") ); 
2989                                     switch ( lastCount 
) 
2993                                             // as for 'd' and 'dd' above 
3006                                             wxFAIL_MSG( _T("too many 'M's") ); 
3011                                     switch ( lastCount 
) 
3023                                             wxFAIL_MSG( _T("wrong number of 'y's") ); 
3028                                     // strftime() doesn't have era string, 
3029                                     // ignore this format 
3030                                     wxASSERT_MSG( lastCount 
<= 2, 
3031                                                   _T("too many 'g's") ); 
3035                                     wxFAIL_MSG( _T("unreachable") ); 
3042                         // not a special character so must be just a separator, 
3044                         if ( *p 
!= _T('\0') ) 
3046                             if ( *p 
== _T('%') ) 
3048                                 // this one needs to be escaped 
3056                 if ( *p 
== _T('\0') ) 
3060         //else: GetLocaleInfo() failed, leave fmtDate value unchanged and 
3061         //      try our luck with the default formats 
3063     //else: default C locale, default formats should work 
3068 #endif // __WINDOWS__ 
3070 const wxChar 
*wxDateTime::ParseFormat(const wxChar 
*date
, 
3071                                       const wxChar 
*format
, 
3072                                       const wxDateTime
& dateDef
) 
3074     wxCHECK_MSG( date 
&& format
, (wxChar 
*)NULL
, 
3075                  _T("NULL pointer in wxDateTime::ParseFormat()") ); 
3080     // what fields have we found? 
3081     bool haveWDay 
= false, 
3090     bool hourIsIn12hFormat 
= false, // or in 24h one? 
3091          isPM 
= false;              // AM by default 
3093     // and the value of the items we have (init them to get rid of warnings) 
3094     wxDateTime_t sec 
= 0, 
3097     WeekDay wday 
= Inv_WeekDay
; 
3098     wxDateTime_t yday 
= 0, 
3100     wxDateTime::Month mon 
= Inv_Month
; 
3103     const wxChar 
*input 
= date
; 
3104     for ( const wxChar 
*fmt 
= format
; *fmt
; fmt
++ ) 
3106         if ( *fmt 
!= _T('%') ) 
3108             if ( wxIsspace(*fmt
) ) 
3110                 // a white space in the format string matches 0 or more white 
3111                 // spaces in the input 
3112                 while ( wxIsspace(*input
) ) 
3119                 // any other character (not whitespace, not '%') must be 
3120                 // matched by itself in the input 
3121                 if ( *input
++ != *fmt 
) 
3124                     return (wxChar 
*)NULL
; 
3128             // done with this format char 
3132         // start of a format specification 
3134         // parse the optional width 
3136         while ( wxIsdigit(*++fmt
) ) 
3139             width 
+= *fmt 
- _T('0'); 
3142         // the default widths for the various fields 
3147                 case _T('Y'):               // year has 4 digits 
3151                 case _T('j'):               // day of year has 3 digits 
3152                 case _T('l'):               // milliseconds have 3 digits 
3156                 case _T('w'):               // week day as number has only one 
3161                     // default for all other fields 
3166         // then the format itself 
3169             case _T('a'):       // a weekday name 
3172                     int flag 
= *fmt 
== _T('a') ? Name_Abbr 
: Name_Full
; 
3173                     wday 
= GetWeekDayFromName(GetAlphaToken(input
), flag
); 
3174                     if ( wday 
== Inv_WeekDay 
) 
3177                         return (wxChar 
*)NULL
; 
3183             case _T('b'):       // a month name 
3186                     int flag 
= *fmt 
== _T('b') ? Name_Abbr 
: Name_Full
; 
3187                     mon 
= GetMonthFromName(GetAlphaToken(input
), flag
); 
3188                     if ( mon 
== Inv_Month 
) 
3191                         return (wxChar 
*)NULL
; 
3197             case _T('c'):       // locale default date and time  representation 
3201                     // this is the format which corresponds to ctime() output 
3202                     // and strptime("%c") should parse it, so try it first 
3203                     static const wxChar 
*fmtCtime 
= _T("%a %b %d %H:%M:%S %Y"); 
3205                     const wxChar 
*result 
= dt
.ParseFormat(input
, fmtCtime
); 
3208                         result 
= dt
.ParseFormat(input
, _T("%x %X")); 
3213                         result 
= dt
.ParseFormat(input
, _T("%X %x")); 
3218                         // we've tried everything and still no match 
3219                         return (wxChar 
*)NULL
; 
3224                     haveDay 
= haveMon 
= haveYear 
= 
3225                     haveHour 
= haveMin 
= haveSec 
= true; 
3239             case _T('d'):       // day of a month (01-31) 
3240                 if ( !GetNumericToken(width
, input
, &num
) || 
3241                         (num 
> 31) || (num 
< 1) ) 
3244                     return (wxChar 
*)NULL
; 
3247                 // we can't check whether the day range is correct yet, will 
3248                 // do it later - assume ok for now 
3250                 mday 
= (wxDateTime_t
)num
; 
3253             case _T('H'):       // hour in 24h format (00-23) 
3254                 if ( !GetNumericToken(width
, input
, &num
) || (num 
> 23) ) 
3257                     return (wxChar 
*)NULL
; 
3261                 hour 
= (wxDateTime_t
)num
; 
3264             case _T('I'):       // hour in 12h format (01-12) 
3265                 if ( !GetNumericToken(width
, input
, &num
) || !num 
|| (num 
> 12) ) 
3268                     return (wxChar 
*)NULL
; 
3272                 hourIsIn12hFormat 
= true; 
3273                 hour 
= (wxDateTime_t
)(num 
% 12);        // 12 should be 0 
3276             case _T('j'):       // day of the year 
3277                 if ( !GetNumericToken(width
, input
, &num
) || !num 
|| (num 
> 366) ) 
3280                     return (wxChar 
*)NULL
; 
3284                 yday 
= (wxDateTime_t
)num
; 
3287             case _T('m'):       // month as a number (01-12) 
3288                 if ( !GetNumericToken(width
, input
, &num
) || !num 
|| (num 
> 12) ) 
3291                     return (wxChar 
*)NULL
; 
3295                 mon 
= (Month
)(num 
- 1); 
3298             case _T('M'):       // minute as a decimal number (00-59) 
3299                 if ( !GetNumericToken(width
, input
, &num
) || (num 
> 59) ) 
3302                     return (wxChar 
*)NULL
; 
3306                 min 
= (wxDateTime_t
)num
; 
3309             case _T('p'):       // AM or PM string 
3311                     wxString am
, pm
, token 
= GetAlphaToken(input
); 
3313                     GetAmPmStrings(&am
, &pm
); 
3314                     if (am
.empty() && pm
.empty()) 
3315                         return (wxChar 
*)NULL
;  // no am/pm strings defined 
3316                     if ( token
.CmpNoCase(pm
) == 0 ) 
3320                     else if ( token
.CmpNoCase(am
) != 0 ) 
3323                         return (wxChar 
*)NULL
; 
3328             case _T('r'):       // time as %I:%M:%S %p 
3331                     input 
= dt
.ParseFormat(input
, _T("%I:%M:%S %p")); 
3335                         return (wxChar 
*)NULL
; 
3338                     haveHour 
= haveMin 
= haveSec 
= true; 
3347             case _T('R'):       // time as %H:%M 
3350                     input 
= dt
.ParseFormat(input
, _T("%H:%M")); 
3354                         return (wxChar 
*)NULL
; 
3357                     haveHour 
= haveMin 
= true; 
3365             case _T('S'):       // second as a decimal number (00-61) 
3366                 if ( !GetNumericToken(width
, input
, &num
) || (num 
> 61) ) 
3369                     return (wxChar 
*)NULL
; 
3373                 sec 
= (wxDateTime_t
)num
; 
3376             case _T('T'):       // time as %H:%M:%S 
3379                     input 
= dt
.ParseFormat(input
, _T("%H:%M:%S")); 
3383                         return (wxChar 
*)NULL
; 
3386                     haveHour 
= haveMin 
= haveSec 
= true; 
3395             case _T('w'):       // weekday as a number (0-6), Sunday = 0 
3396                 if ( !GetNumericToken(width
, input
, &num
) || (wday 
> 6) ) 
3399                     return (wxChar 
*)NULL
; 
3403                 wday 
= (WeekDay
)num
; 
3406             case _T('x'):       // locale default date representation 
3407 #ifdef HAVE_STRPTIME 
3408                 // try using strptime() -- it may fail even if the input is 
3409                 // correct but the date is out of range, so we will fall back 
3410                 // to our generic code anyhow 
3414                     const wxChar 
*result 
= CallStrptime(input
, "%x", &tm
); 
3419                         haveDay 
= haveMon 
= haveYear 
= true; 
3421                         year 
= 1900 + tm
.tm_year
; 
3422                         mon 
= (Month
)tm
.tm_mon
; 
3428 #endif // HAVE_STRPTIME 
3436                     // The above doesn't work for all locales, try to query 
3437                     // Windows for the right way of formatting the date: 
3438                     fmtDate 
= GetLocaleDateFormat(); 
3439                     if ( fmtDate
.empty() ) 
3442                         if ( IsWestEuropeanCountry(GetCountry()) || 
3443                              GetCountry() == Russia 
) 
3445                             fmtDate 
= _T("%d/%m/%y"); 
3446                             fmtDateAlt 
= _T("%m/%d/%y"); 
3450                             fmtDate 
= _T("%m/%d/%y"); 
3451                             fmtDateAlt 
= _T("%d/%m/%y"); 
3455                     const wxChar 
*result 
= dt
.ParseFormat(input
, fmtDate
); 
3457                     if ( !result 
&& !fmtDateAlt
.empty() ) 
3459                         // ok, be nice and try another one 
3460                         result 
= dt
.ParseFormat(input
, fmtDateAlt
); 
3466                         return (wxChar 
*)NULL
; 
3471                     haveDay 
= haveMon 
= haveYear 
= true; 
3482             case _T('X'):       // locale default time representation 
3483 #ifdef HAVE_STRPTIME 
3485                     // use strptime() to do it for us (FIXME !Unicode friendly) 
3487                     input 
= CallStrptime(input
, "%X", &tm
); 
3490                         return (wxChar 
*)NULL
; 
3493                     haveHour 
= haveMin 
= haveSec 
= true; 
3499 #else // !HAVE_STRPTIME 
3500                 // TODO under Win32 we can query the LOCALE_ITIME system 
3501                 //      setting which says whether the default time format is 
3504                     // try to parse what follows as "%H:%M:%S" and, if this 
3505                     // fails, as "%I:%M:%S %p" - this should catch the most 
3509                     const wxChar 
*result 
= dt
.ParseFormat(input
, _T("%T")); 
3512                         result 
= dt
.ParseFormat(input
, _T("%r")); 
3518                         return (wxChar 
*)NULL
; 
3521                     haveHour 
= haveMin 
= haveSec 
= true; 
3530 #endif // HAVE_STRPTIME/!HAVE_STRPTIME 
3533             case _T('y'):       // year without century (00-99) 
3534                 if ( !GetNumericToken(width
, input
, &num
) || (num 
> 99) ) 
3537                     return (wxChar 
*)NULL
; 
3542                 // TODO should have an option for roll over date instead of 
3543                 //      hard coding it here 
3544                 year 
= (num 
> 30 ? 1900 : 2000) + (wxDateTime_t
)num
; 
3547             case _T('Y'):       // year with century 
3548                 if ( !GetNumericToken(width
, input
, &num
) ) 
3551                     return (wxChar 
*)NULL
; 
3555                 year 
= (wxDateTime_t
)num
; 
3558             case _T('Z'):       // timezone name 
3559                 wxFAIL_MSG(_T("TODO")); 
3562             case _T('%'):       // a percent sign 
3563                 if ( *input
++ != _T('%') ) 
3566                     return (wxChar 
*)NULL
; 
3570             case 0:             // the end of string 
3571                 wxFAIL_MSG(_T("unexpected format end")); 
3575             default:            // not a known format spec 
3576                 return (wxChar 
*)NULL
; 
3580     // format matched, try to construct a date from what we have now 
3582     if ( dateDef
.IsValid() ) 
3584         // take this date as default 
3585         tmDef 
= dateDef
.GetTm(); 
3587     else if ( IsValid() ) 
3589         // if this date is valid, don't change it 
3594         // no default and this date is invalid - fall back to Today() 
3595         tmDef 
= Today().GetTm(); 
3606     // TODO we don't check here that the values are consistent, if both year 
3607     //      day and month/day were found, we just ignore the year day and we 
3608     //      also always ignore the week day 
3609     if ( haveMon 
&& haveDay 
) 
3611         if ( mday 
> GetNumOfDaysInMonth(tm
.year
, mon
) ) 
3613             wxLogDebug(_T("bad month day in wxDateTime::ParseFormat")); 
3615             return (wxChar 
*)NULL
; 
3621     else if ( haveYDay 
) 
3623         if ( yday 
> GetNumberOfDays(tm
.year
) ) 
3625             wxLogDebug(_T("bad year day in wxDateTime::ParseFormat")); 
3627             return (wxChar 
*)NULL
; 
3630         Tm tm2 
= wxDateTime(1, Jan
, tm
.year
).SetToYearDay(yday
).GetTm(); 
3637     if ( haveHour 
&& hourIsIn12hFormat 
&& isPM 
) 
3639         // translate to 24hour format 
3642     //else: either already in 24h format or no translation needed 
3662     // finally check that the week day is consistent -- if we had it 
3663     if ( haveWDay 
&& GetWeekDay() != wday 
) 
3665         wxLogDebug(_T("inconsistsnet week day in wxDateTime::ParseFormat()")); 
3673 const wxChar 
*wxDateTime::ParseDateTime(const wxChar 
*date
) 
3675     wxCHECK_MSG( date
, (wxChar 
*)NULL
, _T("NULL pointer in wxDateTime::Parse") ); 
3677     // Set to current day and hour, so strings like '14:00' becomes today at 
3678     // 14, not some other random date 
3679     wxDateTime dtDate 
= wxDateTime::Today(); 
3680     wxDateTime dtTime 
= wxDateTime::Today(); 
3682     const wxChar
* pchTime
; 
3684     // Try to parse the beginning of the string as a date 
3685     const wxChar
* pchDate 
= dtDate
.ParseDate(date
); 
3687     // We got a date in the beginning, see if there is a time specified after the date 
3690         // Skip spaces, as the ParseTime() function fails on spaces 
3691         while ( wxIsspace(*pchDate
) ) 
3694         pchTime 
= dtTime
.ParseTime(pchDate
); 
3696     else // no date in the beginning 
3698         // check and see if we have a time followed by a date 
3699         pchTime 
= dtTime
.ParseTime(date
); 
3702             while ( wxIsspace(*pchTime
) ) 
3705             pchDate 
= dtDate
.ParseDate(pchTime
); 
3709     // If we have a date specified, set our own data to the same date 
3710     if ( !pchDate 
|| !pchTime 
) 
3713     Set(dtDate
.GetDay(), dtDate
.GetMonth(), dtDate
.GetYear(), 
3714         dtTime
.GetHour(), dtTime
.GetMinute(), dtTime
.GetSecond(), 
3715         dtTime
.GetMillisecond()); 
3717     // Return endpoint of scan 
3718     return pchDate 
> pchTime 
? pchDate 
: pchTime
; 
3721 const wxChar 
*wxDateTime::ParseDate(const wxChar 
*date
) 
3723     // this is a simplified version of ParseDateTime() which understands only 
3724     // "today" (for wxDate compatibility) and digits only otherwise (and not 
3725     // all esoteric constructions ParseDateTime() knows about) 
3727     wxCHECK_MSG( date
, (wxChar 
*)NULL
, _T("NULL pointer in wxDateTime::Parse") ); 
3729     const wxChar 
*p 
= date
; 
3730     while ( wxIsspace(*p
) ) 
3733     // some special cases 
3737         int dayDiffFromToday
; 
3740         { wxTRANSLATE("today"),             0 }, 
3741         { wxTRANSLATE("yesterday"),        -1 }, 
3742         { wxTRANSLATE("tomorrow"),          1 }, 
3745     for ( size_t n 
= 0; n 
< WXSIZEOF(literalDates
); n
++ ) 
3747         const wxString dateStr 
= wxGetTranslation(literalDates
[n
].str
); 
3748         size_t len 
= dateStr
.length(); 
3749         if ( wxStrlen(p
) >= len 
) 
3751             wxString 
str(p
, len
); 
3752             if ( str
.CmpNoCase(dateStr
) == 0 ) 
3754                 // nothing can follow this, so stop here 
3757                 int dayDiffFromToday 
= literalDates
[n
].dayDiffFromToday
; 
3759                 if ( dayDiffFromToday 
) 
3761                     *this += wxDateSpan::Days(dayDiffFromToday
); 
3769     // We try to guess what we have here: for each new (numeric) token, we 
3770     // determine if it can be a month, day or a year. Of course, there is an 
3771     // ambiguity as some numbers may be days as well as months, so we also 
3772     // have the ability to back track. 
3775     bool haveDay 
= false,       // the months day? 
3776          haveWDay 
= false,      // the day of week? 
3777          haveMon 
= false,       // the month? 
3778          haveYear 
= false;      // the year? 
3780     // and the value of the items we have (init them to get rid of warnings) 
3781     WeekDay wday 
= Inv_WeekDay
; 
3782     wxDateTime_t day 
= 0; 
3783     wxDateTime::Month mon 
= Inv_Month
; 
3786     // tokenize the string 
3788     static const wxChar 
*dateDelimiters 
= _T(".,/-\t\r\n "); 
3789     wxStringTokenizer 
tok(p
, dateDelimiters
); 
3790     while ( tok
.HasMoreTokens() ) 
3792         wxString token 
= tok
.GetNextToken(); 
3798         if ( token
.ToULong(&val
) ) 
3800             // guess what this number is 
3806             if ( !haveMon 
&& val 
> 0 && val 
<= 12 ) 
3808                 // assume it is month 
3811             else // not the month 
3815                     // this can only be the year 
3818                 else // may be either day or year 
3820                     // use a leap year if we don't have the year yet to allow 
3821                     // dates like 2/29/1976 which would be rejected otherwise 
3822                     wxDateTime_t max_days 
= (wxDateTime_t
)( 
3824                         ? GetNumOfDaysInMonth(haveYear 
? year 
: 1976, mon
) 
3829                     if ( (val 
== 0) || (val 
> (unsigned long)max_days
) ) 
3834                     else // yes, suppose it's the day 
3848                 year 
= (wxDateTime_t
)val
; 
3857                 day 
= (wxDateTime_t
)val
; 
3863                 mon 
= (Month
)(val 
- 1); 
3866         else // not a number 
3868             // be careful not to overwrite the current mon value 
3869             Month mon2 
= GetMonthFromName(token
, Name_Full 
| Name_Abbr
); 
3870             if ( mon2 
!= Inv_Month 
) 
3875                     // but we already have a month - maybe we guessed wrong? 
3878                         // no need to check in month range as always < 12, but 
3879                         // the days are counted from 1 unlike the months 
3880                         day 
= (wxDateTime_t
)(mon 
+ 1); 
3885                         // could possible be the year (doesn't the year come 
3886                         // before the month in the japanese format?) (FIXME) 
3895             else // not a valid month name 
3897                 wday 
= GetWeekDayFromName(token
, Name_Full 
| Name_Abbr
); 
3898                 if ( wday 
!= Inv_WeekDay 
) 
3908                 else // not a valid weekday name 
3911                     static const wxChar 
*ordinals
[] = 
3913                         wxTRANSLATE("first"), 
3914                         wxTRANSLATE("second"), 
3915                         wxTRANSLATE("third"), 
3916                         wxTRANSLATE("fourth"), 
3917                         wxTRANSLATE("fifth"), 
3918                         wxTRANSLATE("sixth"), 
3919                         wxTRANSLATE("seventh"), 
3920                         wxTRANSLATE("eighth"), 
3921                         wxTRANSLATE("ninth"), 
3922                         wxTRANSLATE("tenth"), 
3923                         wxTRANSLATE("eleventh"), 
3924                         wxTRANSLATE("twelfth"), 
3925                         wxTRANSLATE("thirteenth"), 
3926                         wxTRANSLATE("fourteenth"), 
3927                         wxTRANSLATE("fifteenth"), 
3928                         wxTRANSLATE("sixteenth"), 
3929                         wxTRANSLATE("seventeenth"), 
3930                         wxTRANSLATE("eighteenth"), 
3931                         wxTRANSLATE("nineteenth"), 
3932                         wxTRANSLATE("twentieth"), 
3933                         // that's enough - otherwise we'd have problems with 
3934                         // composite (or not) ordinals 
3938                     for ( n 
= 0; n 
< WXSIZEOF(ordinals
); n
++ ) 
3940                         if ( token
.CmpNoCase(ordinals
[n
]) == 0 ) 
3946                     if ( n 
== WXSIZEOF(ordinals
) ) 
3948                         // stop here - something unknown 
3955                         // don't try anything here (as in case of numeric day 
3956                         // above) - the symbolic day spec should always 
3957                         // precede the month/year 
3963                     day 
= (wxDateTime_t
)(n 
+ 1); 
3968         nPosCur 
= tok
.GetPosition(); 
3971     // either no more tokens or the scan was stopped by something we couldn't 
3972     // parse - in any case, see if we can construct a date from what we have 
3973     if ( !haveDay 
&& !haveWDay 
) 
3975         wxLogDebug(_T("ParseDate: no day, no weekday hence no date.")); 
3980     if ( haveWDay 
&& (haveMon 
|| haveYear 
|| haveDay
) && 
3981          !(haveDay 
&& haveMon 
&& haveYear
) ) 
3983         // without adjectives (which we don't support here) the week day only 
3984         // makes sense completely separately or with the full date 
3985         // specification (what would "Wed 1999" mean?) 
3989     if ( !haveWDay 
&& haveYear 
&& !(haveDay 
&& haveMon
) ) 
3991         // may be we have month and day instead of day and year? 
3992         if ( haveDay 
&& !haveMon 
) 
3996                 // exchange day and month 
3997                 mon 
= (wxDateTime::Month
)(day 
- 1); 
3999                 // we're in the current year then 
4000                 if ( (year 
> 0) && (year 
<= (int)GetNumOfDaysInMonth(Inv_Year
, mon
)) ) 
4002                     day 
= (wxDateTime_t
)year
; 
4007                 //else: no, can't exchange, leave haveMon == false 
4013             // if we give the year, month and day must be given too 
4014             wxLogDebug(_T("ParseDate: day and month should be specified if year is.")); 
4022         mon 
= GetCurrentMonth(); 
4027         year 
= GetCurrentYear(); 
4032         // normally we check the day above but the check is optimistic in case 
4033         // we find the day before its month/year so we have to redo it now 
4034         if ( day 
> GetNumOfDaysInMonth(year
, mon
) ) 
4037         Set(day
, mon
, year
); 
4041             // check that it is really the same 
4042             if ( GetWeekDay() != wday 
) 
4044                 // inconsistency detected 
4045                 wxLogDebug(_T("ParseDate: inconsistent day/weekday.")); 
4047                 return (wxChar 
*)NULL
; 
4055         SetToWeekDayInSameWeek(wday
); 
4058     // return the pointer to the first unparsed char 
4060     if ( nPosCur 
&& wxStrchr(dateDelimiters
, *(p 
- 1)) ) 
4062         // if we couldn't parse the token after the delimiter, put back the 
4063         // delimiter as well 
4070 const wxChar 
*wxDateTime::ParseTime(const wxChar 
*time
) 
4072     wxCHECK_MSG( time
, (wxChar 
*)NULL
, _T("NULL pointer in wxDateTime::Parse") ); 
4074     // first try some extra things 
4081         { wxTRANSLATE("noon"),      12 }, 
4082         { wxTRANSLATE("midnight"),  00 }, 
4086     for ( size_t n 
= 0; n 
< WXSIZEOF(stdTimes
); n
++ ) 
4088         wxString timeString 
= wxGetTranslation(stdTimes
[n
].name
); 
4089         size_t len 
= timeString
.length(); 
4090         if ( timeString
.CmpNoCase(wxString(time
, len
)) == 0 ) 
4092             // casts required by DigitalMars 
4093             Set(stdTimes
[n
].hour
, wxDateTime_t(0), wxDateTime_t(0)); 
4099     // try all time formats we may think about in the order from longest to 
4102     // 12hour with AM/PM? 
4103     const wxChar 
*result 
= ParseFormat(time
, _T("%I:%M:%S %p")); 
4107         // normally, it's the same, but why not try it? 
4108         result 
= ParseFormat(time
, _T("%H:%M:%S")); 
4113         // 12hour with AM/PM but without seconds? 
4114         result 
= ParseFormat(time
, _T("%I:%M %p")); 
4120         result 
= ParseFormat(time
, _T("%H:%M")); 
4125         // just the hour and AM/PM? 
4126         result 
= ParseFormat(time
, _T("%I %p")); 
4132         result 
= ParseFormat(time
, _T("%H")); 
4137         // parse the standard format: normally it is one of the formats above 
4138         // but it may be set to something completely different by the user 
4139         result 
= ParseFormat(time
, _T("%X")); 
4142     // TODO: parse timezones 
4147 // ---------------------------------------------------------------------------- 
4148 // Workdays and holidays support 
4149 // ---------------------------------------------------------------------------- 
4151 bool wxDateTime::IsWorkDay(Country 
WXUNUSED(country
)) const 
4153     return !wxDateTimeHolidayAuthority::IsHoliday(*this); 
4156 // ============================================================================ 
4158 // ============================================================================ 
4160 wxDateSpan WXDLLIMPEXP_BASE 
operator*(int n
, const wxDateSpan
& ds
) 
4163     return ds1
.Multiply(n
); 
4166 // ============================================================================ 
4168 // ============================================================================ 
4170 wxTimeSpan WXDLLIMPEXP_BASE 
operator*(int n
, const wxTimeSpan
& ts
) 
4172     return wxTimeSpan(ts
).Multiply(n
); 
4175 // this enum is only used in wxTimeSpan::Format() below but we can't declare 
4176 // it locally to the method as it provokes an internal compiler error in egcs 
4177 // 2.91.60 when building with -O2 
4188 // not all strftime(3) format specifiers make sense here because, for example, 
4189 // a time span doesn't have a year nor a timezone 
4191 // Here are the ones which are supported (all of them are supported by strftime 
4193 //  %H          hour in 24 hour format 
4194 //  %M          minute (00 - 59) 
4195 //  %S          second (00 - 59) 
4198 // Also, for MFC CTimeSpan compatibility, we support 
4199 //  %D          number of days 
4201 // And, to be better than MFC :-), we also have 
4202 //  %E          number of wEeks 
4203 //  %l          milliseconds (000 - 999) 
4204 wxString 
wxTimeSpan::Format(const wxChar 
*format
) const 
4206     wxCHECK_MSG( format
, wxEmptyString
, _T("NULL format in wxTimeSpan::Format") ); 
4209     str
.Alloc(wxStrlen(format
)); 
4211     // Suppose we have wxTimeSpan ts(1 /* hour */, 2 /* min */, 3 /* sec */) 
4213     // Then, of course, ts.Format("%H:%M:%S") must return "01:02:03", but the 
4214     // question is what should ts.Format("%S") do? The code here returns "3273" 
4215     // in this case (i.e. the total number of seconds, not just seconds % 60) 
4216     // because, for me, this call means "give me entire time interval in 
4217     // seconds" and not "give me the seconds part of the time interval" 
4219     // If we agree that it should behave like this, it is clear that the 
4220     // interpretation of each format specifier depends on the presence of the 
4221     // other format specs in the string: if there was "%H" before "%M", we 
4222     // should use GetMinutes() % 60, otherwise just GetMinutes() &c 
4224     // we remember the most important unit found so far 
4225     TimeSpanPart partBiggest 
= Part_MSec
; 
4227     for ( const wxChar 
*pch 
= format
; *pch
; pch
++ ) 
4231         if ( ch 
== _T('%') ) 
4233             // the start of the format specification of the printf() below 
4234             wxString fmtPrefix 
= _T('%'); 
4239             ch 
= *++pch
;    // get the format spec char 
4243                     wxFAIL_MSG( _T("invalid format character") ); 
4249                     // skip the part below switch 
4254                     if ( partBiggest 
< Part_Day 
) 
4260                         partBiggest 
= Part_Day
; 
4265                     partBiggest 
= Part_Week
; 
4271                     if ( partBiggest 
< Part_Hour 
) 
4277                         partBiggest 
= Part_Hour
; 
4280                     fmtPrefix 
+= _T("02"); 
4284                     n 
= GetMilliseconds().ToLong(); 
4285                     if ( partBiggest 
< Part_MSec 
) 
4289                     //else: no need to reset partBiggest to Part_MSec, it is 
4290                     //      the least significant one anyhow 
4292                     fmtPrefix 
+= _T("03"); 
4297                     if ( partBiggest 
< Part_Min 
) 
4303                         partBiggest 
= Part_Min
; 
4306                     fmtPrefix 
+= _T("02"); 
4310                     n 
= GetSeconds().ToLong(); 
4311                     if ( partBiggest 
< Part_Sec 
) 
4317                         partBiggest 
= Part_Sec
; 
4320                     fmtPrefix 
+= _T("02"); 
4324             str 
+= wxString::Format(fmtPrefix 
+ _T("ld"), n
); 
4328             // normal character, just copy 
4336 // ============================================================================ 
4337 // wxDateTimeHolidayAuthority and related classes 
4338 // ============================================================================ 
4340 #include "wx/arrimpl.cpp" 
4342 WX_DEFINE_OBJARRAY(wxDateTimeArray
) 
4344 static int wxCMPFUNC_CONV
 
4345 wxDateTimeCompareFunc(wxDateTime 
**first
, wxDateTime 
**second
) 
4347     wxDateTime dt1 
= **first
, 
4350     return dt1 
== dt2 
? 0 : dt1 
< dt2 
? -1 : +1; 
4353 // ---------------------------------------------------------------------------- 
4354 // wxDateTimeHolidayAuthority 
4355 // ---------------------------------------------------------------------------- 
4357 wxHolidayAuthoritiesArray 
wxDateTimeHolidayAuthority::ms_authorities
; 
4360 bool wxDateTimeHolidayAuthority::IsHoliday(const wxDateTime
& dt
) 
4362     size_t count 
= ms_authorities
.size(); 
4363     for ( size_t n 
= 0; n 
< count
; n
++ ) 
4365         if ( ms_authorities
[n
]->DoIsHoliday(dt
) ) 
4376 wxDateTimeHolidayAuthority::GetHolidaysInRange(const wxDateTime
& dtStart
, 
4377                                                const wxDateTime
& dtEnd
, 
4378                                                wxDateTimeArray
& holidays
) 
4380     wxDateTimeArray hol
; 
4384     const size_t countAuth 
= ms_authorities
.size(); 
4385     for ( size_t nAuth 
= 0; nAuth 
< countAuth
; nAuth
++ ) 
4387         ms_authorities
[nAuth
]->DoGetHolidaysInRange(dtStart
, dtEnd
, hol
); 
4389         WX_APPEND_ARRAY(holidays
, hol
); 
4392     holidays
.Sort(wxDateTimeCompareFunc
); 
4394     return holidays
.size(); 
4398 void wxDateTimeHolidayAuthority::ClearAllAuthorities() 
4400     WX_CLEAR_ARRAY(ms_authorities
); 
4404 void wxDateTimeHolidayAuthority::AddAuthority(wxDateTimeHolidayAuthority 
*auth
) 
4406     ms_authorities
.push_back(auth
); 
4409 wxDateTimeHolidayAuthority::~wxDateTimeHolidayAuthority() 
4411     // required here for Darwin 
4414 // ---------------------------------------------------------------------------- 
4415 // wxDateTimeWorkDays 
4416 // ---------------------------------------------------------------------------- 
4418 bool wxDateTimeWorkDays::DoIsHoliday(const wxDateTime
& dt
) const 
4420     wxDateTime::WeekDay wd 
= dt
.GetWeekDay(); 
4422     return (wd 
== wxDateTime::Sun
) || (wd 
== wxDateTime::Sat
); 
4425 size_t wxDateTimeWorkDays::DoGetHolidaysInRange(const wxDateTime
& dtStart
, 
4426                                                 const wxDateTime
& dtEnd
, 
4427                                                 wxDateTimeArray
& holidays
) const 
4429     if ( dtStart 
> dtEnd 
) 
4431         wxFAIL_MSG( _T("invalid date range in GetHolidaysInRange") ); 
4438     // instead of checking all days, start with the first Sat after dtStart and 
4439     // end with the last Sun before dtEnd 
4440     wxDateTime dtSatFirst 
= dtStart
.GetNextWeekDay(wxDateTime::Sat
), 
4441                dtSatLast 
= dtEnd
.GetPrevWeekDay(wxDateTime::Sat
), 
4442                dtSunFirst 
= dtStart
.GetNextWeekDay(wxDateTime::Sun
), 
4443                dtSunLast 
= dtEnd
.GetPrevWeekDay(wxDateTime::Sun
), 
4446     for ( dt 
= dtSatFirst
; dt 
<= dtSatLast
; dt 
+= wxDateSpan::Week() ) 
4451     for ( dt 
= dtSunFirst
; dt 
<= dtSunLast
; dt 
+= wxDateSpan::Week() ) 
4456     return holidays
.GetCount(); 
4459 // ============================================================================ 
4460 // other helper functions 
4461 // ============================================================================ 
4463 // ---------------------------------------------------------------------------- 
4464 // iteration helpers: can be used to write a for loop over enum variable like 
4466 //  for ( m = wxDateTime::Jan; m < wxDateTime::Inv_Month; wxNextMonth(m) ) 
4467 // ---------------------------------------------------------------------------- 
4469 WXDLLIMPEXP_BASE 
void wxNextMonth(wxDateTime::Month
& m
) 
4471     wxASSERT_MSG( m 
< wxDateTime::Inv_Month
, _T("invalid month") ); 
4473     // no wrapping or the for loop above would never end! 
4474     m 
= (wxDateTime::Month
)(m 
+ 1); 
4477 WXDLLIMPEXP_BASE 
void wxPrevMonth(wxDateTime::Month
& m
) 
4479     wxASSERT_MSG( m 
< wxDateTime::Inv_Month
, _T("invalid month") ); 
4481     m 
= m 
== wxDateTime::Jan 
? wxDateTime::Inv_Month
 
4482                              : (wxDateTime::Month
)(m 
- 1); 
4485 WXDLLIMPEXP_BASE 
void wxNextWDay(wxDateTime::WeekDay
& wd
) 
4487     wxASSERT_MSG( wd 
< wxDateTime::Inv_WeekDay
, _T("invalid week day") ); 
4489     // no wrapping or the for loop above would never end! 
4490     wd 
= (wxDateTime::WeekDay
)(wd 
+ 1); 
4493 WXDLLIMPEXP_BASE 
void wxPrevWDay(wxDateTime::WeekDay
& wd
) 
4495     wxASSERT_MSG( wd 
< wxDateTime::Inv_WeekDay
, _T("invalid week day") ); 
4497     wd 
= wd 
== wxDateTime::Sun 
? wxDateTime::Inv_WeekDay
 
4498                                : (wxDateTime::WeekDay
)(wd 
- 1); 
4501 #endif // wxUSE_DATETIME