#include "wx/intl.h"
#include "wx/stopwatch.h" // for wxGetLocalTimeMillis()
#include "wx/module.h"
+ #include "wx/crt.h"
#endif // WX_PRECOMP
#include "wx/thread.h"
#elif defined(__DARWIN__)
#define WX_GMTOFF_IN_TM
#elif defined(__WXWINCE__) && defined(__VISUALC8__)
+ // _timezone is not present in dynamic run-time library
+ #if 0
+ // Solution (1): use the function equivalent of _timezone
+ static long wxGetTimeZone()
+ {
+ static long s_Timezone = MAXLONG; // invalid timezone
+ if (s_Timezone == MAXLONG)
+ {
+ int t;
+ _get_timezone(& t);
+ s_Timezone = (long) t;
+ }
+ return s_Timezone;
+ }
+ #define WX_TIMEZONE wxGetTimeZone()
+ #elif 1
+ // Solution (2): using GetTimeZoneInformation
+ static long wxGetTimeZone()
+ {
+ static long timezone = MAXLONG; // invalid timezone
+ if (timezone == MAXLONG)
+ {
+ TIME_ZONE_INFORMATION tzi;
+ ::GetTimeZoneInformation(&tzi);
+ timezone = tzi.Bias;
+ }
+ return timezone;
+ }
+ #define WX_TIMEZONE wxGetTimeZone()
+ #else
+ // Old method using _timezone: this symbol doesn't exist in the dynamic run-time library (i.e. using /MD)
#define WX_TIMEZONE _timezone
+ #endif
#else // unknown platform - try timezone
#define WX_TIMEZONE timezone
#endif
// 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 // !HAVE_LOCALTIME_R
// 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;
}
#ifdef HAVE_STRFTIME
// this function is a wrapper around strftime(3) adding error checking
-static wxString CallStrftime(const wxChar *format, const tm* tm)
+static wxString CallStrftime(const wxString& format, const tm* tm)
{
wxChar buf[4096];
// Create temp wxString here to work around mingw/cygwin bug 1046059
// 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)
}
dt += wxTimeSpan::Hours(1);
-
- // disable DST tests because it could result in an infinite recursion!
- dt.MakeGMT(true);
}
else switch ( country )
{
}
dt += wxTimeSpan::Hours(1);
-
- // disable DST tests because it could result in an infinite recursion!
- dt.MakeGMT(true);
}
else switch ( country )
{
time_t ticks = GetTicks();
struct tm tmstruct;
struct tm *tm = wxLocaltime_r(&ticks, &tmstruct);
+ wxCHECK_MSG( tm, ULONG_MAX, _T("time can't be represented in DOS format") );
long year = tm->tm_year;
year -= 80;
// wxDateTime to/from text representations
// ----------------------------------------------------------------------------
-wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
+wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
{
- wxCHECK_MSG( format, wxEmptyString, _T("NULL format in wxDateTime::Format") );
-
- time_t time = GetTicks();
+ wxCHECK_MSG( !format.empty(), wxEmptyString,
+ _T("NULL format in wxDateTime::Format") );
// 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()
tmTimeOnly.tm_isdst = 0; // no DST, we adjust for tz ourselves
wxString tmp, res, fmt;
- for ( const wxChar *p = format; *p; p++ )
+ for ( wxString::const_iterator p = format.begin(); p != format.end(); ++p )
{
if ( *p != _T('%') )
{
}
// set the default format
- switch ( *++p )
+ switch ( (*++p).GetValue() )
{
case _T('Y'): // year has 4 digits
fmt = _T("%04d");
restart = false;
// start of the format specification
- switch ( *p )
+ switch ( (*p).GetValue() )
{
case _T('a'): // a weekday name
case _T('A'):
// will change if one of these years is leap and the other one
// is not!
{
- // find the YEAR: normally, for any year X, Jan 1 or the
+ // find the YEAR: normally, for any year X, Jan 1 of the
// year X + 28 is the same weekday as Jan 1 of X (because
// the weekday advances by 1 for each normal X and by 2
// for each leap X, hence by 5 every 4 years or by 35
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") );
+ // finally move the year below 2000 so that the 2-digit
+ // year number can never match the month or day of the
+ // month when we do the replacements below
+ if ( year >= 2000 )
+ year -= 28;
- 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;
- }
+ wxASSERT_MSG( year >= 1970 && year < 2000,
+ _T("logic error in wxDateTime::Format") );
- 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;
// use strftime() to format the same date but in supported
// year
: _T("%x"),
&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, replacement3);
- str.Replace(strYear2,replacement4);
- str.Replace(replacement3, strYearReal);
- str.Replace(replacement4, strYearReal2);
-
- // and replace back all occurrences of replacement string
- if ( wasReplaced )
- {
- str.Replace(replacement2, strYear2);
- str.Replace(replacement, strYear);
- }
+ // now replace the replacement year with the real year:
+ // notice that we have to replace the 4 digit year with
+ // a unique string not appearing in strftime() output
+ // first to prevent the 2 digit year from matching any
+ // substring of the 4 digit year (but any day, month,
+ // hours or minutes components should be safe because
+ // they are never in 70-99 range)
+ wxString replacement("|");
+ while ( str.find(replacement) != wxString::npos )
+ replacement += '|';
+
+ str.Replace(wxString::Format("%d", year),
+ replacement);
+ str.Replace(wxString::Format("%d", year % 100),
+ wxString::Format("%d", yearReal % 100));
+ str.Replace(replacement,
+ wxString::Format("%d", yearReal));
res += str;
}
#endif // __WINDOWS__
const wxChar *wxDateTime::ParseFormat(const wxChar *date,
- const wxChar *format,
+ const wxString& format,
const wxDateTime& dateDef)
{
- wxCHECK_MSG( date && format, (wxChar *)NULL,
+ wxCHECK_MSG( date && !format.empty(), (wxChar *)NULL,
_T("NULL pointer in wxDateTime::ParseFormat()") );
wxString str;
int year = 0;
const wxChar *input = date;
- for ( const wxChar *fmt = format; *fmt; fmt++ )
+ for ( wxString::const_iterator fmt = format.begin(); fmt != format.end(); ++fmt )
{
if ( *fmt != _T('%') )
{
// the default widths for the various fields
if ( !width )
{
- switch ( *fmt )
+ switch ( (*fmt).GetValue() )
{
case _T('Y'): // year has 4 digits
width = 4;
}
// then the format itself
- switch ( *fmt )
+ switch ( (*fmt).GetValue() )
{
case _T('a'): // a weekday name
case _T('A'):
// some special cases
static struct
{
- const wxChar *str;
+ const char *str;
int dayDiffFromToday;
} literalDates[] =
{
else // not a valid weekday name
{
// try the ordinals
- static const wxChar *ordinals[] =
+ static const char *ordinals[] =
{
wxTRANSLATE("first"),
wxTRANSLATE("second"),
// first try some extra things
static const struct
{
- const wxChar *name;
+ const char *name;
wxDateTime_t hour;
} stdTimes[] =
{
// And, to be better than MFC :-), we also have
// %E number of wEeks
// %l milliseconds (000 - 999)
-wxString wxTimeSpan::Format(const wxChar *format) const
+wxString wxTimeSpan::Format(const wxString& format) const
{
- wxCHECK_MSG( format, wxEmptyString, _T("NULL format in wxTimeSpan::Format") );
+ wxCHECK_MSG( !format.empty(), wxEmptyString,
+ _T("NULL format in wxTimeSpan::Format") );
wxString str;
- str.Alloc(wxStrlen(format));
+ str.Alloc(format.length());
// Suppose we have wxTimeSpan ts(1 /* hour */, 2 /* min */, 3 /* sec */)
//
// we remember the most important unit found so far
TimeSpanPart partBiggest = Part_MSec;
- for ( const wxChar *pch = format; *pch; pch++ )
+ for ( wxString::const_iterator pch = format.begin(); pch != format.end(); ++pch )
{
wxChar ch = *pch;