// 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>
#endif
#include "wx/datetime.h"
-#include "wx/stopwatch.h" // for wxGetLocalTimeMillis()
const long wxDateTime::TIME_T_FACTOR = 1000l;
#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
#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
memcpy(temp, localtime(ticks), 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)
memcpy(temp, gmtime(ticks), sizeof(struct tm));
return temp;
}
-#endif
+#endif // !HAVE_GMTIME_R
+
+#endif // wxWinCE with VC8/other platforms
// ----------------------------------------------------------------------------
// macros
// (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
// 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
- 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)
{
s = buf;
return s;
}
-#endif
+
+#endif // HAVE_STRFTIME
#ifdef HAVE_STRPTIME
case wxDateTime::GMT10:
case wxDateTime::GMT11:
case wxDateTime::GMT12:
+ case wxDateTime::GMT13:
m_offset = 3600*(tz - wxDateTime::GMT0);
break;
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;
tm.tm_mon = month;
return CallStrftime(flags == Name_Abbr ? _T("%b") : _T("%B"), &tm);
-#else
+#else // !HAVE_STRFTIME
wxString ret;
switch(month)
{
break;
}
return ret;
-#endif
+#endif // HAVE_STRFTIME/!HAVE_STRFTIME
}
/* static */
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!)
// ... and call strftime()
return CallStrftime(flags == Name_Abbr ? _T("%a") : _T("%A"), &tm);
-#else
+#else // !HAVE_STRFTIME
wxString ret;
switch(wday)
{
break;
}
return ret;
-
-#endif
+#endif // HAVE_STRFTIME/!HAVE_STRFTIME
}
/* static */
ms_country = USA;
}
}
-#else
+#else // __WXWINCE__
ms_country = USA;
-#endif
+#endif // !__WXWINCE__/__WXWINCE__
return ms_country;
}
return dt;
}
+#if WXWIN_COMPATIBILITY_2_6
// use a separate function to avoid warnings about using deprecated
// SetToTheWeek in GetWeek below
static wxDateTime
{
return ::SetToTheWeek(GetYear(), numWeek, weekday, flags);
}
+#endif // WXWIN_COMPATIBILITY_2_6
wxDateTime& wxDateTime::SetToLastMonthDay(Month month,
int year)
{
wxCHECK_MSG( format, wxEmptyString, _T("NULL format in wxDateTime::Format") );
+ time_t time = GetTicks();
+
// we have to use our own implementation if the date is out of range of
// strftime() or if we use non standard specificators
- time_t time = GetTicks();
+#ifdef HAVE_STRFTIME
if ( (time != (time_t)-1) && !wxStrstr(format, _T("%l")) )
{
// use strftime()
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
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.
{
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
&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);
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)
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)
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)
break;
case _T('Z'): // timezone name
-#ifndef __WXWINCE__
+#ifdef HAVE_STRFTIME
res += CallStrftime(_T("%Z"), &tmTimeOnly);
#endif
break;
}
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
);
{
wxLogDebug(_T("ParseDate: no day, no weekday hence no date."));
- return (wxChar *)NULL;
+ return NULL;
}
if ( haveWDay && (haveMon || haveYear || haveDay) &&
// 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) )
// 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;
}
}
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 )
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 )
{
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
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
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
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