X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6a27c749b302e17446080bb232ef8010b60f3d00..e443232d2e06140e64a3d888d9542d9d6ef2c20c:/src/common/datetime.cpp diff --git a/src/common/datetime.cpp b/src/common/datetime.cpp index 17410c7443..7f1f7924a0 100644 --- a/src/common/datetime.cpp +++ b/src/common/datetime.cpp @@ -16,6 +16,10 @@ // 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: * @@ -77,6 +81,14 @@ #include +#ifdef __WINDOWS__ + #include "wx/msw/wrapwin.h" + #include + #ifndef __WXWINCE__ + #include + #endif +#endif + #include "wx/datetime.h" #include "wx/stopwatch.h" // for wxGetLocalTimeMillis() @@ -347,11 +359,12 @@ static long GetTruncatedJDN(wxDateTime::wxDateTime_t day, - JDN_OFFSET; } +#ifndef __WXWINCE__ // this function is a wrapper around strftime(3) adding error checking static wxString CallStrftime(const wxChar *format, const tm* tm) { wxChar buf[4096]; - if ( !wxStrftime(buf, WXSIZEOF(buf), format, tm) ) + if ( !wxStrftime(buf, WXSIZEOF(buf), format, tm) ) { // buffer is too small? wxFAIL_MSG(_T("strftime() failed")); @@ -359,6 +372,7 @@ static wxString CallStrftime(const wxChar *format, const tm* tm) return wxString(buf); } +#endif #ifdef HAVE_STRPTIME @@ -815,47 +829,47 @@ wxString wxDateTime::GetMonthName(wxDateTime::Month month, return CallStrftime(flags == Name_Abbr ? _T("%b") : _T("%B"), &tm); #else - wxString ret; - switch(month) - { - case Jan: - ret = (flags == Name_Abbr ? wxT("Jan"): wxT("January")); - break; - case Feb: - ret = (flags == Name_Abbr ? wxT("Feb"): wxT("Febuary")); - break; - case Mar: - ret = (flags == Name_Abbr ? wxT("Mar"): wxT("March")); - break; - case Apr: - ret = (flags == Name_Abbr ? wxT("Apr"): wxT("April")); - break; - case May: - ret = (flags == Name_Abbr ? wxT("May"): wxT("May")); - break; - case Jun: - ret = (flags == Name_Abbr ? wxT("Jun"): wxT("June")); - break; - case Jul: - ret = (flags == Name_Abbr ? wxT("Jul"): wxT("July")); - break; - case Aug: - ret = (flags == Name_Abbr ? wxT("Aug"): wxT("August")); - break; - case Sep: - ret = (flags == Name_Abbr ? wxT("Sep"): wxT("September")); - break; - case Oct: - ret = (flags == Name_Abbr ? wxT("Oct"): wxT("October")); - break; - case Nov: - ret = (flags == Name_Abbr ? wxT("Nov"): wxT("November")); - break; - case Dec: - ret = (flags == Name_Abbr ? wxT("Dec"): wxT("December")); - break; - } - return ret; + wxString ret; + switch(month) + { + case Jan: + ret = (flags == Name_Abbr ? wxT("Jan"): wxT("January")); + break; + case Feb: + ret = (flags == Name_Abbr ? wxT("Feb"): wxT("Febuary")); + break; + case Mar: + ret = (flags == Name_Abbr ? wxT("Mar"): wxT("March")); + break; + case Apr: + ret = (flags == Name_Abbr ? wxT("Apr"): wxT("April")); + break; + case May: + ret = (flags == Name_Abbr ? wxT("May"): wxT("May")); + break; + case Jun: + ret = (flags == Name_Abbr ? wxT("Jun"): wxT("June")); + break; + case Jul: + ret = (flags == Name_Abbr ? wxT("Jul"): wxT("July")); + break; + case Aug: + ret = (flags == Name_Abbr ? wxT("Aug"): wxT("August")); + break; + case Sep: + ret = (flags == Name_Abbr ? wxT("Sep"): wxT("September")); + break; + case Oct: + ret = (flags == Name_Abbr ? wxT("Oct"): wxT("October")); + break; + case Nov: + ret = (flags == Name_Abbr ? wxT("Nov"): wxT("November")); + break; + case Dec: + ret = (flags == Name_Abbr ? wxT("Dec"): wxT("December")); + break; + } + return ret; #endif } @@ -883,32 +897,32 @@ wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday, // ... and call strftime() return CallStrftime(flags == Name_Abbr ? _T("%a") : _T("%A"), &tm); #else - wxString ret; - switch(wday) - { - case Sun: - ret = (flags == Name_Abbr ? wxT("Sun") : wxT("Sunday")); - break; - case Mon: - ret = (flags == Name_Abbr ? wxT("Mon") : wxT("Monday")); - break; - case Tue: - ret = (flags == Name_Abbr ? wxT("Tue") : wxT("Tuesday")); - break; - case Wed: - ret = (flags == Name_Abbr ? wxT("Wed") : wxT("Wednesday")); - break; - case Thu: - ret = (flags == Name_Abbr ? wxT("Thu") : wxT("Thursday")); - break; - case Fri: - ret = (flags == Name_Abbr ? wxT("Fri") : wxT("Friday")); - break; - case Sat: - ret = (flags == Name_Abbr ? wxT("Sat") : wxT("Saturday")); - break; - } - return ret; + wxString ret; + switch(wday) + { + case Sun: + ret = (flags == Name_Abbr ? wxT("Sun") : wxT("Sunday")); + break; + case Mon: + ret = (flags == Name_Abbr ? wxT("Mon") : wxT("Monday")); + break; + case Tue: + ret = (flags == Name_Abbr ? wxT("Tue") : wxT("Tuesday")); + break; + case Wed: + ret = (flags == Name_Abbr ? wxT("Wed") : wxT("Wednesday")); + break; + case Thu: + ret = (flags == Name_Abbr ? wxT("Thu") : wxT("Thursday")); + break; + case Fri: + ret = (flags == Name_Abbr ? wxT("Fri") : wxT("Friday")); + break; + case Sat: + ret = (flags == Name_Abbr ? wxT("Sat") : wxT("Saturday")); + break; + } + return ret; #endif } @@ -929,7 +943,7 @@ void wxDateTime::GetAmPmStrings(wxString *am, wxString *pm) // assert, even though it is a perfectly legal use. if ( am ) { - if (wxStrftime(buffer, sizeof buffer, _T("%p"), &tm) > 0) + if (wxStrftime(buffer, sizeof(buffer)/sizeof(wxChar), _T("%p"), &tm) > 0) *am = wxString(buffer); else *am = wxString(); @@ -937,7 +951,7 @@ void wxDateTime::GetAmPmStrings(wxString *am, wxString *pm) if ( pm ) { tm.tm_hour = 13; - if (wxStrftime(buffer, sizeof buffer, _T("%p"), &tm) > 0) + if (wxStrftime(buffer, sizeof(buffer)/sizeof(wxChar), _T("%p"), &tm) > 0) *pm = wxString(buffer); else *pm = wxString(); @@ -1285,18 +1299,21 @@ wxDateTime& wxDateTime::Set(wxDateTime_t hour, wxDATETIME_CHECK( tm, _T("localtime() failed") ); + // make a copy so it isn't clobbered by the call to mktime() below + struct tm tm1(*tm); + // adjust the time - tm->tm_hour = hour; - tm->tm_min = minute; - tm->tm_sec = second; + tm1.tm_hour = hour; + tm1.tm_min = minute; + tm1.tm_sec = second; // and the DST in case it changes on this date - struct tm tm2(*tm); + struct tm tm2(tm1); mktime(&tm2); - if ( tm2.tm_isdst != tm->tm_isdst ) - tm->tm_isdst = tm2.tm_isdst; + if ( tm2.tm_isdst != tm1.tm_isdst ) + tm1.tm_isdst = tm2.tm_isdst; - (void)Set(*tm); + (void)Set(tm1); // and finally adjust milliseconds return SetMillisecond(millisec); @@ -1373,6 +1390,8 @@ wxDateTime& wxDateTime::Set(double jdn) jdn *= MILLISECONDS_PER_DAY; + m_time.Assign(jdn); + // JDNs always suppose an UTC date, so bring it back to local time zone // (also see GetJulianDayNumber() implementation) long tzDiff = GetTimeZone(); @@ -1382,9 +1401,7 @@ wxDateTime& wxDateTime::Set(double jdn) tzDiff -= 3600; } - jdn += tzDiff*1000; // tzDiff is in seconds - - m_time.Assign(jdn); + m_time += tzDiff*1000; // tzDiff is in seconds return *this; } @@ -1805,8 +1822,9 @@ wxDateTime& wxDateTime::SetToWeekDayInSameWeek(WeekDay weekday, WeekFlags flags) { wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") ); - int wdayThis = GetWeekDay(); - if ( weekday == wdayThis ) + int wdayDst = weekday, + wdayThis = GetWeekDay(); + if ( wdayDst == wdayThis ) { // nothing to do return *this; @@ -1820,21 +1838,23 @@ wxDateTime& wxDateTime::SetToWeekDayInSameWeek(WeekDay weekday, WeekFlags flags) // the logic below based on comparing weekday and wdayThis works if Sun (0) // is the first day in the week, but breaks down for Monday_First case so // we adjust the week days in this case - if( flags == Monday_First ) + if ( flags == Monday_First ) { if ( wdayThis == Sun ) wdayThis += 7; + if ( wdayDst == Sun ) + wdayDst += 7; } //else: Sunday_First, nothing to do // go forward or back in time to the day we want - if ( weekday < wdayThis ) + if ( wdayDst < wdayThis ) { - return Subtract(wxDateSpan::Days(wdayThis - weekday)); + return Subtract(wxDateSpan::Days(wdayThis - wdayDst)); } else // weekday > wdayThis { - return Add(wxDateSpan::Days(weekday - wdayThis)); + return Add(wxDateSpan::Days(wdayDst - wdayThis)); } } @@ -2184,7 +2204,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const } } #ifndef __WXWINCE__ - //Windows CE doesn't support strftime or wcsftime, so we use the generic implementation + //Windows CE doesn't support strftime or wcsftime, so we use the generic implementation if ( tm ) { return CallStrftime(format, tm); @@ -2399,9 +2419,9 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const res += str; } #else - //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); + //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 break; @@ -2442,7 +2462,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const #ifndef __WXWINCE__ res += CallStrftime(_T("%p"), &tmTimeOnly); #else - res += (tmTimeOnly.tm_hour > 12) ? wxT("pm") : wxT("am"); + res += (tmTimeOnly.tm_hour > 12) ? wxT("pm") : wxT("am"); #endif break; @@ -2469,7 +2489,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const #ifndef __WXWINCE__ res += CallStrftime(_T("%X"), &tmTimeOnly); #else - res += wxString::Format(wxT("%02d:%02d:%02d"),tm.hour, tm.min, tm.sec); + res += wxString::Format(wxT("%02d:%02d:%02d"),tm.hour, tm.min, tm.sec); #endif break; @@ -2722,7 +2742,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) } // and now the interesting part: the timezone - int offset; + int offset wxDUMMY_INITIALIZE(0); if ( *p == _T('-') || *p == _T('+') ) { // the explicit offset given: it has the form of hhmm @@ -2824,6 +2844,70 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) return p; } +#ifdef __WINDOWS__ + +// Get's current locale's date formatting string and stores it in fmt if +// the locale is set; otherwise or in case of failure, leaves fmt unchanged +static void GetLocaleDateFormat(wxString *fmt) +{ + // there is no setlocale() under Windows CE, so just always query the + // system there +#ifndef __WXWINCE__ + if ( strcmp(setlocale(LC_ALL, NULL), "C") != 0 ) +#endif + { + // The locale was programatically set to non-C. We assume that this was + // done using wxLocale, in which case thread's current locale is also + // set to correct LCID value and we can use GetLocaleInfo to determine + // the correct formatting string: +#ifdef __WXWINCE__ + LCID lcid = LOCALE_USER_DEFAULT; +#else + LCID lcid = GetThreadLocale(); +#endif + wxChar delim[5]; // fields deliminer, 4 chars max + if ( GetLocaleInfo(lcid, LOCALE_SDATE, delim, 5) ) + { + wxChar centurybuf[2]; // use %y or %Y, 1 char max + wxChar century = 'y'; + if ( GetLocaleInfo(lcid, LOCALE_ICENTURY, centurybuf, 2) ) + { + if ( centurybuf[0] == _T('1') ) + century = 'Y'; + // else 'y' as above + } + + wxChar order[2]; // order code, 1 char max + if ( GetLocaleInfo(lcid, LOCALE_IDATE, order, 2) ) + { + if ( order[0] == _T('0') ) // M-D-Y + { + *fmt = wxString::Format(_T("%%m%s%%d%s%%%c"), + delim, delim, century); + } + else if ( order[0] == _T('1') ) // D-M-Y + { + *fmt = wxString::Format(_T("%%d%s%%m%s%%%c"), + delim, delim, century); + } + else if ( order[0] == _T('2') ) // Y-M-D + { + *fmt = wxString::Format(_T("%%%c%s%%m%s%%d"), + century, delim, delim); + } + else + { + wxFAIL_MSG(_T("unexpected GetLocaleInfo return value")); + } + } + } + // if we failed, leave fmtDate value unchanged and + // try our luck with the default set above + } +} + +#endif // __WINDOWS__ + const wxChar *wxDateTime::ParseFormat(const wxChar *date, const wxChar *format, const wxDateTime& dateDef) @@ -3117,6 +3201,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, hour = tm.hour; min = tm.min; } + break; case _T('S'): // second as a decimal number (00-61) if ( !GetNumericToken(width, input, &num) || (num > 61) ) @@ -3183,11 +3268,11 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, } #endif // HAVE_STRPTIME - // TODO query the LOCALE_IDATE setting under Win32 { wxDateTime dt; wxString fmtDate, fmtDateAlt; + if ( IsWestEuropeanCountry(GetCountry()) || GetCountry() == Russia ) { @@ -3200,6 +3285,12 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date, fmtDateAlt = _T("%d/%m/%y"); } +#ifdef __WINDOWS__ + // The above doesn't work for all locales, try to query + // Windows for the right way of formatting the date: + GetLocaleDateFormat(&fmtDate); +#endif + const wxChar *result = dt.ParseFormat(input, fmtDate); if ( !result )