#if !defined(wxUSE_DATETIME) || wxUSE_DATETIME
#ifndef WX_PRECOMP
- #ifdef __WXMSW__
+ #ifdef __WINDOWS__
#include "wx/msw/wrapwin.h"
#endif
#include "wx/string.h"
#endif
#include "wx/datetime.h"
+#include "wx/time.h"
// ============================================================================
// implementation of wxDateTime
extern void InitTm(struct tm& tm);
-extern int GetTimeZone();
-
extern wxString CallStrftime(const wxString& format, const tm* tm);
// ----------------------------------------------------------------------------
const wxString str(p, end);
wxString::const_iterator endParse;
wxDateTime dt;
- if ( dt.ParseFormat(str, fmt, &endParse) ||
- (!fmtAlt.empty() && dt.ParseFormat(str, fmtAlt, &endParse)) )
+
+ // Use a default date outside of the DST period to avoid problems with
+ // parsing the time differently depending on the today's date (which is used
+ // as the fall back date if none is explicitly specified).
+ static const wxDateTime dtDef(1, wxDateTime::Jan, 2012);
+
+ if ( dt.ParseFormat(str, fmt, dtDef, &endParse) ||
+ (!fmtAlt.empty() && dt.ParseFormat(str, fmtAlt, dtDef, &endParse)) )
{
p += endParse - str.begin();
}
format.Replace("%X",wxLocale::GetInfo(wxLOCALE_TIME_FMT));
#endif
// we have to use our own implementation if the date is out of range of
- // strftime() or if we use non standard specificators
+ // strftime() or if we use non standard specifiers (notice that "%z" is
+ // special because it is de facto standard under Unix but is not supported
+ // under Windows)
#ifdef wxHAS_STRFTIME
time_t time = GetTicks();
- if ( (time != (time_t)-1) && !wxStrstr(format, wxT("%l")) )
+ if ( (time != (time_t)-1) && !wxStrstr(format, wxT("%l"))
+#ifdef __WINDOWS__
+ && !wxStrstr(format, wxT("%z"))
+#endif
+ )
{
// use strftime()
struct tm tmstruct;
struct tm *tm;
- if ( tz.GetOffset() == -GetTimeZone() )
+ if ( tz.GetOffset() == -wxGetTimeZone() )
{
// we are working with local time
tm = wxLocaltime_r(&time, &tmstruct);
// used for calls to strftime() when we only deal with time
struct tm tmTimeOnly;
+ memset(&tmTimeOnly, 0, sizeof(tmTimeOnly));
tmTimeOnly.tm_hour = tm.hour;
tmTimeOnly.tm_min = tm.min;
tmTimeOnly.tm_sec = tm.sec;
- tmTimeOnly.tm_wday = 0;
- tmTimeOnly.tm_yday = 0;
- tmTimeOnly.tm_mday = 1; // any date will do
+ tmTimeOnly.tm_mday = 1; // any date will do, use 1976-01-01
tmTimeOnly.tm_mon = 0;
tmTimeOnly.tm_year = 76;
tmTimeOnly.tm_isdst = 0; // no DST, we adjust for tz ourselves
switch ( (*++p).GetValue() )
{
case wxT('Y'): // year has 4 digits
+ case wxT('z'): // time zone as well
fmt = wxT("%04d");
break;
// (indirectly) set the year correctly
while ( (nLostWeekDays % 7) != 0 )
{
- nLostWeekDays += year++ % 4 ? 1 : 2;
+ nLostWeekDays += (year++ % 4) ? 1 : 2;
}
// finally move the year below 2000 so that the 2-digit
res += wxString::Format(fmt, tm.year);
break;
+ case wxT('z'): // time zone as [-+]HHMM
+ {
+ int ofs = tz.GetOffset();
+
+ // The time zone offset does not include the DST, but
+ // we do need to take it into account when showing the
+ // time in the local time zone to the user.
+ if ( ofs == -wxGetTimeZone() && IsDST() == 1 )
+ {
+ // FIXME: As elsewhere in wxDateTime, we assume
+ // that the DST is always 1 hour, but this is not
+ // true in general.
+ ofs += 3600;
+ }
+
+ if ( ofs < 0 )
+ {
+ res += '-';
+ ofs = -ofs;
+ }
+ else
+ {
+ res += '+';
+ }
+
+ // Converts seconds to HHMM representation.
+ res += wxString::Format(fmt,
+ 100*(ofs/3600) + (ofs/60)%60);
+ }
+ break;
+
case wxT('Z'): // timezone name
#ifdef wxHAS_STRFTIME
res += CallStrftime(wxT("%Z"), &tmTimeOnly);
default:
// is it the format width?
- fmt.Empty();
- while ( *p == wxT('-') || *p == wxT('+') ||
- *p == wxT(' ') || wxIsdigit(*p) )
+ for ( fmt.clear();
+ *p == wxT('-') || *p == wxT('+') ||
+ *p == wxT(' ') || wxIsdigit(*p);
+ ++p )
{
fmt += *p;
}
}
// no, it wasn't the width
- wxFAIL_MSG(wxT("unknown format specificator"));
+ wxFAIL_MSG(wxT("unknown format specifier"));
// fall through and just copy it nevertheless
return true;
}
+const char* wxDateTime::ParseRfc822Date(const char* date)
+{
+ wxString::const_iterator end;
+ wxString dateStr(date);
+ if ( !ParseRfc822Date(dateStr, &end) )
+ return NULL;
+
+ return date + dateStr.IterOffsetInMBStr(end);
+}
+
+const wchar_t* wxDateTime::ParseRfc822Date(const wchar_t* date)
+{
+ wxString::const_iterator end;
+ wxString dateStr(date);
+ if ( !ParseRfc822Date(dateStr, &end) )
+ return NULL;
+
+ return date + (end - dateStr.begin());
+}
+
bool
wxDateTime::ParseFormat(const wxString& date,
const wxString& format,
bool hourIsIn12hFormat = false, // or in 24h one?
isPM = false; // AM by default
+ bool haveTimeZone = false;
+
// and the value of the items we have (init them to get rid of warnings)
wxDateTime_t msec = 0,
sec = 0,
mday = 0;
wxDateTime::Month mon = Inv_Month;
int year = 0;
+ long timeZone = 0; // time zone in seconds as expected in Tm structure
wxString::const_iterator input = date.begin();
const wxString::const_iterator end = date.end();
year = (wxDateTime_t)num;
break;
+ case wxT('z'):
+ {
+ // check that we have something here at all
+ if ( input == end )
+ return false;
+
+ // and then check that it's either plus or minus sign
+ bool minusFound;
+ if ( *input == wxT('-') )
+ minusFound = true;
+ else if ( *input == wxT('+') )
+ minusFound = false;
+ else
+ return false; // no match
+
+ // here should follow 4 digits HHMM
+ ++input;
+ unsigned long tzHourMin;
+ if ( !GetNumericToken(4, input, end, &tzHourMin) )
+ return false; // no match
+
+ const unsigned hours = tzHourMin / 100;
+ const unsigned minutes = tzHourMin % 100;
+
+ if ( hours > 12 || minutes > 59 )
+ return false; // bad format
+
+ timeZone = 3600*hours + 60*minutes;
+ if ( minusFound )
+ timeZone = -timeZone;
+
+ haveTimeZone = true;
+ }
+ break;
+
case wxT('Z'): // timezone name
// FIXME: currently we just ignore everything that looks like a
// time zone here
break;
case wxT('%'): // a percent sign
- if ( *input++ != wxT('%') )
+ if ( input == end || *input++ != wxT('%') )
{
// no match
return false;
Set(tm);
+ // If a time zone was specified and it is not the local time zone, we need
+ // to shift the time accordingly.
+ //
+ // Note that avoiding the call to MakeFromTimeZone is necessary to avoid
+ // DST problems.
+ if ( haveTimeZone && timeZone != -wxGetTimeZone() )
+ MakeFromTimezone(timeZone);
+
// finally check that the week day is consistent -- if we had it
if ( haveWDay && GetWeekDay() != wday )
return false;
return true;
}
+const char*
+wxDateTime::ParseFormat(const char* date,
+ const wxString& format,
+ const wxDateTime& dateDef)
+{
+ wxString::const_iterator end;
+ wxString dateStr(date);
+ if ( !ParseFormat(dateStr, format, dateDef, &end) )
+ return NULL;
+
+ return date + dateStr.IterOffsetInMBStr(end);
+}
+
+const wchar_t*
+wxDateTime::ParseFormat(const wchar_t* date,
+ const wxString& format,
+ const wxDateTime& dateDef)
+{
+ wxString::const_iterator end;
+ wxString dateStr(date);
+ if ( !ParseFormat(dateStr, format, dateDef, &end) )
+ return NULL;
+
+ return date + (end - dateStr.begin());
+}
+
bool
wxDateTime::ParseDateTime(const wxString& date, wxString::const_iterator *end)
{
wxCHECK_MSG( end, false, "end iterator pointer must be specified" );
- // 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();
+ wxDateTime
+ dtDate,
+ dtTime;
wxString::const_iterator
endTime,
return true;
}
+const char* wxDateTime::ParseDateTime(const char* date)
+{
+ wxString::const_iterator end;
+ wxString dateStr(date);
+ if ( !ParseDateTime(dateStr, &end) )
+ return NULL;
+
+ return date + dateStr.IterOffsetInMBStr(end);
+}
+
+const wchar_t* wxDateTime::ParseDateTime(const wchar_t* date)
+{
+ wxString::const_iterator end;
+ wxString dateStr(date);
+ if ( !ParseDateTime(dateStr, &end) )
+ return NULL;
+
+ return date + (end - dateStr.begin());
+}
+
bool
wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
{
const wxString::const_iterator pEnd = date.end();
wxString::const_iterator p = pBegin;
- while ( wxIsspace(*p) )
+ while ( p != pEnd && wxIsspace(*p) )
p++;
// some special cases
if ( len > lenRest )
continue;
- const wxString::const_iterator pEnd = p + len;
- if ( wxString(p, pEnd).CmpNoCase(dateStr) == 0 )
+ const wxString::const_iterator pEndStr = p + len;
+ if ( wxString(p, pEndStr).CmpNoCase(dateStr) == 0 )
{
// nothing can follow this, so stop here
- p = pEnd;
+ p = pEndStr;
int dayDiffFromToday = literalDates[n].dayDiffFromToday;
*this = Today();
*this += wxDateSpan::Days(dayDiffFromToday);
}
- *end = pEnd;
+ *end = pEndStr;
return true;
}
while ( p != pEnd )
{
// skip white space and date delimiters
- while ( wxStrchr(".,/-\t\r\n ", *p) )
+ if ( wxStrchr(".,/-\t\r\n ", *p) )
{
++p;
+ continue;
}
// modify copy of the iterator as we're not sure if the next token is
else // not a valid weekday name
{
// try the ordinals
- static const char *ordinals[] =
+ static const char *const ordinals[] =
{
wxTRANSLATE("first"),
wxTRANSLATE("second"),
return true;
}
+const char* wxDateTime::ParseDate(const char* date)
+{
+ wxString::const_iterator end;
+ wxString dateStr(date);
+ if ( !ParseDate(dateStr, &end) )
+ return NULL;
+
+ return date + dateStr.IterOffsetInMBStr(end);
+}
+
+const wchar_t* wxDateTime::ParseDate(const wchar_t* date)
+{
+ wxString::const_iterator end;
+ wxString dateStr(date);
+ if ( !ParseDate(dateStr, &end) )
+ return NULL;
+
+ return date + (end - dateStr.begin());
+}
+
bool
wxDateTime::ParseTime(const wxString& time, wxString::const_iterator *end)
{
for ( size_t n = 0; n < WXSIZEOF(stdTimes); n++ )
{
const wxString timeString = wxGetTranslation(stdTimes[n].name);
- const wxString::const_iterator p = time.begin() + timeString.length();
- if ( timeString.CmpNoCase(wxString(time.begin(), p)) == 0 )
+ if ( timeString.CmpNoCase(wxString(time, timeString.length())) == 0 )
{
// casts required by DigitalMars
Set(stdTimes[n].hour, wxDateTime_t(0), wxDateTime_t(0));
if ( end )
- *end = p;
+ *end = time.begin() + timeString.length();
return true;
}
// try all time formats we may think about in the order from longest to
// shortest
- static const char *timeFormats[] =
+ static const char *const timeFormats[] =
{
"%I:%M:%S %p", // 12hour with AM/PM
"%H:%M:%S", // could be the same or 24 hour one so try it too
"%I:%M %p", // 12hour with AM/PM but without seconds
- "%H:%M:%S", // and a possibly 24 hour version without seconds
+ "%H:%M", // and a possibly 24 hour version without seconds
+ "%I %p", // just hour with AM/AM
+ "%H", // just hour in 24 hour version
"%X", // possibly something from above or maybe something
// completely different -- try it last
return false;
}
+const char* wxDateTime::ParseTime(const char* date)
+{
+ wxString::const_iterator end;
+ wxString dateStr(date);
+ if ( !ParseTime(dateStr, &end) )
+ return NULL;
+
+ return date + dateStr.IterOffsetInMBStr(end);
+}
+
+const wchar_t* wxDateTime::ParseTime(const wchar_t* date)
+{
+ wxString::const_iterator end;
+ wxString dateStr(date);
+ if ( !ParseTime(dateStr, &end) )
+ return NULL;
+
+ return date + (end - dateStr.begin());
+}
+
// ----------------------------------------------------------------------------
// Workdays and holidays support
// ----------------------------------------------------------------------------