]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/datetimefmt.cpp
made definition of wxUSE_LOG_DEBUG dependent on wxDEBUG_LEVEL and added wxUSE_LOG_TRA...
[wxWidgets.git] / src / common / datetimefmt.cpp
index dae6e0f1a8d9e290195407457e969ec79639cdc2..3ecb11b15ec9ed97eb6cff03838b6219c3cac8d1 100644 (file)
 // implementation of wxDateTime
 // ============================================================================
 
+// ----------------------------------------------------------------------------
+// helpers shared between datetime.cpp and datetimefmt.cpp
+// ----------------------------------------------------------------------------
+
+extern void InitTm(struct tm& tm);
+
+extern int GetTimeZone();
+
+extern wxString CallStrftime(const wxString& format, const tm* tm);
+
 // ----------------------------------------------------------------------------
 // constants (see also datetime.cpp)
 // ----------------------------------------------------------------------------
@@ -79,8 +89,40 @@ static const int MIN_PER_HOUR = 60;
 // parsing helpers
 // ----------------------------------------------------------------------------
 
-// see datetime.cpp:
-wxDateTime::wxDateTime_t GetNumOfDaysInMonth(int year, wxDateTime::Month month);
+#ifdef HAVE_STRPTIME
+
+#if wxUSE_UNIX && !defined(HAVE_STRPTIME_DECL)
+    // configure detected that we had strptime() but not its declaration,
+    // provide it ourselves
+    extern "C" char *strptime(const char *, const char *, struct tm *);
+#endif
+
+// Unicode-friendly strptime() wrapper
+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_WCHAR
+    wxCharBuffer inputMB(wxConvertWX2MB(input));
+#else // ASCII
+    const char * const inputMB = input;
+#endif // Unicode/Ascii
+
+    const char *result = strptime(inputMB, fmt, tm);
+    if ( !result )
+        return NULL;
+
+#if wxUSE_UNICODE_WCHAR
+    // FIXME: this is wrong in presence of surrogates &c
+    return input + (result - inputMB.data());
+#else // ASCII
+    return result;
+#endif // Unicode/Ascii
+}
+
+#endif // HAVE_STRPTIME
 
 // return the month if the string is a month name or Inv_Month otherwise
 static wxDateTime::Month GetMonthFromName(const wxString& name, int flags)
@@ -142,13 +184,6 @@ static wxDateTime::WeekDay GetWeekDayFromName(const wxString& name, int flags)
     return wd;
 }
 
-/* static */
-struct tm *wxDateTime::GetTmNow(struct tm *tmstruct)
-{
-    time_t t = GetTimeNow();
-    return wxLocaltime_r(&t, tmstruct);
-}
-
 // scans all digits (but no more than len) and returns the resulting number
 static bool GetNumericToken(size_t len,
                             const wxStringCharType*& p,
@@ -1154,30 +1189,62 @@ wxDateTime::ParseFormat(const wxString& date,
 
                     const wxString inc(input);
 
-                    // 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) )
+                    // NOTE: %c is locale-dependent; try strptime
+#ifdef HAVE_STRPTIME
+                    struct tm tm;
+
+                    // try using strptime() -- it may fail even if the input is
+                    // correct but the date is out of range, so we will fall back
+                    // to our generic code anyhow
+                    const wxStringCharType *
+                        result = CallStrptime(input, "%c", &tm);
+                    if ( result )
                     {
-                        // we've tried everything and still no match
-                        return NULL;
-                    }
+                        haveDay = haveMon = haveYear =
+                        haveHour = haveMin = haveSec = true;
 
-                    Tm tm = dt.GetTm();
+                        hour = tm.tm_hour;
+                        min = tm.tm_min;
+                        sec = tm.tm_sec;
 
-                    haveDay = haveMon = haveYear =
-                    haveHour = haveMin = haveSec = true;
+                        year = 1900 + tm.tm_year;
+                        mon = (Month)tm.tm_mon;
+                        mday = tm.tm_mday;
+                        
+                        input = result;     // proceed where strptime() ended
+                    }
+                    else
+                    {
+                        // strptime() failed; try generic heuristic code
+#endif // HAVE_STRPTIME
 
-                    hour = tm.hour;
-                    min = tm.min;
-                    sec = tm.sec;
+                        // 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 NULL;
+                        }
 
-                    year = tm.year;
-                    mon = tm.mon;
-                    mday = tm.mday;
+                        Tm tm = dt.GetTm();
+                        
+                        haveDay = haveMon = haveYear =
+                        haveHour = haveMin = haveSec = true;
+
+                        hour = tm.hour;
+                        min = tm.min;
+                        sec = tm.sec;
 
-                    input += endc - inc.begin();
+                        year = tm.year;
+                        mon = tm.mon;
+                        mday = tm.mday;
+                        
+                        input += endc - inc.begin();
+#ifdef HAVE_STRPTIME
+                    }
+#endif // HAVE_STRPTIME
                 }
                 break;
 
@@ -1262,6 +1329,13 @@ wxDateTime::ParseFormat(const wxString& date,
             case _T('p'):       // AM or PM string
                 {
                     wxString am, pm, token = GetAlphaToken(input);
+                    
+                    // some locales have empty AM/PM tokens and thus when formatting
+                    // dates with the %p specifier nothing is generated; when trying to
+                    // parse them back, we get an empty token here... but that's not
+                    // an error.
+                    if (token.empty())
+                        break;
 
                     GetAmPmStrings(&am, &pm);
                     if (am.empty() && pm.empty())
@@ -1570,7 +1644,7 @@ wxDateTime::ParseFormat(const wxString& date,
     //      also always ignore the week day
     if ( haveDay )
     {
-        if ( mday > GetNumOfDaysInMonth(tm.year, tm.mon) )
+        if ( mday > GetNumberOfDays(tm.mon, tm.year) )
         {
             wxLogDebug(_T("bad month day in wxDateTime::ParseFormat"));
 
@@ -1798,7 +1872,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
                     // dates like 2/29/1976 which would be rejected otherwise
                     wxDateTime_t max_days = (wxDateTime_t)(
                         haveMon
-                        ? GetNumOfDaysInMonth(haveYear ? year : 1976, mon)
+                        ? GetNumberOfDays(mon, haveYear ? year : 1976)
                         : 31
                     );
 
@@ -1976,7 +2050,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
                 mon = (wxDateTime::Month)(day - 1);
 
                 // we're in the current year then
-                if ( (year > 0) && (year <= (int)GetNumOfDaysInMonth(Inv_Year, mon)) )
+                if ( (year > 0) && (year <= (int)GetNumberOfDays(mon, Inv_Year)) )
                 {
                     day = (wxDateTime_t)year;
 
@@ -2010,7 +2084,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
     {
         // 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) )
+        if ( day > GetNumberOfDays(mon, year) )
             return NULL;
 
         Set(day, mon, year);