X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9a83f860948059b0273b5cc6d9e43fadad3ebfca..87f0b1323b7ac77f02133b836c8dfee63b0fd387:/src/common/datetimefmt.cpp?ds=sidebyside diff --git a/src/common/datetimefmt.cpp b/src/common/datetimefmt.cpp index 516d9a3347..fda6c0ad52 100644 --- a/src/common/datetimefmt.cpp +++ b/src/common/datetimefmt.cpp @@ -34,7 +34,7 @@ #if !defined(wxUSE_DATETIME) || wxUSE_DATETIME #ifndef WX_PRECOMP - #ifdef __WXMSW__ + #ifdef __WINDOWS__ #include "wx/msw/wrapwin.h" #endif #include "wx/string.h" @@ -57,6 +57,7 @@ #endif #include "wx/datetime.h" +#include "wx/time.h" // ============================================================================ // implementation of wxDateTime @@ -68,8 +69,6 @@ extern void InitTm(struct tm& tm); -extern int GetTimeZone(); - extern wxString CallStrftime(const wxString& format, const tm* tm); // ---------------------------------------------------------------------------- @@ -292,8 +291,14 @@ ParseFormatAt(wxString::const_iterator& p, const wxString str(p, end); wxString::const_iterator endParse; wxDateTime dt; - if ( dt.ParseFormat(str, fmt, &endParse) || - (!fmtAlt.empty() && dt.ParseFormat(str, fmtAlt, &endParse)) ) + + // Use a default date outside of the DST period to avoid problems with + // parsing the time differently depending on the today's date (which is used + // as the fall back date if none is explicitly specified). + static const wxDateTime dtDef(1, wxDateTime::Jan, 2012); + + if ( dt.ParseFormat(str, fmt, dtDef, &endParse) || + (!fmtAlt.empty() && dt.ParseFormat(str, fmtAlt, dtDef, &endParse)) ) { p += endParse - str.begin(); } @@ -320,16 +325,22 @@ wxString wxDateTime::Format(const wxString& formatp, const TimeZone& tz) const format.Replace("%X",wxLocale::GetInfo(wxLOCALE_TIME_FMT)); #endif // we have to use our own implementation if the date is out of range of - // strftime() or if we use non standard specificators + // strftime() or if we use non standard specifiers (notice that "%z" is + // special because it is de facto standard under Unix but is not supported + // under Windows) #ifdef wxHAS_STRFTIME time_t time = GetTicks(); - if ( (time != (time_t)-1) && !wxStrstr(format, wxT("%l")) ) + if ( (time != (time_t)-1) && !wxStrstr(format, wxT("%l")) +#ifdef __WINDOWS__ + && !wxStrstr(format, wxT("%z")) +#endif + ) { // use strftime() struct tm tmstruct; struct tm *tm; - if ( tz.GetOffset() == -GetTimeZone() ) + if ( tz.GetOffset() == -wxGetTimeZone() ) { // we are working with local time tm = wxLocaltime_r(&time, &tmstruct); @@ -374,12 +385,11 @@ wxString wxDateTime::Format(const wxString& formatp, const TimeZone& tz) const // used for calls to strftime() when we only deal with time struct tm tmTimeOnly; + memset(&tmTimeOnly, 0, sizeof(tmTimeOnly)); tmTimeOnly.tm_hour = tm.hour; tmTimeOnly.tm_min = tm.min; tmTimeOnly.tm_sec = tm.sec; - tmTimeOnly.tm_wday = 0; - tmTimeOnly.tm_yday = 0; - tmTimeOnly.tm_mday = 1; // any date will do + tmTimeOnly.tm_mday = 1; // any date will do, use 1976-01-01 tmTimeOnly.tm_mon = 0; tmTimeOnly.tm_year = 76; tmTimeOnly.tm_isdst = 0; // no DST, we adjust for tz ourselves @@ -399,6 +409,7 @@ wxString wxDateTime::Format(const wxString& formatp, const TimeZone& tz) const switch ( (*++p).GetValue() ) { case wxT('Y'): // year has 4 digits + case wxT('z'): // time zone as well fmt = wxT("%04d"); break; @@ -503,7 +514,7 @@ wxString wxDateTime::Format(const wxString& formatp, const TimeZone& tz) const // (indirectly) set the year correctly while ( (nLostWeekDays % 7) != 0 ) { - nLostWeekDays += year++ % 4 ? 1 : 2; + nLostWeekDays += (year++ % 4) ? 1 : 2; } // finally move the year below 2000 so that the 2-digit @@ -641,6 +652,25 @@ wxString wxDateTime::Format(const wxString& formatp, const TimeZone& tz) const res += wxString::Format(fmt, tm.year); break; + case wxT('z'): // time zone as [-+]HHMM + { + int ofs = tz.GetOffset(); + if ( ofs < 0 ) + { + res += '-'; + ofs = -ofs; + } + else + { + res += '+'; + } + + // Converts seconds to HHMM representation. + res += wxString::Format(fmt, + 100*(ofs/3600) + (ofs/60)%60); + } + break; + case wxT('Z'): // timezone name #ifdef wxHAS_STRFTIME res += CallStrftime(wxT("%Z"), &tmTimeOnly); @@ -649,9 +679,10 @@ wxString wxDateTime::Format(const wxString& formatp, const TimeZone& tz) const default: // is it the format width? - fmt.Empty(); - while ( *p == wxT('-') || *p == wxT('+') || - *p == wxT(' ') || wxIsdigit(*p) ) + for ( fmt.clear(); + *p == wxT('-') || *p == wxT('+') || + *p == wxT(' ') || wxIsdigit(*p); + ++p ) { fmt += *p; } @@ -668,7 +699,7 @@ wxString wxDateTime::Format(const wxString& formatp, const TimeZone& tz) const } // no, it wasn't the width - wxFAIL_MSG(wxT("unknown format specificator")); + wxFAIL_MSG(wxT("unknown format specifier")); // fall through and just copy it nevertheless @@ -904,6 +935,26 @@ wxDateTime::ParseRfc822Date(const wxString& date, wxString::const_iterator *end) return true; } +const char* wxDateTime::ParseRfc822Date(const char* date) +{ + wxString::const_iterator end; + wxString dateStr(date); + if ( !ParseRfc822Date(dateStr, &end) ) + return NULL; + + return date + dateStr.IterOffsetInMBStr(end); +} + +const wchar_t* wxDateTime::ParseRfc822Date(const wchar_t* date) +{ + wxString::const_iterator end; + wxString dateStr(date); + if ( !ParseRfc822Date(dateStr, &end) ) + return NULL; + + return date + (end - dateStr.begin()); +} + bool wxDateTime::ParseFormat(const wxString& date, const wxString& format, @@ -930,6 +981,8 @@ wxDateTime::ParseFormat(const wxString& date, bool hourIsIn12hFormat = false, // or in 24h one? isPM = false; // AM by default + bool haveTimeZone = false; + // and the value of the items we have (init them to get rid of warnings) wxDateTime_t msec = 0, sec = 0, @@ -940,6 +993,7 @@ wxDateTime::ParseFormat(const wxString& date, mday = 0; wxDateTime::Month mon = Inv_Month; int year = 0; + long timeZone = 0; // time zone in seconds as expected in Tm structure wxString::const_iterator input = date.begin(); const wxString::const_iterator end = date.end(); @@ -1048,11 +1102,12 @@ wxDateTime::ParseFormat(const wxString& date, { wxDateTime dt; +#if wxUSE_INTL const wxString fmtDateTime = wxLocale::GetInfo(wxLOCALE_DATE_TIME_FMT); if ( !fmtDateTime.empty() ) dt = ParseFormatAt(input, end, fmtDateTime); - +#endif // wxUSE_INTL if ( !dt.IsValid() ) { // also try the format which corresponds to ctime() @@ -1269,10 +1324,13 @@ wxDateTime::ParseFormat(const wxString& date, case wxT('x'): // locale default date representation { +#if wxUSE_INTL wxString fmtDate = wxLocale::GetInfo(wxLOCALE_SHORT_DATE_FMT), fmtDateAlt = wxLocale::GetInfo(wxLOCALE_LONG_DATE_FMT); - +#else // !wxUSE_INTL + wxString fmtDate, fmtDateAlt; +#endif // wxUSE_INTL/!wxUSE_INTL if ( fmtDate.empty() ) { if ( IsWestEuropeanCountry(GetCountry()) || @@ -1317,9 +1375,12 @@ wxDateTime::ParseFormat(const wxString& date, case wxT('X'): // locale default time representation { +#if wxUSE_INTL wxString fmtTime = wxLocale::GetInfo(wxLOCALE_TIME_FMT), fmtTimeAlt; - +#else // !wxUSE_INTL + wxString fmtTime, fmtTimeAlt; +#endif // wxUSE_INTL/!wxUSE_INTL if ( fmtTime.empty() ) { // try to parse what follows as "%H:%M:%S" and, if this @@ -1371,6 +1432,41 @@ wxDateTime::ParseFormat(const wxString& date, year = (wxDateTime_t)num; break; + case wxT('z'): + { + // check that we have something here at all + if ( input == end ) + return false; + + // and then check that it's either plus or minus sign + bool minusFound; + if ( *input == wxT('-') ) + minusFound = true; + else if ( *input == wxT('+') ) + minusFound = false; + else + return false; // no match + + // here should follow 4 digits HHMM + ++input; + unsigned long tzHourMin; + if ( !GetNumericToken(4, input, end, &tzHourMin) ) + return false; // no match + + const unsigned hours = tzHourMin / 100; + const unsigned minutes = tzHourMin % 100; + + if ( hours > 12 || minutes > 59 ) + return false; // bad format + + timeZone = 3600*hours + 60*minutes; + if ( minusFound ) + timeZone = -timeZone; + + haveTimeZone = true; + } + break; + case wxT('Z'): // timezone name // FIXME: currently we just ignore everything that looks like a // time zone here @@ -1378,7 +1474,7 @@ wxDateTime::ParseFormat(const wxString& date, break; case wxT('%'): // a percent sign - if ( *input++ != wxT('%') ) + if ( input == end || *input++ != wxT('%') ) { // no match return false; @@ -1476,6 +1572,14 @@ wxDateTime::ParseFormat(const wxString& date, Set(tm); + // If a time zone was specified and it is not the local time zone, we need + // to shift the time accordingly. + // + // Note that avoiding the call to MakeFromTimeZone is necessary to avoid + // DST problems. + if ( haveTimeZone && timeZone != -wxGetTimeZone() ) + MakeFromTimezone(timeZone); + // finally check that the week day is consistent -- if we had it if ( haveWDay && GetWeekDay() != wday ) return false; @@ -1485,15 +1589,40 @@ wxDateTime::ParseFormat(const wxString& date, return true; } +const char* +wxDateTime::ParseFormat(const char* date, + const wxString& format, + const wxDateTime& dateDef) +{ + wxString::const_iterator end; + wxString dateStr(date); + if ( !ParseFormat(dateStr, format, dateDef, &end) ) + return NULL; + + return date + dateStr.IterOffsetInMBStr(end); +} + +const wchar_t* +wxDateTime::ParseFormat(const wchar_t* date, + const wxString& format, + const wxDateTime& dateDef) +{ + wxString::const_iterator end; + wxString dateStr(date); + if ( !ParseFormat(dateStr, format, dateDef, &end) ) + return NULL; + + return date + (end - dateStr.begin()); +} + bool wxDateTime::ParseDateTime(const wxString& date, wxString::const_iterator *end) { wxCHECK_MSG( end, false, "end iterator pointer must be specified" ); - // 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(); + wxDateTime + dtDate, + dtTime; wxString::const_iterator endTime, @@ -1539,6 +1668,26 @@ wxDateTime::ParseDateTime(const wxString& date, wxString::const_iterator *end) return true; } +const char* wxDateTime::ParseDateTime(const char* date) +{ + wxString::const_iterator end; + wxString dateStr(date); + if ( !ParseDateTime(dateStr, &end) ) + return NULL; + + return date + dateStr.IterOffsetInMBStr(end); +} + +const wchar_t* wxDateTime::ParseDateTime(const wchar_t* date) +{ + wxString::const_iterator end; + wxString dateStr(date); + if ( !ParseDateTime(dateStr, &end) ) + return NULL; + + return date + (end - dateStr.begin()); +} + bool wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end) { @@ -1552,7 +1701,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end) const wxString::const_iterator pEnd = date.end(); wxString::const_iterator p = pBegin; - while ( wxIsspace(*p) ) + while ( p != pEnd && wxIsspace(*p) ) p++; // some special cases @@ -1576,12 +1725,12 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end) if ( len > lenRest ) continue; - const wxString::const_iterator pEnd = p + len; - if ( wxString(p, pEnd).CmpNoCase(dateStr) == 0 ) + const wxString::const_iterator pEndStr = p + len; + if ( wxString(p, pEndStr).CmpNoCase(dateStr) == 0 ) { // nothing can follow this, so stop here - p = pEnd; + p = pEndStr; int dayDiffFromToday = literalDates[n].dayDiffFromToday; *this = Today(); @@ -1590,7 +1739,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end) *this += wxDateSpan::Days(dayDiffFromToday); } - *end = pEnd; + *end = pEndStr; return true; } @@ -1619,9 +1768,10 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end) while ( p != pEnd ) { // skip white space and date delimiters - while ( wxStrchr(".,/-\t\r\n ", *p) ) + if ( wxStrchr(".,/-\t\r\n ", *p) ) { ++p; + continue; } // modify copy of the iterator as we're not sure if the next token is @@ -1753,7 +1903,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end) else // not a valid weekday name { // try the ordinals - static const char *ordinals[] = + static const char *const ordinals[] = { wxTRANSLATE("first"), wxTRANSLATE("second"), @@ -1895,6 +2045,26 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end) return true; } +const char* wxDateTime::ParseDate(const char* date) +{ + wxString::const_iterator end; + wxString dateStr(date); + if ( !ParseDate(dateStr, &end) ) + return NULL; + + return date + dateStr.IterOffsetInMBStr(end); +} + +const wchar_t* wxDateTime::ParseDate(const wchar_t* date) +{ + wxString::const_iterator end; + wxString dateStr(date); + if ( !ParseDate(dateStr, &end) ) + return NULL; + + return date + (end - dateStr.begin()); +} + bool wxDateTime::ParseTime(const wxString& time, wxString::const_iterator *end) { @@ -1915,14 +2085,13 @@ wxDateTime::ParseTime(const wxString& time, wxString::const_iterator *end) for ( size_t n = 0; n < WXSIZEOF(stdTimes); n++ ) { const wxString timeString = wxGetTranslation(stdTimes[n].name); - const wxString::const_iterator p = time.begin() + timeString.length(); - if ( timeString.CmpNoCase(wxString(time.begin(), p)) == 0 ) + if ( timeString.CmpNoCase(wxString(time, timeString.length())) == 0 ) { // casts required by DigitalMars Set(stdTimes[n].hour, wxDateTime_t(0), wxDateTime_t(0)); if ( end ) - *end = p; + *end = time.begin() + timeString.length(); return true; } @@ -1930,12 +2099,12 @@ wxDateTime::ParseTime(const wxString& time, wxString::const_iterator *end) // try all time formats we may think about in the order from longest to // shortest - static const char *timeFormats[] = + static const char *const timeFormats[] = { "%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 + "%H:%M", // and a possibly 24 hour version without seconds "%X", // possibly something from above or maybe something // completely different -- try it last @@ -1951,6 +2120,26 @@ wxDateTime::ParseTime(const wxString& time, wxString::const_iterator *end) return false; } +const char* wxDateTime::ParseTime(const char* date) +{ + wxString::const_iterator end; + wxString dateStr(date); + if ( !ParseTime(dateStr, &end) ) + return NULL; + + return date + dateStr.IterOffsetInMBStr(end); +} + +const wchar_t* wxDateTime::ParseTime(const wchar_t* date) +{ + wxString::const_iterator end; + wxString dateStr(date); + if ( !ParseTime(dateStr, &end) ) + return NULL; + + return date + (end - dateStr.begin()); +} + // ---------------------------------------------------------------------------- // Workdays and holidays support // ----------------------------------------------------------------------------