]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/datetime.cpp
implementation of the range insert for wxStringArray (patch 975003)
[wxWidgets.git] / src / common / datetime.cpp
index 56324c0d3da9fe60952fd8d5cd3dbbe43e0a6f5f..2b208928df69644e5bb338f75205c87088e60514 100644 (file)
 #include <ctype.h>
 
 #include "wx/datetime.h"
-#include "wx/timer.h"           // for wxGetLocalTimeMillis()
+#include "wx/stopwatch.h"           // for wxGetLocalTimeMillis()
 
 const long wxDateTime::TIME_T_FACTOR = 1000l;
 
+#if wxUSE_EXTENDED_RTTI
+
+template<> void wxStringReadValue(const wxString &s , wxDateTime &data )
+{
+    data.ParseFormat(s,wxT("%Y-%m-%d %H:%M:%S")) ;
+}
+
+template<> void wxStringWriteValue(wxString &s , const wxDateTime &data )
+{
+    s = data.Format(wxT("%Y-%m-%d %H:%M:%S")) ;
+}
+
+wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter<wxDateTime> , wxFromStringConverter<wxDateTime>)
+
+#endif
+
+//
 // ----------------------------------------------------------------------------
 // conditional compilation
 // ----------------------------------------------------------------------------
@@ -822,14 +839,29 @@ void wxDateTime::GetAmPmStrings(wxString *am, wxString *pm)
 {
     tm tm;
     InitTm(tm);
+    wxChar buffer[64];
+    // @Note: Do not call 'CallStrftime' here! CallStrftime checks the return code
+    // and causes an assertion failed if the buffer is to small (which is good) - OR -
+    // if strftime does not return anything because the format string is invalid - OR -
+    // if there are no 'am' / 'pm' tokens defined for the current locale (which is not good).
+    // wxDateTime::ParseTime will try several different formats to parse the time.
+    // As a result, GetAmPmStrings might get called, even if the current locale
+    // does not define any 'am' / 'pm' tokens. In this case, wxStrftime would
+    // assert, even though it is a perfectly legal use.
     if ( am )
     {
-        *am = CallStrftime(_T("%p"), &tm);
+        if (wxStrftime(buffer, sizeof buffer, _T("%p"), &tm) > 0)
+            *am = wxString(buffer);
+        else
+            *am = wxString();
     }
     if ( pm )
     {
         tm.tm_hour = 13;
-        *pm = CallStrftime(_T("%p"), &tm);
+        if (wxStrftime(buffer, sizeof buffer, _T("%p"), &tm) > 0)
+            *pm = wxString(buffer);
+        else
+            *pm = wxString();
     }
 }
 
@@ -1255,6 +1287,17 @@ wxDateTime& wxDateTime::Set(double jdn)
 
     jdn *= MILLISECONDS_PER_DAY;
 
+    // JDNs always suppose an UTC date, so bring it back to local time zone
+    // (also see GetJulianDayNumber() implementation)
+    long tzDiff = GetTimeZone();
+    if ( IsDST() == 1 )
+    {
+        // FIXME: again, we suppose that DST is always one hour
+        tzDiff -= 3600;
+    }
+
+    jdn += tzDiff*1000; // tzDiff is in seconds
+
     m_time.Assign(jdn);
 
     return *this;
@@ -1294,6 +1337,7 @@ wxDateTime& wxDateTime::ResetTime()
 wxDateTime& wxDateTime::SetFromDOS(unsigned long ddt)
 {
     struct tm tm;
+    InitTm(tm);
 
     long year = ddt & 0xFE000000;
     year >>= 25;
@@ -1854,7 +1898,7 @@ wxDateTime& wxDateTime::SetToYearDay(wxDateTime::wxDateTime_t yday)
         // for Dec, we can't compare with gs_cumulatedDays[mon + 1], but we
         // don't need it neither - because of the CHECK above we know that
         // yday lies in December then
-        if ( (mon == Dec) || (yday < gs_cumulatedDays[isLeap][mon + 1]) )
+        if ( (mon == Dec) || (yday <= gs_cumulatedDays[isLeap][mon + 1]) )
         {
             Set(yday - gs_cumulatedDays[isLeap][mon], mon, year);
 
@@ -1871,8 +1915,8 @@ wxDateTime& wxDateTime::SetToYearDay(wxDateTime::wxDateTime_t yday)
 
 double wxDateTime::GetJulianDayNumber() const
 {
-    // JDN are always expressed for the GMT dates
-    Tm tm(ToTimezone(GMT0).GetTm(GMT0));
+    // JDN are always expressed for the UTC dates
+    Tm tm(ToTimezone(UTC).GetTm(UTC));
 
     double result = GetTruncatedJDN(tm.mday, tm.mon, tm.year);
 
@@ -2848,6 +2892,8 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     wxString am, pm, token = GetAlphaToken(input);
 
                     GetAmPmStrings(&am, &pm);
+                    if (am.IsEmpty() && pm.IsEmpty())
+                        return (wxChar *)NULL;  // no am/pm strings defined
                     if ( token.CmpNoCase(pm) == 0 )
                     {
                         isPM = TRUE;
@@ -3185,6 +3231,14 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
 
     Set(tm);
 
+    // finally check that the week day is consistent -- if we had it
+    if ( haveWDay && GetWeekDay() != wday )
+    {
+        wxLogDebug(_T("inconsistsnet week day in wxDateTime::ParseFormat()"));
+
+        return NULL;
+    }
+
     return input;
 }
 
@@ -3192,11 +3246,48 @@ const wxChar *wxDateTime::ParseDateTime(const wxChar *date)
 {
     wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") );
 
-    // there is a public domain version of getdate.y, but it only works for
-    // English...
-    wxFAIL_MSG(_T("TODO"));
+    // 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);
+
+    // We got a date in the beginning, see if there is a time specified after the date
+    if ( pchDate )
+    {
+        // Skip spaces, as the ParseTime() function fails on spaces
+        while ( wxIsspace(*pchDate) )
+            pchDate++;
+
+        pchTime = dtTime.ParseTime(pchDate);
+    }
+    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++;
+
+            pchDate = dtDate.ParseDate(pchTime);
+        }
+    }
+
+    // If we have a date specified, set our own data to the same date
+    if ( !pchDate || !pchTime )
+        return NULL;
+
+    Set(dtDate.GetDay(), dtDate.GetMonth(), dtDate.GetYear(),
+        dtTime.GetHour(), dtTime.GetMinute(), dtTime.GetSecond(),
+        dtTime.GetMillisecond());
 
-    return (wxChar *)NULL;
+    // Return endpoint of scan
+    return pchDate > pchTime ? pchDate : pchTime;
 }
 
 const wxChar *wxDateTime::ParseDate(const wxChar *date)
@@ -3287,18 +3378,27 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
             }
             else // not the month
             {
-                wxDateTime_t maxDays = haveMon
-                    ? GetNumOfDaysInMonth(haveYear ? year : Inv_Year, mon)
-                    : 31;
-
-                // can it be day?
-                if ( (val == 0) || (val > (unsigned long)maxDays) )  // cast to shut up compiler warning in BCC
+                if ( haveDay )
                 {
+                    // this can only be the year
                     isYear = TRUE;
                 }
-                else
+                else // may be either day or year
                 {
-                    isDay = TRUE;
+                    wxDateTime_t maxDays = haveMon
+                        ? GetNumOfDaysInMonth(haveYear ? year : Inv_Year, mon)
+                        : 31;
+
+                    // can it be day?
+                    if ( (val == 0) || (val > (unsigned long)maxDays) )
+                    {
+                        // no
+                        isYear = TRUE;
+                    }
+                    else // yes, suppose it's the day
+                    {
+                        isDay = TRUE;
+                    }
                 }
             }
 
@@ -3461,8 +3561,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
                 mon = (wxDateTime::Month)(day - 1);
 
                 // we're in the current year then
-                if ( (year > 0) &&
-                        (unsigned)year <= GetNumOfDaysInMonth(Inv_Year, mon) )
+                if ( (year > 0) && (year <= (int)GetNumOfDaysInMonth(Inv_Year, mon)) )
                 {
                     day = year;