]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/datetime.cpp
added HasExtraStyle()
[wxWidgets.git] / src / common / datetime.cpp
index 1873b018468006777a0ecab19d90a0c72ac7d19e..765e3164192d7fc4adcdda191632be7c24efa5ea 100644 (file)
 // 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:
  *
 #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 +85,6 @@
 #endif
 
 #include "wx/datetime.h"
-#include "wx/stopwatch.h"           // for wxGetLocalTimeMillis()
 
 const long wxDateTime::TIME_T_FACTOR = 1000l;
 
@@ -139,6 +137,13 @@ wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter<wxDateTime> , wxFromStringCon
     #include <wtime.h>
 #endif
 
+// define a special symbol for VC8 instead of writing tests for 1400 repeatedly
+#ifdef __VISUALC__
+    #if __VISUALC__ >= 1400
+        #define __VISUALC8__
+    #endif
+#endif
+
 #if !defined(WX_TIMEZONE) && !defined(WX_GMTOFF_IN_TM)
     #if defined(__WXPALMOS__)
         #define WX_GMTOFF_IN_TM
@@ -164,11 +169,35 @@ wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter<wxDateTime> , wxFromStringCon
         #define WX_TIMEZONE wxGetTimeZone()
     #elif defined(__DARWIN__)
         #define WX_GMTOFF_IN_TM
+    #elif defined(__WXWINCE__) && defined(__VISUALC8__)
+        #define WX_TIMEZONE _timezone
     #else // unknown platform - try timezone
         #define WX_TIMEZONE timezone
     #endif
 #endif // !WX_TIMEZONE && !WX_GMTOFF_IN_TM
 
+// everyone has strftime except Win CE unless VC8 is used
+#if !defined(__WXWINCE__) || defined(__VISUALC8__)
+    #define HAVE_STRFTIME
+#endif
+
+// NB: VC8 safe time functions could/should be used for wxMSW as well probably
+#if defined(__WXWINCE__) && defined(__VISUALC8__)
+
+struct tm *wxLocaltime_r(const time_t *t, struct tm* tm)
+{
+    __time64_t t64 = *t;
+    return _localtime64_s(tm, &t64) == 0 ? tm : NULL;
+}
+
+struct tm *wxGmtime_r(const time_t* t, struct tm* tm)
+{
+    __time64_t t64 = *t;
+    return _gmtime64_s(tm, &t64) == 0 ? tm : NULL;
+}
+
+#else // !wxWinCE with VC8
+
 #if (!defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)) && wxUSE_THREADS && !defined(__WINDOWS__)
 static wxMutex timeLock;
 #endif
@@ -181,10 +210,21 @@ struct tm *wxLocaltime_r(const time_t* ticks, struct tm* temp)
   // thread local storage for localtime anyway.
   wxMutexLocker locker(timeLock);
 #endif
-  memcpy(temp, localtime(ticks), sizeof(struct tm));
+
+  // Borland CRT crashes when passed 0 ticks for some reason, see SF bug 1704438
+#ifdef __BORLANDC__
+  if ( !*ticks )
+      return NULL;
+#endif
+
+  const tm * const t = localtime(ticks);
+  if ( !t )
+      return NULL;
+
+  memcpy(temp, t, sizeof(struct tm));
   return temp;
 }
-#endif
+#endif // !HAVE_LOCALTIME_R
 
 #ifndef HAVE_GMTIME_R
 struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp)
@@ -194,10 +234,22 @@ struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp)
   // using thread local storage for gmtime anyway.
   wxMutexLocker locker(timeLock);
 #endif
+
+#ifdef __BORLANDC__
+  if ( !*ticks )
+      return NULL;
+#endif
+
+  const tm * const t = gmtime(ticks);
+  if ( !t )
+      return NULL;
+
   memcpy(temp, gmtime(ticks), sizeof(struct tm));
   return temp;
 }
-#endif
+#endif // !HAVE_GMTIME_R
+
+#endif // wxWinCE with VC8/other platforms
 
 // ----------------------------------------------------------------------------
 // macros
@@ -395,7 +447,8 @@ static long GetTruncatedJDN(wxDateTime::wxDateTime_t day,
             - JDN_OFFSET;
 }
 
-#ifndef __WXWINCE__
+#ifdef HAVE_STRFTIME
+
 // this function is a wrapper around strftime(3) adding error checking
 static wxString CallStrftime(const wxChar *format, const tm* tm)
 {
@@ -413,7 +466,8 @@ static wxString CallStrftime(const wxChar *format, const tm* tm)
     s = buf;
     return s;
 }
-#endif
+
+#endif // HAVE_STRFTIME
 
 #ifdef HAVE_STRPTIME
 
@@ -627,7 +681,7 @@ void wxDateTime::Tm::ComputeWeekDay()
     // compute the week day from day/month/year: we use the dumbest algorithm
     // possible: just compute our JDN and then use the (simple to derive)
     // formula: weekday = (JDN + 1.5) % 7
-    wday = (wxDateTime::wxDateTime_t)((wxDateTime::WeekDay)(GetTruncatedJDN(mday, mon, year) + 2) % 7);
+    wday = (wxDateTime::wxDateTime_t)((GetTruncatedJDN(mday, mon, year) + 2) % 7);
 }
 
 void wxDateTime::Tm::AddMonths(int monDiff)
@@ -719,6 +773,7 @@ wxDateTime::TimeZone::TimeZone(wxDateTime::TZ tz)
         case wxDateTime::GMT10:
         case wxDateTime::GMT11:
         case wxDateTime::GMT12:
+        case wxDateTime::GMT13:
             m_offset = 3600*(tz - wxDateTime::GMT0);
             break;
 
@@ -869,7 +924,7 @@ wxString wxDateTime::GetMonthName(wxDateTime::Month month,
                                   wxDateTime::NameFlags flags)
 {
     wxCHECK_MSG( month != Inv_Month, wxEmptyString, _T("invalid month") );
-#ifndef __WXWINCE__
+#ifdef HAVE_STRFTIME
     // notice that we must set all the fields to avoid confusing libc (GNU one
     // gets confused to a crash if we don't do this)
     tm tm;
@@ -877,7 +932,7 @@ wxString wxDateTime::GetMonthName(wxDateTime::Month month,
     tm.tm_mon = month;
 
     return CallStrftime(flags == Name_Abbr ? _T("%b") : _T("%B"), &tm);
-#else
+#else // !HAVE_STRFTIME
     wxString ret;
     switch(month)
     {
@@ -919,7 +974,7 @@ wxString wxDateTime::GetMonthName(wxDateTime::Month month,
             break;
     }
     return ret;
-#endif
+#endif // HAVE_STRFTIME/!HAVE_STRFTIME
 }
 
 /* static */
@@ -927,7 +982,7 @@ wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday,
                                     wxDateTime::NameFlags flags)
 {
     wxCHECK_MSG( wday != Inv_WeekDay, wxEmptyString, _T("invalid weekday") );
-#ifndef __WXWINCE__
+#ifdef HAVE_STRFTIME
     // take some arbitrary Sunday (but notice that the day should be such that
     // after adding wday to it below we still have a valid date, e.g. don't
     // take 28 here!)
@@ -945,7 +1000,7 @@ wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday,
 
     // ... and call strftime()
     return CallStrftime(flags == Name_Abbr ? _T("%a") : _T("%A"), &tm);
-#else
+#else // !HAVE_STRFTIME
     wxString ret;
     switch(wday)
     {
@@ -972,8 +1027,7 @@ wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday,
             break;
     }
     return ret;
-
-#endif
+#endif // HAVE_STRFTIME/!HAVE_STRFTIME
 }
 
 /* static */
@@ -1051,9 +1105,9 @@ wxDateTime::Country wxDateTime::GetCountry()
             ms_country = USA;
         }
     }
-#else
+#else // __WXWINCE__
      ms_country = USA;
-#endif
+#endif // !__WXWINCE__/__WXWINCE__
 
     return ms_country;
 }
@@ -1463,6 +1517,16 @@ wxDateTime& wxDateTime::ResetTime()
     return *this;
 }
 
+wxDateTime wxDateTime::GetDateOnly() const
+{
+    Tm tm = GetTm();
+    tm.msec =
+    tm.sec =
+    tm.min =
+    tm.hour = 0;
+    return wxDateTime(tm);
+}
+
 // ----------------------------------------------------------------------------
 // DOS Date and Time Format functions
 // ----------------------------------------------------------------------------
@@ -2220,7 +2284,9 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
 
     // we have to use our own implementation if the date is out of range of
     // strftime() or if we use non standard specificators
+#ifdef HAVE_STRFTIME
     time_t time = GetTicks();
+
     if ( (time != (time_t)-1) && !wxStrstr(format, _T("%l")) )
     {
         // use strftime()
@@ -2255,15 +2321,14 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
                 tm = (struct tm *)NULL;
             }
         }
-#ifndef __WXWINCE__
-    //Windows CE doesn't support strftime or wcsftime, so we use the generic implementation
+
         if ( tm )
         {
             return CallStrftime(format, tm);
         }
-#endif
-        //else: use generic code below
     }
+    //else: use generic code below
+#endif // HAVE_STRFTIME
 
     // we only parse ANSI C format specifications here, no POSIX 2
     // complications, no GNU extensions but we do add support for a "%l" format
@@ -2340,7 +2405,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
 
                 case _T('c'):       // locale default date and time  representation
                 case _T('x'):       // locale default date representation
-#ifndef __WXWINCE__
+#ifdef HAVE_STRFTIME
                     //
                     // the problem: there is no way to know what do these format
                     // specifications correspond to for the current locale.
@@ -2403,40 +2468,42 @@ 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;
+
+                        // 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") );
 
-                       wxString strYear, strYear2;
+                        wxString strYear, strYear2;
                         strYear.Printf(_T("%d"), year);
                         strYear2.Printf(_T("%d"), year % 100);
-       
+
                         // find four strings not occurring in format (this is surely
                         // not the optimal way of doing it... improvements welcome!)
                         wxString fmt2 = format;
-                       wxString replacement,replacement2,replacement3,replacement4;
-                       for (int rnr=1; rnr<5 ; rnr++) {
-                               wxString r = (wxChar)-rnr;
-                               while ( fmt2.Find(r) != wxNOT_FOUND )
-                               {
-                                   r << (wxChar)-rnr;
-                               }
-
-                               switch (rnr) {
-                                       case 1: replacement=r; break;
-                                       case 2: replacement2=r; break;
-                                       case 3: replacement3=r; break;
-                                       case 4: replacement4=r; break;
-                               }
-                       }
+                        wxString replacement,replacement2,replacement3,replacement4;
+                        for (int rnr=1; rnr<5 ; rnr++)
+                        {
+                            wxString r = (wxChar)-rnr;
+                            while ( fmt2.Find(r) != wxNOT_FOUND )
+                            {
+                                r << (wxChar)-rnr;
+                            }
+
+                            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;
                         // evaluation order ensures we always attempt the replacement.
-                       wasReplaced = (fmt2.Replace(strYear2, replacement2) > 0) | wasReplaced ;
+                        wasReplaced = (fmt2.Replace(strYear2, replacement2) > 0) || wasReplaced;
 
                         // use strftime() to format the same date but in supported
                         // year
@@ -2461,10 +2528,10 @@ 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.
+                        // 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);
@@ -2482,11 +2549,11 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
 
                         res += str;
                     }
-#else
-                    //Use "%m/%d/%y %H:%M:%S" format instead
+#else // !HAVE_STRFTIME
+                    // 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
+#endif // HAVE_STRFTIME/!HAVE_STRFTIME
                     break;
 
                 case _T('d'):       // day of a month (01-31)
@@ -2523,11 +2590,11 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
                     break;
 
                 case _T('p'):       // AM or PM string
-#ifndef __WXWINCE__
+#ifdef HAVE_STRFTIME
                     res += CallStrftime(_T("%p"), &tmTimeOnly);
-#else
+#else // !HAVE_STRFTIME
                     res += (tmTimeOnly.tm_hour > 12) ? wxT("pm") : wxT("am");
-#endif
+#endif // HAVE_STRFTIME/!HAVE_STRFTIME
                     break;
 
                 case _T('S'):       // second as a decimal number (00-61)
@@ -2550,11 +2617,11 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
 
                 case _T('X'):       // locale default time representation
                     // just use strftime() to format the time for us
-#ifndef __WXWINCE__
+#ifdef HAVE_STRFTIME
                     res += CallStrftime(_T("%X"), &tmTimeOnly);
-#else
+#else // !HAVE_STRFTIME
                     res += wxString::Format(wxT("%02d:%02d:%02d"),tm.hour, tm.min, tm.sec);
-#endif
+#endif // HAVE_STRFTIME/!HAVE_STRFTIME
                     break;
 
                 case _T('y'):       // year without century (00-99)
@@ -2566,7 +2633,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
                     break;
 
                 case _T('Z'):       // timezone name
-#ifndef __WXWINCE__
+#ifdef HAVE_STRFTIME
                     res += CallStrftime(_T("%Z"), &tmTimeOnly);
 #endif
                     break;
@@ -4232,11 +4299,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 )
             {
@@ -4271,6 +4341,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
@@ -4278,25 +4355,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
@@ -4304,13 +4387,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
@@ -4318,10 +4404,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