X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/cf44a61c2410fab7cc9b71c5f2578296e44c28e7..4b5e178a4c22caac92952131632641c63821fc0c:/src/common/datetime.cpp?ds=sidebyside diff --git a/src/common/datetime.cpp b/src/common/datetime.cpp index 12732e144b..16ccbc4094 100644 --- a/src/common/datetime.cpp +++ b/src/common/datetime.cpp @@ -16,10 +16,6 @@ // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// -// TODO: for $DEITY sake, someone please fix the #ifdef __WXWINCE__ everywhere, -// the proper way to do it is to implement (subset of) wxStrftime() for -// CE instead of this horror!! - /* * Implementation notes: * @@ -66,19 +62,23 @@ #if !defined(wxUSE_DATETIME) || wxUSE_DATETIME #ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" + #endif #include "wx/string.h" #include "wx/log.h" + #include "wx/intl.h" + #include "wx/stopwatch.h" // for wxGetLocalTimeMillis() + #include "wx/module.h" + #include "wx/crt.h" #endif // WX_PRECOMP -#include "wx/intl.h" #include "wx/thread.h" #include "wx/tokenzr.h" -#include "wx/module.h" #include #ifdef __WINDOWS__ - #include "wx/msw/wrapwin.h" #include #ifndef __WXWINCE__ #include @@ -86,7 +86,6 @@ #endif #include "wx/datetime.h" -#include "wx/stopwatch.h" // for wxGetLocalTimeMillis() const long wxDateTime::TIME_T_FACTOR = 1000l; @@ -94,17 +93,17 @@ const long wxDateTime::TIME_T_FACTOR = 1000l; template<> void wxStringReadValue(const wxString &s , wxDateTime &data ) { - data.ParseFormat(s,wxT("%Y-%m-%d %H:%M:%S")) ; + data.ParseFormat(s,"%Y-%m-%d %H:%M:%S", NULL); } template<> void wxStringWriteValue(wxString &s , const wxDateTime &data ) { - s = data.Format(wxT("%Y-%m-%d %H:%M:%S")) ; + s = data.Format("%Y-%m-%d %H:%M:%S"); } wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter , wxFromStringConverter) -#endif +#endif // wxUSE_EXTENDED_RTTI // // ---------------------------------------------------------------------------- @@ -164,12 +163,68 @@ wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter , wxFromStringCon #define WX_TIMEZONE wxGetTimeZone() #elif defined(__DARWIN__) #define WX_GMTOFF_IN_TM + #elif defined(__WXWINCE__) && defined(__VISUALC8__) + // _timezone is not present in dynamic run-time library + #if 0 + // Solution (1): use the function equivalent of _timezone + static long wxGetTimeZone() + { + static long s_Timezone = MAXLONG; // invalid timezone + if (s_Timezone == MAXLONG) + { + int t; + _get_timezone(& t); + s_Timezone = (long) t; + } + return s_Timezone; + } + #define WX_TIMEZONE wxGetTimeZone() + #elif 1 + // Solution (2): using GetTimeZoneInformation + static long wxGetTimeZone() + { + static long timezone = MAXLONG; // invalid timezone + if (timezone == MAXLONG) + { + TIME_ZONE_INFORMATION tzi; + ::GetTimeZoneInformation(&tzi); + timezone = tzi.Bias; + } + return timezone; + } + #define WX_TIMEZONE wxGetTimeZone() + #else + // Old method using _timezone: this symbol doesn't exist in the dynamic run-time library (i.e. using /MD) + #define WX_TIMEZONE _timezone + #endif #else // unknown platform - try timezone #define WX_TIMEZONE timezone #endif #endif // !WX_TIMEZONE && !WX_GMTOFF_IN_TM -#if wxUSE_THREADS +// everyone has strftime except Win CE unless VC8 is used +#if !defined(__WXWINCE__) || defined(__VISUALC8__) + #define HAVE_STRFTIME +#endif + +// NB: VC8 safe time functions could/should be used for wxMSW as well probably +#if defined(__WXWINCE__) && defined(__VISUALC8__) + +struct tm *wxLocaltime_r(const time_t *t, struct tm* tm) +{ + __time64_t t64 = *t; + return _localtime64_s(tm, &t64) == 0 ? tm : NULL; +} + +struct tm *wxGmtime_r(const time_t* t, struct tm* tm) +{ + __time64_t t64 = *t; + return _gmtime64_s(tm, &t64) == 0 ? tm : NULL; +} + +#else // !wxWinCE with VC8 + +#if (!defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)) && wxUSE_THREADS && !defined(__WINDOWS__) static wxMutex timeLock; #endif @@ -179,12 +234,23 @@ struct tm *wxLocaltime_r(const time_t* ticks, struct tm* temp) #if wxUSE_THREADS && !defined(__WINDOWS__) // No need to waste time with a mutex on windows since it's using // thread local storage for localtime anyway. - wxMutexLocker(timeLock); + wxMutexLocker locker(timeLock); +#endif + + // Borland CRT crashes when passed 0 ticks for some reason, see SF bug 1704438 +#ifdef __BORLANDC__ + if ( !*ticks ) + return NULL; #endif - memcpy(temp, localtime(ticks), sizeof(struct tm)); + + const tm * const t = localtime(ticks); + if ( !t ) + return NULL; + + memcpy(temp, t, sizeof(struct tm)); return temp; } -#endif +#endif // !HAVE_LOCALTIME_R #ifndef HAVE_GMTIME_R struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp) @@ -192,25 +258,32 @@ struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp) #if wxUSE_THREADS && !defined(__WINDOWS__) // No need to waste time with a mutex on windows since it's // using thread local storage for gmtime anyway. - wxMutexLocker(timeLock); + wxMutexLocker locker(timeLock); +#endif + +#ifdef __BORLANDC__ + if ( !*ticks ) + return NULL; #endif + + const tm * const t = gmtime(ticks); + if ( !t ) + return NULL; + memcpy(temp, gmtime(ticks), sizeof(struct tm)); return temp; } -#endif +#endif // !HAVE_GMTIME_R + +#endif // wxWinCE with VC8/other platforms // ---------------------------------------------------------------------------- // macros // ---------------------------------------------------------------------------- // debugging helper: just a convenient replacement of wxCHECK() -#define wxDATETIME_CHECK(expr, msg) \ - if ( !(expr) ) \ - { \ - wxFAIL_MSG(msg); \ - *this = wxInvalidDateTime; \ - return *this; \ - } +#define wxDATETIME_CHECK(expr, msg) \ + wxCHECK2_MSG(expr, *this = wxInvalidDateTime; return *this, msg) // ---------------------------------------------------------------------------- // private classes @@ -288,8 +361,8 @@ static const wxDateTime::wxDateTime_t gs_cumulatedDays[2][MONTHS_IN_YEAR] = // global data // ---------------------------------------------------------------------------- -const wxChar * wxDefaultDateTimeFormat = wxT("%c"); -const wxChar * wxDefaultTimeSpanFormat = wxT("%H:%M:%S"); +const char *wxDefaultDateTimeFormat = "%c"; +const char *wxDefaultTimeSpanFormat = "%H:%M:%S"; // in the fine tradition of ANSI C we use our equivalent of (time_t)-1 to // indicate an invalid wxDateTime object @@ -303,11 +376,14 @@ wxDateTime::Country wxDateTime::ms_country = wxDateTime::Country_Unknown; // debugger helper: shows what the date really is #ifdef __WXDEBUG__ -extern const wxChar *wxDumpDate(const wxDateTime* dt) +extern const char *wxDumpDate(const wxDateTime* dt) { - static wxChar buf[128]; + static char buf[128]; - wxStrcpy(buf, dt->Format(_T("%Y-%m-%d (%a) %H:%M:%S"))); + wxString fmt(dt->Format("%Y-%m-%d (%a) %H:%M:%S")); + wxStrlcpy(buf, + (fmt + " (" + dt->GetValue().ToString() + " ticks)").ToAscii(), + WXSIZEOF(buf)); return buf; } @@ -332,7 +408,6 @@ wxDateTime::wxDateTime_t GetNumOfDaysInMonth(int year, wxDateTime::Month month) // (in seconds) static int GetTimeZone() { -#ifdef WX_GMTOFF_IN_TM // set to true when the timezone is set static bool s_timezoneSet = false; static long gmtoffset = LONG_MAX; // invalid timezone @@ -343,22 +418,22 @@ static int GetTimeZone() // just call wxLocaltime_r() instead of figuring out whether this // system supports tzset(), _tzset() or something else time_t t = 0; - struct tm *tm; - struct tm tmstruct; + struct tm tm; - tm = wxLocaltime_r(&t, &tmstruct); + wxLocaltime_r(&t, &tm); s_timezoneSet = true; +#ifdef WX_GMTOFF_IN_TM // note that GMT offset is the opposite of time zone and so to return // consistent results in both WX_GMTOFF_IN_TM and !WX_GMTOFF_IN_TM // cases we have to negate it - gmtoffset = -tm->tm_gmtoff; + gmtoffset = -tm.tm_gmtoff; +#else // !WX_GMTOFF_IN_TM + gmtoffset = WX_TIMEZONE; +#endif // WX_GMTOFF_IN_TM/!WX_GMTOFF_IN_TM } return (int)gmtoffset; -#else // !WX_GMTOFF_IN_TM - return (int)WX_TIMEZONE; -#endif // WX_GMTOFF_IN_TM/!WX_GMTOFF_IN_TM } // return the integral part of the JDN for the midnight of the given date (to @@ -401,9 +476,10 @@ static long GetTruncatedJDN(wxDateTime::wxDateTime_t day, - JDN_OFFSET; } -#ifndef __WXWINCE__ +#ifdef HAVE_STRFTIME + // this function is a wrapper around strftime(3) adding error checking -static wxString CallStrftime(const wxChar *format, const tm* tm) +static wxString CallStrftime(const wxString& format, const tm* tm) { wxChar buf[4096]; // Create temp wxString here to work around mingw/cygwin bug 1046059 @@ -412,14 +488,17 @@ static wxString CallStrftime(const wxChar *format, const tm* tm) if ( !wxStrftime(buf, WXSIZEOF(buf), format, tm) ) { - // buffer is too small? + // if the format is valid, buffer must be too small? wxFAIL_MSG(_T("strftime() failed")); + + buf[0] = '\0'; } s = buf; return s; } -#endif + +#endif // HAVE_STRFTIME #ifdef HAVE_STRPTIME @@ -430,13 +509,13 @@ static wxString CallStrftime(const wxChar *format, const tm* tm) #endif // Unicode-friendly strptime() wrapper -static const wxChar * -CallStrptime(const wxChar *input, const char *fmt, tm *tm) +static const wxStringCharType * +CallStrptime(const wxStringCharType *input, const char *fmt, tm *tm) { // the problem here is that strptime() returns pointer into the string we // passed to it while we're really interested in the pointer into the // original, Unicode, string so we try to transform the pointer back -#if wxUSE_UNICODE +#if wxUSE_UNICODE_WCHAR wxCharBuffer inputMB(wxConvertWX2MB(input)); #else // ASCII const char * const inputMB = input; @@ -446,7 +525,7 @@ CallStrptime(const wxChar *input, const char *fmt, tm *tm) if ( !result ) return NULL; -#if wxUSE_UNICODE +#if wxUSE_UNICODE_WCHAR // FIXME: this is wrong in presence of surrogates &c return input + (result - inputMB.data()); #else // ASCII @@ -562,7 +641,9 @@ struct tm *wxDateTime::GetTmNow(struct tm *tmstruct) } // scans all digits (but no more than len) and returns the resulting number -static bool GetNumericToken(size_t len, const wxChar*& p, unsigned long *number) +static bool GetNumericToken(size_t len, + const wxStringCharType*& p, + unsigned long *number) { size_t n = 1; wxString s; @@ -578,7 +659,7 @@ static bool GetNumericToken(size_t len, const wxChar*& p, unsigned long *number) } // scans all alphabetic characters and returns the resulting string -static wxString GetAlphaToken(const wxChar*& p) +static wxString GetAlphaToken(const wxStringCharType*& p) { wxString s; while ( wxIsalpha(*p) ) @@ -633,7 +714,7 @@ void wxDateTime::Tm::ComputeWeekDay() // compute the week day from day/month/year: we use the dumbest algorithm // possible: just compute our JDN and then use the (simple to derive) // formula: weekday = (JDN + 1.5) % 7 - wday = (wxDateTime::wxDateTime_t)((wxDateTime::WeekDay)(GetTruncatedJDN(mday, mon, year) + 2) % 7); + wday = (wxDateTime::wxDateTime_t)((GetTruncatedJDN(mday, mon, year) + 2) % 7); } void wxDateTime::Tm::AddMonths(int monDiff) @@ -725,6 +806,7 @@ wxDateTime::TimeZone::TimeZone(wxDateTime::TZ tz) case wxDateTime::GMT10: case wxDateTime::GMT11: case wxDateTime::GMT12: + case wxDateTime::GMT13: m_offset = 3600*(tz - wxDateTime::GMT0); break; @@ -875,7 +957,7 @@ wxString wxDateTime::GetMonthName(wxDateTime::Month month, wxDateTime::NameFlags flags) { wxCHECK_MSG( month != Inv_Month, wxEmptyString, _T("invalid month") ); -#ifndef __WXWINCE__ +#ifdef HAVE_STRFTIME // notice that we must set all the fields to avoid confusing libc (GNU one // gets confused to a crash if we don't do this) tm tm; @@ -883,7 +965,7 @@ wxString wxDateTime::GetMonthName(wxDateTime::Month month, tm.tm_mon = month; return CallStrftime(flags == Name_Abbr ? _T("%b") : _T("%B"), &tm); -#else +#else // !HAVE_STRFTIME wxString ret; switch(month) { @@ -925,7 +1007,7 @@ wxString wxDateTime::GetMonthName(wxDateTime::Month month, break; } return ret; -#endif +#endif // HAVE_STRFTIME/!HAVE_STRFTIME } /* static */ @@ -933,7 +1015,7 @@ wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday, wxDateTime::NameFlags flags) { wxCHECK_MSG( wday != Inv_WeekDay, wxEmptyString, _T("invalid weekday") ); -#ifndef __WXWINCE__ +#ifdef HAVE_STRFTIME // take some arbitrary Sunday (but notice that the day should be such that // after adding wday to it below we still have a valid date, e.g. don't // take 28 here!) @@ -951,7 +1033,7 @@ wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday, // ... and call strftime() return CallStrftime(flags == Name_Abbr ? _T("%a") : _T("%A"), &tm); -#else +#else // !HAVE_STRFTIME wxString ret; switch(wday) { @@ -978,8 +1060,7 @@ wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday, break; } return ret; - -#endif +#endif // HAVE_STRFTIME/!HAVE_STRFTIME } /* static */ @@ -1057,9 +1138,9 @@ wxDateTime::Country wxDateTime::GetCountry() ms_country = USA; } } -#else +#else // __WXWINCE__ ms_country = USA; -#endif +#endif // !__WXWINCE__/__WXWINCE__ return ms_country; } @@ -1150,9 +1231,6 @@ wxDateTime wxDateTime::GetBeginDST(int year, Country country) } dt += wxTimeSpan::Hours(1); - - // disable DST tests because it could result in an infinite recursion! - dt.MakeGMT(true); } else switch ( country ) { @@ -1251,9 +1329,6 @@ wxDateTime wxDateTime::GetEndDST(int year, Country country) } dt += wxTimeSpan::Hours(1); - - // disable DST tests because it could result in an infinite recursion! - dt.MakeGMT(true); } else switch ( country ) { @@ -1469,6 +1544,16 @@ wxDateTime& wxDateTime::ResetTime() return *this; } +wxDateTime wxDateTime::GetDateOnly() const +{ + Tm tm = GetTm(); + tm.msec = + tm.sec = + tm.min = + tm.hour = 0; + return wxDateTime(tm); +} + // ---------------------------------------------------------------------------- // DOS Date and Time Format functions // ---------------------------------------------------------------------------- @@ -1522,6 +1607,7 @@ unsigned long wxDateTime::GetAsDOS() const time_t ticks = GetTicks(); struct tm tmstruct; struct tm *tm = wxLocaltime_r(&ticks, &tmstruct); + wxCHECK_MSG( tm, ULONG_MAX, _T("time can't be represented in DOS format") ); long year = tm->tm_year; year -= 80; @@ -1816,6 +1902,7 @@ wxDateTime::SetToWeekOfYear(int year, wxDateTime_t numWeek, WeekDay wd) return dt; } +#if WXWIN_COMPATIBILITY_2_6 // use a separate function to avoid warnings about using deprecated // SetToTheWeek in GetWeek below static wxDateTime @@ -1853,6 +1940,7 @@ wxDateTime wxDateTime::GetWeek(wxDateTime_t numWeek, { return ::SetToTheWeek(GetYear(), numWeek, weekday, flags); } +#endif // WXWIN_COMPATIBILITY_2_6 wxDateTime& wxDateTime::SetToLastMonthDay(Month month, int year) @@ -2218,13 +2306,16 @@ wxDateTime& wxDateTime::MakeFromTimezone(const TimeZone& tz, bool noDST) // wxDateTime to/from text representations // ---------------------------------------------------------------------------- -wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const +wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const { - wxCHECK_MSG( format, wxEmptyString, _T("NULL format in wxDateTime::Format") ); + wxCHECK_MSG( !format.empty(), wxEmptyString, + _T("NULL format in wxDateTime::Format") ); // we have to use our own implementation if the date is out of range of // strftime() or if we use non standard specificators +#ifdef HAVE_STRFTIME time_t time = GetTicks(); + if ( (time != (time_t)-1) && !wxStrstr(format, _T("%l")) ) { // use strftime() @@ -2259,15 +2350,14 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const tm = (struct tm *)NULL; } } -#ifndef __WXWINCE__ - //Windows CE doesn't support strftime or wcsftime, so we use the generic implementation + if ( tm ) { return CallStrftime(format, tm); } -#endif - //else: use generic code below } + //else: use generic code below +#endif // HAVE_STRFTIME // we only parse ANSI C format specifications here, no POSIX 2 // complications, no GNU extensions but we do add support for a "%l" format @@ -2287,7 +2377,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const tmTimeOnly.tm_isdst = 0; // no DST, we adjust for tz ourselves wxString tmp, res, fmt; - for ( const wxChar *p = format; *p; p++ ) + for ( wxString::const_iterator p = format.begin(); p != format.end(); ++p ) { if ( *p != _T('%') ) { @@ -2298,7 +2388,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const } // set the default format - switch ( *++p ) + switch ( (*++p).GetValue() ) { case _T('Y'): // year has 4 digits fmt = _T("%04d"); @@ -2327,7 +2417,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const restart = false; // start of the format specification - switch ( *p ) + switch ( (*p).GetValue() ) { case _T('a'): // a weekday name case _T('A'): @@ -2344,7 +2434,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const case _T('c'): // locale default date and time representation case _T('x'): // locale default date representation -#ifndef __WXWINCE__ +#ifdef HAVE_STRFTIME // // the problem: there is no way to know what do these format // specifications correspond to for the current locale. @@ -2366,7 +2456,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const // will change if one of these years is leap and the other one // is not! { - // find the YEAR: normally, for any year X, Jan 1 or the + // find the YEAR: normally, for any year X, Jan 1 of the // year X + 28 is the same weekday as Jan 1 of X (because // the weekday advances by 1 for each normal X and by 2 // for each leap X, hence by 5 every 4 years or by 35 @@ -2408,33 +2498,15 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const nLostWeekDays += year++ % 4 ? 1 : 2; } - // at any rate, we couldn't go further than 1988 + 9 + 28! - wxASSERT_MSG( year < 2030, - _T("logic error in wxDateTime::Format") ); + // finally move the year below 2000 so that the 2-digit + // year number can never match the month or day of the + // month when we do the replacements below + if ( year >= 2000 ) + year -= 28; - wxString strYear, strYear2; - strYear.Printf(_T("%d"), year); - strYear2.Printf(_T("%d"), year % 100); - - // find two strings not occurring in format (this is surely - // not the optimal way of doing it... improvements welcome!) - wxString fmt2 = format; - wxString replacement = (wxChar)-1; - while ( fmt2.Find(replacement) != wxNOT_FOUND ) - { - replacement << (wxChar)-1; - } - - wxString replacement2 = (wxChar)-2; - while ( fmt2.Find(replacement) != wxNOT_FOUND ) - { - replacement << (wxChar)-2; - } + wxASSERT_MSG( year >= 1970 && year < 2000, + _T("logic error in wxDateTime::Format") ); - // replace all occurrences of year with it - bool wasReplaced = fmt2.Replace(strYear, replacement) > 0; - if ( !wasReplaced ) - wasReplaced = fmt2.Replace(strYear2, replacement2) > 0; // use strftime() to format the same date but in supported // year @@ -2458,27 +2530,31 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const : _T("%x"), &tmAdjusted); - // now replace the occurrence of 1999 with the real year - wxString strYearReal, strYearReal2; - strYearReal.Printf(_T("%04d"), yearReal); - strYearReal2.Printf(_T("%02d"), yearReal % 100); - str.Replace(strYear, strYearReal); - str.Replace(strYear2, strYearReal2); - - // and replace back all occurrences of replacement string - if ( wasReplaced ) - { - str.Replace(replacement2, strYear2); - str.Replace(replacement, strYear); - } + // now replace the replacement year with the real year: + // notice that we have to replace the 4 digit year with + // a unique string not appearing in strftime() output + // first to prevent the 2 digit year from matching any + // substring of the 4 digit year (but any day, month, + // hours or minutes components should be safe because + // they are never in 70-99 range) + wxString replacement("|"); + while ( str.find(replacement) != wxString::npos ) + replacement += '|'; + + str.Replace(wxString::Format("%d", year), + replacement); + str.Replace(wxString::Format("%d", year % 100), + wxString::Format("%d", yearReal % 100)); + str.Replace(replacement, + wxString::Format("%d", yearReal)); res += str; } -#else - //Use "%m/%d/%y %H:%M:%S" format instead +#else // !HAVE_STRFTIME + // Use "%m/%d/%y %H:%M:%S" format instead res += wxString::Format(wxT("%02d/%02d/%04d %02d:%02d:%02d"), tm.mon+1,tm.mday, tm.year, tm.hour, tm.min, tm.sec); -#endif +#endif // HAVE_STRFTIME/!HAVE_STRFTIME break; case _T('d'): // day of a month (01-31) @@ -2515,11 +2591,11 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const break; case _T('p'): // AM or PM string -#ifndef __WXWINCE__ +#ifdef HAVE_STRFTIME res += CallStrftime(_T("%p"), &tmTimeOnly); -#else +#else // !HAVE_STRFTIME res += (tmTimeOnly.tm_hour > 12) ? wxT("pm") : wxT("am"); -#endif +#endif // HAVE_STRFTIME/!HAVE_STRFTIME break; case _T('S'): // second as a decimal number (00-61) @@ -2542,11 +2618,11 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const case _T('X'): // locale default time representation // just use strftime() to format the time for us -#ifndef __WXWINCE__ +#ifdef HAVE_STRFTIME res += CallStrftime(_T("%X"), &tmTimeOnly); -#else +#else // !HAVE_STRFTIME res += wxString::Format(wxT("%02d:%02d:%02d"),tm.hour, tm.min, tm.sec); -#endif +#endif // HAVE_STRFTIME/!HAVE_STRFTIME break; case _T('y'): // year without century (00-99) @@ -2558,7 +2634,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const break; case _T('Z'): // timezone name -#ifndef __WXWINCE__ +#ifdef HAVE_STRFTIME res += CallStrftime(_T("%Z"), &tmTimeOnly); #endif break; @@ -2613,12 +2689,12 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const // RFC822 time specs. // // TODO a great candidate for using reg exps -const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) +const char * +wxDateTime::ParseRfc822Date(const wxString& date, wxString::const_iterator *end) { - wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); - - const wxChar *p = date; - const wxChar *comma = wxStrchr(p, _T(',')); + // TODO: rewrite using iterators instead of wxChar pointers + const wxStringCharType *p = date.wx_str(); + const wxStringCharType *comma = wxStrchr(p, wxS(',')); if ( comma ) { // the part before comma is the weekday @@ -2631,7 +2707,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) { wxLogDebug(_T("no space after weekday in RFC822 time spec")); - return (wxChar *)NULL; + return NULL; } p++; // skip space @@ -2642,7 +2718,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) { wxLogDebug(_T("day number expected in RFC822 time spec, none found")); - return (wxChar *)NULL; + return NULL; } wxDateTime_t day = (wxDateTime_t)(*p++ - _T('0')); @@ -2654,7 +2730,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) if ( *p++ != _T(' ') ) { - return (wxChar *)NULL; + return NULL; } // the following 3 letters specify the month @@ -2688,21 +2764,21 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) { wxLogDebug(_T("Invalid RFC 822 month name '%s'"), monName.c_str()); - return (wxChar *)NULL; + return NULL; } p += 3; if ( *p++ != _T(' ') ) { - return (wxChar *)NULL; + return NULL; } // next is the year if ( !wxIsdigit(*p) ) { // no year? - return (wxChar *)NULL; + return NULL; } int year = *p++ - _T('0'); @@ -2710,7 +2786,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) if ( !wxIsdigit(*p) ) { // should have at least 2 digits in the year - return (wxChar *)NULL; + return NULL; } year *= 10; @@ -2725,7 +2801,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) if ( !wxIsdigit(*p) ) { // no 3 digit years please - return (wxChar *)NULL; + return NULL; } year *= 10; @@ -2734,20 +2810,20 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) if ( *p++ != _T(' ') ) { - return (wxChar *)NULL; + return NULL; } // time is in the format hh:mm:ss and seconds are optional if ( !wxIsdigit(*p) ) { - return (wxChar *)NULL; + return NULL; } wxDateTime_t hour = (wxDateTime_t)(*p++ - _T('0')); if ( !wxIsdigit(*p) ) { - return (wxChar *)NULL; + return NULL; } hour *= 10; @@ -2755,37 +2831,38 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) if ( *p++ != _T(':') ) { - return (wxChar *)NULL; + return NULL; } if ( !wxIsdigit(*p) ) { - return (wxChar *)NULL; + return NULL; } wxDateTime_t min = (wxDateTime_t)(*p++ - _T('0')); if ( !wxIsdigit(*p) ) { - return (wxChar *)NULL; + return NULL; } min *= 10; min = (wxDateTime_t)(min + *p++ - _T('0')); wxDateTime_t sec = 0; - if ( *p++ == _T(':') ) + if ( *p == _T(':') ) { + p++; if ( !wxIsdigit(*p) ) { - return (wxChar *)NULL; + return NULL; } sec = (wxDateTime_t)(*p++ - _T('0')); if ( !wxIsdigit(*p) ) { - return (wxChar *)NULL; + return NULL; } sec *= 10; @@ -2794,7 +2871,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) if ( *p++ != _T(' ') ) { - return (wxChar *)NULL; + return NULL; } // and now the interesting part: the timezone @@ -2806,7 +2883,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) ) { - return (wxChar *)NULL; + return NULL; } // hours @@ -2816,7 +2893,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) ) { - return (wxChar *)NULL; + return NULL; } // minutes @@ -2848,7 +2925,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) { wxLogDebug(_T("Invalid militaty timezone '%c'"), *p); - return (wxChar *)NULL; + return NULL; } offset = offsets[*p++ - _T('A')]; @@ -2883,7 +2960,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) { wxLogDebug(_T("Unknown RFC 822 timezone '%s'"), p); - return (wxChar *)NULL; + return NULL; } p += tz.length(); @@ -2895,9 +2972,13 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) // the spec was correct, construct the date from the values we found Set(day, mon, year, hour, min, sec); - MakeFromTimezone(TimeZone((wxDateTime_t)(offset*SEC_PER_MIN))); + MakeFromTimezone(TimeZone::Make(offset*SEC_PER_MIN)); - return p; + const size_t endpos = p - date.wx_str(); + if ( end ) + *end = date.begin() + endpos; + + return date.c_str() + endpos; } #ifdef __WINDOWS__ @@ -3060,12 +3141,13 @@ static wxString GetLocaleDateFormat() #endif // __WINDOWS__ -const wxChar *wxDateTime::ParseFormat(const wxChar *date, - const wxChar *format, - const wxDateTime& dateDef) +const char * +wxDateTime::ParseFormat(const wxString& date, + const wxString& format, + const wxDateTime& dateDef, + wxString::const_iterator *end) { - wxCHECK_MSG( date && format, (wxChar *)NULL, - _T("NULL pointer in wxDateTime::ParseFormat()") ); + wxCHECK_MSG( !format.empty(), NULL, "format can't be empty" ); wxString str; unsigned long num; @@ -3093,8 +3175,8 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, wxDateTime::Month mon = Inv_Month; int year = 0; - const wxChar *input = date; - for ( const wxChar *fmt = format; *fmt; fmt++ ) + const wxStringCharType *input = date.wx_str(); + for ( wxString::const_iterator fmt = format.begin(); fmt != format.end(); ++fmt ) { if ( *fmt != _T('%') ) { @@ -3114,7 +3196,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, if ( *input++ != *fmt ) { // no match - return (wxChar *)NULL; + return NULL; } } @@ -3135,7 +3217,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, // the default widths for the various fields if ( !width ) { - switch ( *fmt ) + switch ( (*fmt).GetValue() ) { case _T('Y'): // year has 4 digits width = 4; @@ -3157,7 +3239,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, } // then the format itself - switch ( *fmt ) + switch ( (*fmt).GetValue() ) { case _T('a'): // a weekday name case _T('A'): @@ -3167,7 +3249,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, if ( wday == Inv_WeekDay ) { // no match - return (wxChar *)NULL; + return NULL; } } haveWDay = true; @@ -3181,7 +3263,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, if ( mon == Inv_Month ) { // no match - return (wxChar *)NULL; + return NULL; } } haveMon = true; @@ -3191,25 +3273,16 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, { wxDateTime dt; - // this is the format which corresponds to ctime() output - // and strptime("%c") should parse it, so try it first - static const wxChar *fmtCtime = _T("%a %b %d %H:%M:%S %Y"); - - const wxChar *result = dt.ParseFormat(input, fmtCtime); - if ( !result ) - { - result = dt.ParseFormat(input, _T("%x %X")); - } - - if ( !result ) - { - result = dt.ParseFormat(input, _T("%X %x")); - } + const wxString inc(input); - if ( !result ) + // try the format which corresponds to ctime() output first + wxString::const_iterator endc; + if ( !dt.ParseFormat(inc, wxS("%a %b %d %H:%M:%S %Y"), &endc) && + !dt.ParseFormat(inc, wxS("%x %X"), &endc) && + !dt.ParseFormat(inc, wxS("%X %x"), &endc) ) { // we've tried everything and still no match - return (wxChar *)NULL; + return NULL; } Tm tm = dt.GetTm(); @@ -3225,7 +3298,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, mon = tm.mon; mday = tm.mday; - input = result; + input += endc - inc.begin(); } break; @@ -3234,7 +3307,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, (num > 31) || (num < 1) ) { // no match - return (wxChar *)NULL; + return NULL; } // we can't check whether the day range is correct yet, will @@ -3247,7 +3320,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, if ( !GetNumericToken(width, input, &num) || (num > 23) ) { // no match - return (wxChar *)NULL; + return NULL; } haveHour = true; @@ -3258,7 +3331,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, if ( !GetNumericToken(width, input, &num) || !num || (num > 12) ) { // no match - return (wxChar *)NULL; + return NULL; } haveHour = true; @@ -3270,7 +3343,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, if ( !GetNumericToken(width, input, &num) || !num || (num > 366) ) { // no match - return (wxChar *)NULL; + return NULL; } haveYDay = true; @@ -3281,7 +3354,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, if ( !GetNumericToken(width, input, &num) || !num || (num > 12) ) { // no match - return (wxChar *)NULL; + return NULL; } haveMon = true; @@ -3292,7 +3365,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, if ( !GetNumericToken(width, input, &num) || (num > 59) ) { // no match - return (wxChar *)NULL; + return NULL; } haveMin = true; @@ -3305,7 +3378,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, GetAmPmStrings(&am, &pm); if (am.empty() && pm.empty()) - return (wxChar *)NULL; // no am/pm strings defined + return NULL; // no am/pm strings defined if ( token.CmpNoCase(pm) == 0 ) { isPM = true; @@ -3313,7 +3386,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, else if ( token.CmpNoCase(am) != 0 ) { // no match - return (wxChar *)NULL; + return NULL; } } break; @@ -3321,11 +3394,11 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, case _T('r'): // time as %I:%M:%S %p { wxDateTime dt; - input = dt.ParseFormat(input, _T("%I:%M:%S %p")); + input = dt.ParseFormat(input, wxS("%I:%M:%S %p")); if ( !input ) { // no match - return (wxChar *)NULL; + return NULL; } haveHour = haveMin = haveSec = true; @@ -3340,11 +3413,11 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, case _T('R'): // time as %H:%M { wxDateTime dt; - input = dt.ParseFormat(input, _T("%H:%M")); + input = dt.ParseFormat(input, wxS("%H:%M")); if ( !input ) { // no match - return (wxChar *)NULL; + return NULL; } haveHour = haveMin = true; @@ -3359,7 +3432,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, if ( !GetNumericToken(width, input, &num) || (num > 61) ) { // no match - return (wxChar *)NULL; + return NULL; } haveSec = true; @@ -3373,7 +3446,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, if ( !input ) { // no match - return (wxChar *)NULL; + return NULL; } haveHour = haveMin = haveSec = true; @@ -3389,7 +3462,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, if ( !GetNumericToken(width, input, &num) || (wday > 6) ) { // no match - return (wxChar *)NULL; + return NULL; } haveWDay = true; @@ -3404,7 +3477,8 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, { struct tm tm; - const wxChar *result = CallStrptime(input, "%x", &tm); + const wxStringCharType * + result = CallStrptime(input, "%x", &tm); if ( result ) { input = result; @@ -3430,7 +3504,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, // Windows for the right way of formatting the date: fmtDate = GetLocaleDateFormat(); if ( fmtDate.empty() ) -#endif +#endif // __WINDOWS__ { if ( IsWestEuropeanCountry(GetCountry()) || GetCountry() == Russia ) @@ -3445,29 +3519,29 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, } } - const wxChar *result = dt.ParseFormat(input, fmtDate); - - if ( !result && !fmtDateAlt.empty() ) + const wxString indate(input); + wxString::const_iterator endDate; + if ( !dt.ParseFormat(indate, fmtDate, &endDate) ) { - // ok, be nice and try another one - result = dt.ParseFormat(input, fmtDateAlt); - } - - if ( !result ) - { - // bad luck - return (wxChar *)NULL; + // try another one if we have it + if ( fmtDateAlt.empty() || + !dt.ParseFormat(indate, fmtDateAlt, &endDate) ) + { + return NULL; + } } Tm tm = dt.GetTm(); - haveDay = haveMon = haveYear = true; + haveDay = + haveMon = + haveYear = true; year = tm.year; mon = tm.mon; mday = tm.mday; - input = result; + input += endDate - indate.begin(); } break; @@ -3480,7 +3554,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, input = CallStrptime(input, "%X", &tm); if ( !input ) { - return (wxChar *)NULL; + return NULL; } haveHour = haveMin = haveSec = true; @@ -3499,19 +3573,22 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, // common cases wxDateTime dt; - const wxChar *result = dt.ParseFormat(input, _T("%T")); + const wxStringCharType * + result = dt.ParseFormat(input, wxS("%T")); if ( !result ) { - result = dt.ParseFormat(input, _T("%r")); + result = dt.ParseFormat(input, wxS("%r")); } if ( !result ) { // no match - return (wxChar *)NULL; + return NULL; } - haveHour = haveMin = haveSec = true; + haveHour = + haveMin = + haveSec = true; Tm tm = dt.GetTm(); hour = tm.hour; @@ -3527,7 +3604,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, if ( !GetNumericToken(width, input, &num) || (num > 99) ) { // no match - return (wxChar *)NULL; + return NULL; } haveYear = true; @@ -3541,7 +3618,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, if ( !GetNumericToken(width, input, &num) ) { // no match - return (wxChar *)NULL; + return NULL; } haveYear = true; @@ -3556,7 +3633,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, if ( *input++ != _T('%') ) { // no match - return (wxChar *)NULL; + return NULL; } break; @@ -3566,7 +3643,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, // fall through default: // not a known format spec - return (wxChar *)NULL; + return NULL; } } @@ -3591,6 +3668,11 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, Tm tm = tmDef; // set the date + if ( haveMon ) + { + tm.mon = mon; + } + if ( haveYear ) { tm.year = year; @@ -3599,16 +3681,15 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, // TODO we don't check here that the values are consistent, if both year // day and month/day were found, we just ignore the year day and we // also always ignore the week day - if ( haveMon && haveDay ) + if ( haveDay ) { - if ( mday > GetNumOfDaysInMonth(tm.year, mon) ) + if ( mday > GetNumOfDaysInMonth(tm.year, tm.mon) ) { wxLogDebug(_T("bad month day in wxDateTime::ParseFormat")); - return (wxChar *)NULL; + return NULL; } - tm.mon = mon; tm.mday = mday; } else if ( haveYDay ) @@ -3617,7 +3698,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, { wxLogDebug(_T("bad year day in wxDateTime::ParseFormat")); - return (wxChar *)NULL; + return NULL; } Tm tm2 = wxDateTime(1, Jan, tm.year).SetToYearDay(yday).GetTm(); @@ -3660,73 +3741,82 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, return NULL; } - return input; + const size_t endpos = input - date.wx_str(); + if ( end ) + *end = date.begin() + endpos; + + return date.c_str() + endpos; } -const wxChar *wxDateTime::ParseDateTime(const wxChar *date) +const char * +wxDateTime::ParseDateTime(const wxString& date, wxString::const_iterator *end) { - wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); - // Set to current day and hour, so strings like '14:00' becomes today at // 14, not some other random date wxDateTime dtDate = wxDateTime::Today(); wxDateTime dtTime = wxDateTime::Today(); - const wxChar* pchTime; - - // Try to parse the beginning of the string as a date - const wxChar* pchDate = dtDate.ParseDate(date); + wxString::const_iterator + endTime, + endDate, + endBoth; - // We got a date in the beginning, see if there is a time specified after the date - if ( pchDate ) + // If we got a date in the beginning, see if there is a time specified + // after the date + if ( dtDate.ParseDate(date, &endDate) ) { // Skip spaces, as the ParseTime() function fails on spaces - while ( wxIsspace(*pchDate) ) - pchDate++; + while ( endDate != date.end() && wxIsspace(*endDate) ) + ++endDate; - pchTime = dtTime.ParseTime(pchDate); + const wxString timestr(endDate, date.end()); + if ( !dtTime.ParseTime(timestr, &endTime) ) + return NULL; + + endBoth = endDate + (endTime - timestr.begin()); } else // no date in the beginning { - // check and see if we have a time followed by a date - pchTime = dtTime.ParseTime(date); - if ( pchTime ) - { - while ( wxIsspace(*pchTime) ) - pchTime++; + // check if we have a time followed by a date + if ( !dtTime.ParseTime(date, &endTime) ) + return NULL; - pchDate = dtDate.ParseDate(pchTime); - } - } + while ( endTime != date.end() && wxIsspace(*endTime) ) + ++endTime; - // If we have a date specified, set our own data to the same date - if ( !pchDate || !pchTime ) - return NULL; + const wxString datestr(endTime, date.end()); + if ( !dtDate.ParseDate(datestr, &endDate) ) + return NULL; + + endBoth = endTime + (endDate - datestr.begin()); + } Set(dtDate.GetDay(), dtDate.GetMonth(), dtDate.GetYear(), dtTime.GetHour(), dtTime.GetMinute(), dtTime.GetSecond(), dtTime.GetMillisecond()); // Return endpoint of scan - return pchDate > pchTime ? pchDate : pchTime; + if ( end ) + *end = endBoth; + + return date.c_str() + (endBoth - date.begin()); } -const wxChar *wxDateTime::ParseDate(const wxChar *date) +const char * +wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end) { // this is a simplified version of ParseDateTime() which understands only // "today" (for wxDate compatibility) and digits only otherwise (and not // all esoteric constructions ParseDateTime() knows about) - wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); - - const wxChar *p = date; + const wxStringCharType *p = date.wx_str(); while ( wxIsspace(*p) ) p++; // some special cases static struct { - const wxChar *str; + const char *str; int dayDiffFromToday; } literalDates[] = { @@ -3754,7 +3844,11 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) *this += wxDateSpan::Days(dayDiffFromToday); } - return p; + const size_t endpos = p - date.wx_str(); + + if ( end ) + *end = date.begin() + endpos; + return date.c_str() + endpos; } } } @@ -3778,7 +3872,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) // tokenize the string size_t nPosCur = 0; - static const wxChar *dateDelimiters = _T(".,/-\t\r\n "); + static const wxStringCharType *dateDelimiters = wxS(".,/-\t\r\n "); wxStringTokenizer tok(p, dateDelimiters); while ( tok.HasMoreTokens() ) { @@ -3810,9 +3904,11 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) } else // may be either day or year { + // use a leap year if we don't have the year yet to allow + // dates like 2/29/1976 which would be rejected otherwise wxDateTime_t max_days = (wxDateTime_t)( haveMon - ? GetNumOfDaysInMonth(haveYear ? year : Inv_Year, mon) + ? GetNumOfDaysInMonth(haveYear ? year : 1976, mon) : 31 ); @@ -3885,8 +3981,8 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) } else // not a valid month name { - wday = GetWeekDayFromName(token, Name_Full | Name_Abbr); - if ( wday != Inv_WeekDay ) + WeekDay wday2 = GetWeekDayFromName(token, Name_Full | Name_Abbr); + if ( wday2 != Inv_WeekDay ) { // a week day if ( haveWDay ) @@ -3894,12 +3990,14 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) break; } + wday = wday2; + haveWDay = true; } else // not a valid weekday name { // try the ordinals - static const wxChar *ordinals[] = + static const char *ordinals[] = { wxTRANSLATE("first"), wxTRANSLATE("second"), @@ -3965,7 +4063,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) { wxLogDebug(_T("ParseDate: no day, no weekday hence no date.")); - return (wxChar *)NULL; + return NULL; } if ( haveWDay && (haveMon || haveYear || haveDay) && @@ -3974,7 +4072,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) // without adjectives (which we don't support here) the week day only // makes sense completely separately or with the full date // specification (what would "Wed 1999" mean?) - return (wxChar *)NULL; + return NULL; } if ( !haveWDay && haveYear && !(haveDay && haveMon) ) @@ -4004,7 +4102,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) // if we give the year, month and day must be given too wxLogDebug(_T("ParseDate: day and month should be specified if year is.")); - return (wxChar *)NULL; + return NULL; } } @@ -4020,6 +4118,11 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) if ( haveDay ) { + // normally we check the day above but the check is optimistic in case + // we find the day before its month/year so we have to redo it now + if ( day > GetNumOfDaysInMonth(year, mon) ) + return NULL; + Set(day, mon, year); if ( haveWDay ) @@ -4030,7 +4133,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) // inconsistency detected wxLogDebug(_T("ParseDate: inconsistent day/weekday.")); - return (wxChar *)NULL; + return NULL; } } } @@ -4050,17 +4153,20 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) p--; } - return p; + const size_t endpos = p - date.wx_str(); + if ( end ) + *end = date.begin() + endpos; + + return date.c_str() + endpos; } -const wxChar *wxDateTime::ParseTime(const wxChar *time) +const char * +wxDateTime::ParseTime(const wxString& time, wxString::const_iterator *end) { - wxCHECK_MSG( time, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); - // first try some extra things static const struct { - const wxChar *name; + const char *name; wxDateTime_t hour; } stdTimes[] = { @@ -4078,56 +4184,35 @@ const wxChar *wxDateTime::ParseTime(const wxChar *time) // casts required by DigitalMars Set(stdTimes[n].hour, wxDateTime_t(0), wxDateTime_t(0)); - return time + len; + if ( end ) + *end = time.begin() + len; + + return time.c_str() + len; } } // try all time formats we may think about in the order from longest to // shortest - - // 12hour with AM/PM? - const wxChar *result = ParseFormat(time, _T("%I:%M:%S %p")); - - if ( !result ) - { - // normally, it's the same, but why not try it? - result = ParseFormat(time, _T("%H:%M:%S")); - } - - if ( !result ) - { - // 12hour with AM/PM but without seconds? - result = ParseFormat(time, _T("%I:%M %p")); - } - - if ( !result ) - { - // without seconds? - result = ParseFormat(time, _T("%H:%M")); - } - - if ( !result ) + static const char *timeFormats[] = { - // just the hour and AM/PM? - result = ParseFormat(time, _T("%I %p")); - } + "%I:%M:%S %p", // 12hour with AM/PM + "%H:%M:%S", // could be the same or 24 hour one so try it too + "%I:%M %p", // 12hour with AM/PM but without seconds + "%H:%M:%S", // and a possibly 24 hour version without seconds + "%X", // possibly something from above or maybe something + // completely different -- try it last - if ( !result ) - { - // just the hour? - result = ParseFormat(time, _T("%H")); - } + // TODO: parse timezones + }; - if ( !result ) + for ( size_t nFmt = 0; nFmt < WXSIZEOF(timeFormats); nFmt++ ) { - // parse the standard format: normally it is one of the formats above - // but it may be set to something completely different by the user - result = ParseFormat(time, _T("%X")); + const char *result = ParseFormat(time, timeFormats[nFmt], end); + if ( result ) + return result; } - // TODO: parse timezones - - return result; + return NULL; } // ---------------------------------------------------------------------------- @@ -4187,12 +4272,21 @@ enum TimeSpanPart // And, to be better than MFC :-), we also have // %E number of wEeks // %l milliseconds (000 - 999) -wxString wxTimeSpan::Format(const wxChar *format) const +wxString wxTimeSpan::Format(const wxString& format) const { - wxCHECK_MSG( format, wxEmptyString, _T("NULL format in wxTimeSpan::Format") ); + // we deal with only positive time spans here and just add the sign in + // front for the negative ones + if ( IsNegative() ) + { + wxString str(Negate().Format(format)); + return "-" + str; + } + + wxCHECK_MSG( !format.empty(), wxEmptyString, + _T("NULL format in wxTimeSpan::Format") ); wxString str; - str.Alloc(wxStrlen(format)); + str.Alloc(format.length()); // Suppose we have wxTimeSpan ts(1 /* hour */, 2 /* min */, 3 /* sec */) // @@ -4210,18 +4304,21 @@ wxString wxTimeSpan::Format(const wxChar *format) const // we remember the most important unit found so far TimeSpanPart partBiggest = Part_MSec; - for ( const wxChar *pch = format; *pch; pch++ ) + for ( wxString::const_iterator pch = format.begin(); pch != format.end(); ++pch ) { wxChar ch = *pch; if ( ch == _T('%') ) { // the start of the format specification of the printf() below - wxString fmtPrefix = _T('%'); + wxString fmtPrefix(_T('%')); // the number long n; + // the number of digits for the format string, 0 if unused + unsigned digits = 0; + ch = *++pch; // get the format spec char switch ( ch ) { @@ -4263,7 +4360,7 @@ wxString wxTimeSpan::Format(const wxChar *format) const partBiggest = Part_Hour; } - fmtPrefix += _T("02"); + digits = 2; break; case _T('l'): @@ -4275,7 +4372,7 @@ wxString wxTimeSpan::Format(const wxChar *format) const //else: no need to reset partBiggest to Part_MSec, it is // the least significant one anyhow - fmtPrefix += _T("03"); + digits = 3; break; case _T('M'): @@ -4289,7 +4386,7 @@ wxString wxTimeSpan::Format(const wxChar *format) const partBiggest = Part_Min; } - fmtPrefix += _T("02"); + digits = 2; break; case _T('S'): @@ -4303,10 +4400,15 @@ wxString wxTimeSpan::Format(const wxChar *format) const partBiggest = Part_Sec; } - fmtPrefix += _T("02"); + digits = 2; break; } + if ( digits ) + { + fmtPrefix << _T("0") << digits; + } + str += wxString::Format(fmtPrefix + _T("ld"), n); } else @@ -4484,4 +4586,30 @@ WXDLLIMPEXP_BASE void wxPrevWDay(wxDateTime::WeekDay& wd) : (wxDateTime::WeekDay)(wd - 1); } +#ifdef __WXMSW__ + +wxDateTime& wxDateTime::SetFromMSWSysTime(const SYSTEMTIME& st) +{ + return Set(st.wDay, + static_cast(wxDateTime::Jan + st.wMonth - 1), + st.wYear, + 0, 0, 0); +} + +void wxDateTime::GetAsMSWSysTime(SYSTEMTIME* st) const +{ + const wxDateTime::Tm tm(GetTm()); + + st->wYear = (WXWORD)tm.year; + st->wMonth = (WXWORD)(tm.mon - wxDateTime::Jan + 1); + st->wDay = tm.mday; + + st->wDayOfWeek = + st->wHour = + st->wMinute = + st->wSecond = + st->wMilliseconds = 0; +} +#endif // __WXMSW__ + #endif // wxUSE_DATETIME