]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/datetime.cpp
add more virtual border drawing functions used by frame decorations code
[wxWidgets.git] / src / common / datetime.cpp
index 12732e144b010de690fd276371e9cb5917e2c8c9..4e68a76cd23edd1388e046523804da8c2893fba3 100644 (file)
 #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"
 #endif // WX_PRECOMP
 
-#include "wx/intl.h"
 #include "wx/thread.h"
 #include "wx/tokenzr.h"
-#include "wx/module.h"
 
 #include <ctype.h>
 
 #ifdef __WINDOWS__
-    #include "wx/msw/wrapwin.h"
     #include <winnls.h>
     #ifndef __WXWINCE__
         #include <locale.h>
@@ -86,7 +89,6 @@
 #endif
 
 #include "wx/datetime.h"
-#include "wx/stopwatch.h"           // for wxGetLocalTimeMillis()
 
 const long wxDateTime::TIME_T_FACTOR = 1000l;
 
@@ -169,7 +171,7 @@ wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter<wxDateTime> , wxFromStringCon
     #endif
 #endif // !WX_TIMEZONE && !WX_GMTOFF_IN_TM
 
-#if wxUSE_THREADS
+#if (!defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)) && wxUSE_THREADS && !defined(__WINDOWS__)
 static wxMutex timeLock;
 #endif
 
@@ -179,7 +181,7 @@ 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
   memcpy(temp, localtime(ticks), sizeof(struct tm));
   return temp;
@@ -192,7 +194,7 @@ 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
   memcpy(temp, gmtime(ticks), sizeof(struct tm));
   return temp;
@@ -204,13 +206,8 @@ struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp)
 // ----------------------------------------------------------------------------
 
 // 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
@@ -332,7 +329,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 +339,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
@@ -1816,6 +1812,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 +1850,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)
@@ -2408,6 +2406,9 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
                             nLostWeekDays += year++ % 4 ? 1 : 2;
                         }
 
+                        // Keep year below 2000 so the 2digit year number
+                        // can never match the month or day of the month
+                        if (year>=2000) year-=28;
                         // at any rate, we couldn't go further than 1988 + 9 + 28!
                         wxASSERT_MSG( year < 2030,
                                       _T("logic error in wxDateTime::Format") );
@@ -2416,25 +2417,30 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
                         strYear.Printf(_T("%d"), year);
                         strYear2.Printf(_T("%d"), year % 100);
 
-                        // find two strings not occurring in format (this is surely
+                        // find four 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 )
+                        wxString replacement,replacement2,replacement3,replacement4;
+                        for (int rnr=1; rnr<5 ; rnr++)
                         {
-                            replacement << (wxChar)-1;
-                        }
+                            wxString r = (wxChar)-rnr;
+                            while ( fmt2.Find(r) != wxNOT_FOUND )
+                            {
+                                r << (wxChar)-rnr;
+                            }
 
-                        wxString replacement2 = (wxChar)-2;
-                        while ( fmt2.Find(replacement) != wxNOT_FOUND )
-                        {
-                            replacement << (wxChar)-2;
+                            switch (rnr)
+                            {
+                                case 1: replacement=r; break;
+                                case 2: replacement2=r; break;
+                                case 3: replacement3=r; break;
+                                case 4: replacement4=r; break;
+                            }
                         }
-
                         // replace all occurrences of year with it
                         bool wasReplaced = fmt2.Replace(strYear, replacement) > 0;
-                        if ( !wasReplaced )
-                            wasReplaced = fmt2.Replace(strYear2, replacement2) > 0;
+                        // evaluation order ensures we always attempt the replacement.
+                        wasReplaced = (fmt2.Replace(strYear2, replacement2) > 0) | wasReplaced ;
 
                         // use strftime() to format the same date but in supported
                         // year
@@ -2459,11 +2465,17 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
                                                     &tmAdjusted);
 
                         // now replace the occurrence of 1999 with the real year
+                        // we do this in two stages to stop the 2 digit year
+                        // matching any substring of the 4 digit year.
+                        // Any day,month hours and minutes components should be safe due
+                        // to ensuring the range of the years.
                         wxString strYearReal, strYearReal2;
                         strYearReal.Printf(_T("%04d"), yearReal);
                         strYearReal2.Printf(_T("%02d"), yearReal % 100);
-                        str.Replace(strYear, strYearReal);
-                        str.Replace(strYear2, strYearReal2);
+                        str.Replace(strYear, replacement3);
+                        str.Replace(strYear2,replacement4);
+                        str.Replace(replacement3, strYearReal);
+                        str.Replace(replacement4, strYearReal2);
 
                         // and replace back all occurrences of replacement string
                         if ( wasReplaced )
@@ -3810,9 +3822,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
                     );
 
@@ -3965,7 +3979,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 +3988,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 +4018,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 +4034,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 )
@@ -4217,11 +4236,14 @@ wxString wxTimeSpan::Format(const wxChar *format) const
         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 )
             {
@@ -4256,6 +4278,13 @@ wxString wxTimeSpan::Format(const wxChar *format) const
                     n = GetHours();
                     if ( partBiggest < Part_Hour )
                     {
+                        if ( n < 0 )
+                        {
+                            // the sign has already been taken into account
+                            // when outputting the biggest part
+                            n = -n;
+                        }
+
                         n %= HOURS_PER_DAY;
                     }
                     else
@@ -4263,25 +4292,31 @@ wxString wxTimeSpan::Format(const wxChar *format) const
                         partBiggest = Part_Hour;
                     }
 
-                    fmtPrefix += _T("02");
+                    digits = 2;
                     break;
 
                 case _T('l'):
                     n = GetMilliseconds().ToLong();
                     if ( partBiggest < Part_MSec )
                     {
+                        if ( n < 0 )
+                            n = -n;
+
                         n %= 1000;
                     }
                     //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'):
                     n = GetMinutes();
                     if ( partBiggest < Part_Min )
                     {
+                        if ( n < 0 )
+                            n = -n;
+
                         n %= MIN_PER_HOUR;
                     }
                     else
@@ -4289,13 +4324,16 @@ wxString wxTimeSpan::Format(const wxChar *format) const
                         partBiggest = Part_Min;
                     }
 
-                    fmtPrefix += _T("02");
+                    digits = 2;
                     break;
 
                 case _T('S'):
                     n = GetSeconds().ToLong();
                     if ( partBiggest < Part_Sec )
                     {
+                        if ( n < 0 )
+                            n = -n;
+
                         n %= SEC_PER_MIN;
                     }
                     else
@@ -4303,10 +4341,19 @@ wxString wxTimeSpan::Format(const wxChar *format) const
                         partBiggest = Part_Sec;
                     }
 
-                    fmtPrefix += _T("02");
+                    digits = 2;
                     break;
             }
 
+            if ( digits )
+            {
+                // negative numbers need one extra position for '-' display
+                if ( n < 0 )
+                    digits++;
+
+                fmtPrefix << _T("0") << digits;
+            }
+
             str += wxString::Format(fmtPrefix + _T("ld"), n);
         }
         else