wxDateTime::ParseFormat() and ParseTime() added (compile but don't work)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@5054 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
657d209757
commit
f0f951faab
@ -33,6 +33,7 @@ all (GUI):
|
||||
- wxDC::DrawRotatedText() (based on contribution by Hans-Joachim Baader)
|
||||
|
||||
- TIFF support added (libtiff required and included in the distribution)
|
||||
- PCX files can now be written (24 bit only so far)
|
||||
|
||||
wxMSW:
|
||||
|
||||
@ -46,6 +47,10 @@ wxGTK:
|
||||
- wxGTK synthesizes wxActivateEvents
|
||||
- UpdateUI handlers may be used with wxTextCtrl
|
||||
|
||||
wxMotif:
|
||||
|
||||
- wxMenu::Enable) works
|
||||
|
||||
NOTE: for changes after wxWindows 2.1.0 b4, please see the CVS
|
||||
change log.
|
||||
|
||||
|
@ -108,6 +108,9 @@ public:
|
||||
// data in this format
|
||||
typedef unsigned short wxDateTime_t;
|
||||
|
||||
// constants
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// the timezones
|
||||
enum TZ
|
||||
{
|
||||
@ -344,6 +347,13 @@ public:
|
||||
Inv_Year = SHRT_MIN // should hold in wxDateTime_t
|
||||
};
|
||||
|
||||
// flags for GetWeekDayName and GetMonthName
|
||||
enum NameFlags
|
||||
{
|
||||
Name_Full = 0x01, // return full name
|
||||
Name_Abbr = 0x02 // return abbreviated name
|
||||
};
|
||||
|
||||
// helper classes
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@ -453,11 +463,16 @@ public:
|
||||
|
||||
// get the full (default) or abbreviated month name in the current
|
||||
// locale, returns empty string on error
|
||||
static wxString GetMonthName(Month month, bool abbr = FALSE);
|
||||
static wxString GetMonthName(Month month,
|
||||
NameFlags flags = Name_Full);
|
||||
|
||||
// get the full (default) or abbreviated weekday name in the current
|
||||
// locale, returns empty string on error
|
||||
static wxString GetWeekDayName(WeekDay weekday, bool abbr = FALSE);
|
||||
static wxString GetWeekDayName(WeekDay weekday,
|
||||
NameFlags flags = Name_Full);
|
||||
|
||||
// get the AM and PM strings in the current locale (may be empty)
|
||||
static void GetAmPmStrings(wxString *am, wxString *pm);
|
||||
|
||||
// return TRUE if the given country uses DST for this year
|
||||
static bool IsDSTApplicable(int year = Inv_Year,
|
||||
@ -622,6 +637,9 @@ public:
|
||||
wxDateTime& SetToLastMonthDay(Month month = Inv_Month,
|
||||
int year = Inv_Year);
|
||||
|
||||
// sets to the given year day (1..365 or 366)
|
||||
wxDateTime& SetToYearDay(wxDateTime_t yday);
|
||||
|
||||
// The definitions below were taken verbatim from
|
||||
//
|
||||
// http://www.capecod.net/~pbaum/date/date0.htm
|
||||
@ -815,9 +833,13 @@ public:
|
||||
// parse a string in RFC 822 format (found e.g. in mail headers and
|
||||
// having the form "Wed, 10 Feb 1999 19:07:07 +0100")
|
||||
const wxChar *ParseRfc822Date(const wxChar* date);
|
||||
// parse a date/time in the given format (see strptime(3))
|
||||
// parse a date/time in the given format (see strptime(3)), fill in
|
||||
// the missing (in the string) fields with the values of dateDef (by
|
||||
// default, they will not change if they had valid values or will
|
||||
// default to Today() otherwise)
|
||||
const wxChar *ParseFormat(const wxChar *date,
|
||||
const wxChar *format = _T("%c"));
|
||||
const wxChar *format = _T("%c"),
|
||||
const wxDateTime& dateDef = ms_InvDateTime);
|
||||
// parse a string containing the date/time in "free" format, this
|
||||
// function will try to make an educated guess at the string contents
|
||||
const wxChar *ParseDateTime(const wxChar *datetime);
|
||||
|
@ -304,7 +304,7 @@ struct Date
|
||||
wxString s;
|
||||
s.Printf("%02d-%s-%4d%s",
|
||||
day,
|
||||
wxDateTime::GetMonthName(month, TRUE).c_str(),
|
||||
wxDateTime::GetMonthName(month, wxDateTime::Name_Abbr).c_str(),
|
||||
abs(wxDateTime::ConvertYearToBC(year)),
|
||||
year > 0 ? "AD" : "BC");
|
||||
return s;
|
||||
@ -344,7 +344,7 @@ static void TestTimeStatic()
|
||||
|
||||
wxDateTime::Month month = wxDateTime::GetCurrentMonth();
|
||||
printf("Current month is '%s' ('%s') and it has %d days\n",
|
||||
wxDateTime::GetMonthName(month, TRUE).c_str(),
|
||||
wxDateTime::GetMonthName(month, wxDateTime::Name_Abbr).c_str(),
|
||||
wxDateTime::GetMonthName(month).c_str(),
|
||||
wxDateTime::GetNumberOfDays(month));
|
||||
|
||||
@ -822,7 +822,7 @@ static void TestTimeFormat()
|
||||
|
||||
static const char *formatTestFormats[] =
|
||||
{
|
||||
"%c",
|
||||
"---> %c",
|
||||
"Date is %A, %d of %B, in year %Y",
|
||||
"Date is %x, time is %X",
|
||||
"Time is %H:%M:%S or %I:%M:%S %p",
|
||||
@ -849,7 +849,30 @@ static void TestTimeFormat()
|
||||
wxDateTime dt = d == 0 ? wxDateTime::Now() : formatTestDates[d].DT();
|
||||
for ( size_t n = 0; n < WXSIZEOF(formatTestFormats); n++ )
|
||||
{
|
||||
printf("%s\n", dt.Format(formatTestFormats[n]).c_str());
|
||||
wxString s = dt.Format(formatTestFormats[n]);
|
||||
printf("%s", s.c_str());
|
||||
|
||||
// convert back
|
||||
wxDateTime dt2;
|
||||
const wxChar *result = dt2.ParseFormat(s, formatTestFormats[n]);
|
||||
if ( !result )
|
||||
{
|
||||
puts(" (ERROR: conversion back failed)");
|
||||
}
|
||||
else if ( *result )
|
||||
{
|
||||
// should have parsed the entire string
|
||||
puts(" (ERROR: conversion back stopped too soon)");
|
||||
}
|
||||
else if ( dt2 != dt )
|
||||
{
|
||||
printf(" (ERROR: got back '%s' instead of '%s')\n",
|
||||
dt2.Format().c_str(), dt.Format().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
puts(" (ok)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1270,6 +1293,19 @@ static void TestStringSub()
|
||||
puts("");
|
||||
}
|
||||
|
||||
static void TestStringFormat()
|
||||
{
|
||||
puts("*** Testing wxString formatting ***");
|
||||
|
||||
wxString s;
|
||||
s.Printf("%03d", 18);
|
||||
|
||||
printf("Number 18: %s\n", wxString::Format("%03d", 18).c_str());
|
||||
printf("Number 18: %s\n", s.c_str());
|
||||
|
||||
puts("");
|
||||
}
|
||||
|
||||
#endif // TEST_STRINGS
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -1289,7 +1325,11 @@ int main(int argc, char **argv)
|
||||
TestPChar();
|
||||
TestString();
|
||||
}
|
||||
TestStringSub();
|
||||
if ( 0 )
|
||||
{
|
||||
TestStringSub();
|
||||
}
|
||||
TestStringFormat();
|
||||
#endif // TEST_STRINGS
|
||||
|
||||
#ifdef TEST_ARRAYS
|
||||
|
@ -72,18 +72,32 @@
|
||||
#include "wx/thread.h"
|
||||
#include "wx/tokenzr.h"
|
||||
|
||||
#define wxDEFINE_TIME_CONSTANTS
|
||||
#define wxDEFINE_TIME_CONSTANTS // before including datetime.h
|
||||
|
||||
#include "wx/datetime.h"
|
||||
|
||||
#ifndef WX_TIMEZONE
|
||||
#define WX_TIMEZONE timezone
|
||||
#endif
|
||||
// ----------------------------------------------------------------------------
|
||||
// conditional compilation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Is this right? Just a guess. (JACS)
|
||||
#ifdef __MINGW32__
|
||||
#define timezone _timezone
|
||||
#endif
|
||||
#if defined(HAVE_STRPTIME) && defined(__LINUX__)
|
||||
// glibc 2.0.7 strptime() is broken - the following snippet causes it to
|
||||
// crash (instead of just failing):
|
||||
//
|
||||
// strncpy(buf, "Tue Dec 21 20:25:40 1999", 128);
|
||||
// strptime(buf, "%x", &tm);
|
||||
//
|
||||
// so don't use it
|
||||
#undef HAVE_STRPTIME
|
||||
#endif // broken strptime()
|
||||
|
||||
#ifndef WX_TIMEZONE
|
||||
#ifdef __MINGW32__
|
||||
#define WX_TIMEZONE _timezone
|
||||
#else // unknown platform - try timezone
|
||||
#define WX_TIMEZONE timezone
|
||||
#endif
|
||||
#endif // !WX_TIMEZONE
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// constants
|
||||
@ -114,6 +128,14 @@ static const long DAYS_PER_5_MONTHS = 153l;
|
||||
static const long DAYS_PER_4_YEARS = 1461l;
|
||||
static const long DAYS_PER_400_YEARS = 146097l;
|
||||
|
||||
// this array contains the cumulated number of days in all previous months for
|
||||
// normal and leap years
|
||||
static const wxDateTime::wxDateTime_t gs_cumulatedDays[2][MONTHS_IN_YEAR] =
|
||||
{
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
|
||||
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// globals
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -124,12 +146,6 @@ static const long DAYS_PER_400_YEARS = 146097l;
|
||||
wxCriticalSection gs_critsectTimezone;
|
||||
#endif // wxUSE_THREADS
|
||||
|
||||
// the symbolic names for date spans
|
||||
wxDateSpan wxYear = wxDateSpan(1, 0, 0, 0);
|
||||
wxDateSpan wxMonth = wxDateSpan(0, 1, 0, 0);
|
||||
wxDateSpan wxWeek = wxDateSpan(0, 0, 1, 0);
|
||||
wxDateSpan wxDay = wxDateSpan(0, 0, 0, 1);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// private functions
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -245,20 +261,45 @@ static void ReplaceDefaultYearMonthWithCurrent(int *year,
|
||||
}
|
||||
}
|
||||
|
||||
// fll the struct tm with default values
|
||||
static void InitTm(struct tm& tm)
|
||||
{
|
||||
// struct tm may have etxra fields (undocumented and with unportable
|
||||
// names) which, nevertheless, must be set to 0
|
||||
memset(&tm, 0, sizeof(struct tm));
|
||||
|
||||
tm.tm_mday = 1; // mday 0 is invalid
|
||||
tm.tm_year = 76; // any valid year
|
||||
tm.tm_isdst = -1; // auto determine
|
||||
}
|
||||
|
||||
// parsing helpers
|
||||
// ---------------
|
||||
|
||||
// return the month if the string is a month name or Inv_Month otherwise
|
||||
static wxDateTime::Month GetMonthFromName(const wxString& name)
|
||||
static wxDateTime::Month GetMonthFromName(const wxString& name, int flags)
|
||||
{
|
||||
wxDateTime::Month mon;
|
||||
for ( mon = wxDateTime::Jan; mon < wxDateTime::Inv_Month; wxNextMonth(mon) )
|
||||
{
|
||||
// case-insensitive comparison with both abbreviated and not versions
|
||||
if ( name.CmpNoCase(wxDateTime::GetMonthName(mon, TRUE)) ||
|
||||
name.CmpNoCase(wxDateTime::GetMonthName(mon, FALSE)) )
|
||||
// case-insensitive comparison either one of or with both abbreviated
|
||||
// and not versions
|
||||
if ( flags & wxDateTime::Name_Full )
|
||||
{
|
||||
break;
|
||||
if ( name.CmpNoCase(wxDateTime::
|
||||
GetMonthName(mon, wxDateTime::Name_Full)) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( flags & wxDateTime::Name_Abbr )
|
||||
{
|
||||
if ( name.CmpNoCase(wxDateTime::
|
||||
GetMonthName(mon, wxDateTime::Name_Abbr)) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,22 +307,59 @@ static wxDateTime::Month GetMonthFromName(const wxString& name)
|
||||
}
|
||||
|
||||
// return the weekday if the string is a weekday name or Inv_WeekDay otherwise
|
||||
static wxDateTime::WeekDay GetWeekDayFromName(const wxString& name)
|
||||
static wxDateTime::WeekDay GetWeekDayFromName(const wxString& name, int flags)
|
||||
{
|
||||
wxDateTime::WeekDay wd;
|
||||
for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) )
|
||||
{
|
||||
// case-insensitive comparison with both abbreviated and not versions
|
||||
if ( name.IsSameAs(wxDateTime::GetWeekDayName(wd, TRUE), FALSE) ||
|
||||
name.IsSameAs(wxDateTime::GetWeekDayName(wd, FALSE), FALSE) )
|
||||
// case-insensitive comparison either one of or with both abbreviated
|
||||
// and not versions
|
||||
if ( flags & wxDateTime::Name_Full )
|
||||
{
|
||||
break;
|
||||
if ( name.CmpNoCase(wxDateTime::
|
||||
GetWeekDayName(wd, wxDateTime::Name_Full)) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( flags & wxDateTime::Name_Abbr )
|
||||
{
|
||||
if ( name.CmpNoCase(wxDateTime::
|
||||
GetWeekDayName(wd, wxDateTime::Name_Abbr)) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return wd;
|
||||
}
|
||||
|
||||
// scans all digits and returns the resulting number
|
||||
static bool GetNumericToken(const wxChar*& p, unsigned long *number)
|
||||
{
|
||||
wxString s;
|
||||
while ( wxIsdigit(*p) )
|
||||
{
|
||||
s += *p++;
|
||||
}
|
||||
|
||||
return !!s && s.ToULong(number);
|
||||
}
|
||||
|
||||
// scans all alphabetic characters and returns the resulting string
|
||||
static wxString GetAlphaToken(const wxChar*& p)
|
||||
{
|
||||
wxString s;
|
||||
while ( wxIsalpha(*p) )
|
||||
{
|
||||
s += *p++;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// implementation of wxDateTime
|
||||
// ============================================================================
|
||||
@ -570,33 +648,32 @@ wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(wxDateTime::Month month,
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxString wxDateTime::GetMonthName(wxDateTime::Month month, bool abbr)
|
||||
wxString wxDateTime::GetMonthName(wxDateTime::Month month,
|
||||
wxDateTime::NameFlags flags)
|
||||
{
|
||||
wxCHECK_MSG( month != Inv_Month, _T(""), _T("invalid month") );
|
||||
|
||||
// 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_hour =
|
||||
tm.tm_min =
|
||||
tm.tm_sec =
|
||||
tm.tm_wday =
|
||||
tm.tm_yday = 0;
|
||||
tm.tm_mday = 1;
|
||||
InitTm(tm);
|
||||
tm.tm_mon = month;
|
||||
tm.tm_year = 76; // any year will do
|
||||
tm.tm_isdst = -1;
|
||||
|
||||
return CallStrftime(abbr ? _T("%b") : _T("%B"), &tm);
|
||||
return CallStrftime(flags == Name_Abbr ? _T("%b") : _T("%B"), &tm);
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday, bool abbr)
|
||||
wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday,
|
||||
wxDateTime::NameFlags flags)
|
||||
{
|
||||
wxCHECK_MSG( wday != Inv_WeekDay, _T(""), _T("invalid weekday") );
|
||||
|
||||
// take some arbitrary Sunday
|
||||
tm tm = { 0, 0, 0, 28, Nov, 99 };
|
||||
tm tm;
|
||||
InitTm(tm);
|
||||
tm.tm_mday = 28;
|
||||
tm.tm_mon = Nov;
|
||||
tm.tm_year = 99;
|
||||
|
||||
// and offset it by the number of days needed to get the correct wday
|
||||
tm.tm_mday += wday;
|
||||
@ -605,7 +682,23 @@ wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday, bool abbr)
|
||||
(void)mktime(&tm);
|
||||
|
||||
// ... and call strftime()
|
||||
return CallStrftime(abbr ? _T("%a") : _T("%A"), &tm);
|
||||
return CallStrftime(flags == Name_Abbr ? _T("%a") : _T("%A"), &tm);
|
||||
}
|
||||
|
||||
/* static */
|
||||
void wxDateTime::GetAmPmStrings(wxString *am, wxString *pm)
|
||||
{
|
||||
tm tm;
|
||||
InitTm(tm);
|
||||
if ( am )
|
||||
{
|
||||
*am = CallStrftime(_T("%p"), &tm);
|
||||
}
|
||||
if ( pm )
|
||||
{
|
||||
tm.tm_hour = 13;
|
||||
*pm = CallStrftime(_T("%p"), &tm);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -616,6 +709,8 @@ wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday, bool abbr)
|
||||
/* static */
|
||||
wxDateTime::Country wxDateTime::GetCountry()
|
||||
{
|
||||
// TODO use LOCALE_ICOUNTRY setting under Win32
|
||||
|
||||
if ( ms_country == Country_Unknown )
|
||||
{
|
||||
// try to guess from the time zone name
|
||||
@ -1397,17 +1492,9 @@ bool wxDateTime::SetToWeekDay(WeekDay weekday,
|
||||
|
||||
wxDateTime::wxDateTime_t wxDateTime::GetDayOfYear(const TimeZone& tz) const
|
||||
{
|
||||
// this array contains the cumulated number of days in all previous months
|
||||
// for normal and leap years
|
||||
static const wxDateTime_t cumulatedDays[2][MONTHS_IN_YEAR] =
|
||||
{
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
|
||||
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
|
||||
};
|
||||
|
||||
Tm tm(GetTm(tz));
|
||||
|
||||
return cumulatedDays[IsLeapYear(tm.year)][tm.mon] + tm.mday;
|
||||
return gs_cumulatedDays[IsLeapYear(tm.year)][tm.mon] + tm.mday;
|
||||
}
|
||||
|
||||
wxDateTime::wxDateTime_t wxDateTime::GetWeekOfYear(const TimeZone& tz) const
|
||||
@ -1455,6 +1542,29 @@ wxDateTime::wxDateTime_t wxDateTime::GetWeekOfMonth(const TimeZone& tz) const
|
||||
return nWeek;
|
||||
}
|
||||
|
||||
wxDateTime& wxDateTime::SetToYearDay(wxDateTime::wxDateTime_t yday)
|
||||
{
|
||||
int year = GetYear();
|
||||
wxCHECK_MSG( (0 < yday) && (yday < GetNumberOfDays(year)),
|
||||
ms_InvDateTime, _T("invalid year day") );
|
||||
|
||||
bool isLeap = IsLeapYear(year);
|
||||
for ( Month mon = Jan; mon < Inv_Month; wxNextMonth(mon) )
|
||||
{
|
||||
// for Dec, we can't compare with gs_cumulatedDays[mon + 1], but we
|
||||
// don't need it neither - because of the CHECK above we know that
|
||||
// yday lies in December then
|
||||
if ( (mon == Dec) || (yday < gs_cumulatedDays[isLeap][mon + 1]) )
|
||||
{
|
||||
Set(yday - gs_cumulatedDays[isLeap][mon], mon, year);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Julian day number conversion and related stuff
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -1624,13 +1734,14 @@ restart:
|
||||
case _T('a'): // a weekday name
|
||||
case _T('A'):
|
||||
// second parameter should be TRUE for abbreviated names
|
||||
res += GetWeekDayName(tm.GetWeekDay(), *p == _T('a'));
|
||||
res += GetWeekDayName(tm.GetWeekDay(),
|
||||
*p == _T('a') ? Name_Abbr : Name_Full);
|
||||
break;
|
||||
|
||||
case _T('b'): // a month name
|
||||
case _T('B'):
|
||||
// second parameter should be TRUE for abbreviated names
|
||||
res += GetMonthName(tm.mon, *p == _T('b'));
|
||||
res += GetMonthName(tm.mon,
|
||||
*p == _T('b') ? Name_Abbr : Name_Full);
|
||||
break;
|
||||
|
||||
case _T('c'): // locale default date and time representation
|
||||
@ -1734,6 +1845,7 @@ restart:
|
||||
// corresponding to Feb 29 of a non leap year (which
|
||||
// may happen if yearReal was leap and year is not)
|
||||
struct tm tmAdjusted;
|
||||
InitTm(tmAdjusted);
|
||||
tmAdjusted.tm_hour = tm.hour;
|
||||
tmAdjusted.tm_min = tm.min;
|
||||
tmAdjusted.tm_sec = tm.sec;
|
||||
@ -1863,7 +1975,7 @@ restart:
|
||||
res += *p;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
case 0: // the end of string
|
||||
wxFAIL_MSG(_T("missing format at the end of string"));
|
||||
|
||||
// just put the '%' which was the last char in format
|
||||
@ -2170,23 +2282,520 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
|
||||
return p;
|
||||
}
|
||||
|
||||
const wxChar *wxDateTime::ParseFormat(const wxChar *date, const wxChar *format)
|
||||
const wxChar *wxDateTime::ParseFormat(const wxChar *date,
|
||||
const wxChar *format,
|
||||
const wxDateTime& dateDef)
|
||||
{
|
||||
wxCHECK_MSG( date && format, (wxChar *)NULL,
|
||||
_T("NULL pointer in wxDateTime::Parse") );
|
||||
_T("NULL pointer in wxDateTime::ParseFormat()") );
|
||||
|
||||
// there is a public domain version of getdate.y, but it only works for
|
||||
// English...
|
||||
wxFAIL_MSG(_T("TODO"));
|
||||
wxString str;
|
||||
unsigned long num;
|
||||
|
||||
return (wxChar *)NULL;
|
||||
// what fields have we found?
|
||||
bool haveWDay = FALSE,
|
||||
haveYDay = FALSE,
|
||||
haveDay = FALSE,
|
||||
haveMon = FALSE,
|
||||
haveYear = FALSE,
|
||||
haveHour = FALSE,
|
||||
haveMin = FALSE,
|
||||
haveSec = FALSE;
|
||||
|
||||
bool hourIsIn12hFormat = FALSE, // or in 24h one?
|
||||
isPM = FALSE; // AM by default
|
||||
|
||||
// and the value of the items we have (init them to get rid of warnings)
|
||||
wxDateTime_t sec = 0,
|
||||
min = 0,
|
||||
hour = 0;
|
||||
WeekDay wday = Inv_WeekDay;
|
||||
wxDateTime_t yday = 0,
|
||||
mday = 0;
|
||||
wxDateTime::Month mon = Inv_Month;
|
||||
int year = 0;
|
||||
|
||||
const wxChar *input = date;
|
||||
for ( const wxChar *fmt = format; *fmt; fmt++ )
|
||||
{
|
||||
if ( *fmt != _T('%') )
|
||||
{
|
||||
if ( wxIsspace(*fmt) )
|
||||
{
|
||||
// a white space in the format string matches 0 or more white
|
||||
// spaces in the input
|
||||
while ( wxIsspace(*input) )
|
||||
{
|
||||
input++;
|
||||
}
|
||||
}
|
||||
else // !space
|
||||
{
|
||||
// any other character (not whitespace, not '%') must be
|
||||
// matched by itself in the input
|
||||
if ( *input++ != *fmt )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// done with this format char
|
||||
continue;
|
||||
}
|
||||
|
||||
// start of a format specification
|
||||
switch ( *++fmt )
|
||||
{
|
||||
case _T('a'): // a weekday name
|
||||
case _T('A'):
|
||||
{
|
||||
int flag = *fmt == _T('a') ? Name_Abbr : Name_Full;
|
||||
wday = GetWeekDayFromName(GetAlphaToken(input), flag);
|
||||
if ( wday == Inv_WeekDay )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
}
|
||||
haveWDay = TRUE;
|
||||
break;
|
||||
|
||||
case _T('b'): // a month name
|
||||
case _T('B'):
|
||||
{
|
||||
int flag = *fmt == _T('b') ? Name_Abbr : Name_Full;
|
||||
mon = GetMonthFromName(GetAlphaToken(input), flag);
|
||||
if ( mon == Inv_Month )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
}
|
||||
haveMon = TRUE;
|
||||
break;
|
||||
|
||||
case _T('c'): // locale default date and time representation
|
||||
{
|
||||
wxDateTime dt;
|
||||
|
||||
// this is the format which corresponds to ctime() output
|
||||
// and strptime("%c") should parse it, so try it first
|
||||
static const wxChar *fmtCtime = _T("%a %b %e %H:%M:%S %Y");
|
||||
|
||||
const wxChar *result = dt.ParseFormat(input, fmtCtime);
|
||||
if ( !result )
|
||||
{
|
||||
result = dt.ParseFormat(input, _T("%x %X"));
|
||||
}
|
||||
|
||||
if ( !result )
|
||||
{
|
||||
result = dt.ParseFormat(input, _T("%X %x"));
|
||||
}
|
||||
|
||||
if ( !result )
|
||||
{
|
||||
// we've tried everything and still no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
input = result;
|
||||
}
|
||||
break;
|
||||
|
||||
case _T('d'): // day of a month (01-31)
|
||||
if ( !GetNumericToken(input, &num) || (num > 31) )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
// we can't check whether the day range is correct yet, will
|
||||
// do it later - assume ok for now
|
||||
haveDay = TRUE;
|
||||
mday = (wxDateTime_t)num;
|
||||
break;
|
||||
|
||||
case _T('H'): // hour in 24h format (00-23)
|
||||
if ( !GetNumericToken(input, &num) || (num > 23) )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
haveHour = TRUE;
|
||||
hour = (wxDateTime_t)num;
|
||||
break;
|
||||
|
||||
case _T('I'): // hour in 12h format (01-12)
|
||||
if ( !GetNumericToken(input, &num) || !num || (num > 12) )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
haveHour = TRUE;
|
||||
hourIsIn12hFormat = TRUE;
|
||||
hour = num % 12; // 12 should be 0
|
||||
break;
|
||||
|
||||
case _T('j'): // day of the year
|
||||
if ( !GetNumericToken(input, &num) || !num || (num > 366) )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
haveYDay = TRUE;
|
||||
yday = (wxDateTime_t)num;
|
||||
break;
|
||||
|
||||
case _T('m'): // month as a number (01-12)
|
||||
if ( !GetNumericToken(input, &num) || !num || (num > 12) )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
haveMon = TRUE;
|
||||
mon = (Month)num;
|
||||
break;
|
||||
|
||||
case _T('M'): // minute as a decimal number (00-59)
|
||||
if ( !GetNumericToken(input, &num) || (num > 59) )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
haveMin = TRUE;
|
||||
min = (wxDateTime_t)num;
|
||||
break;
|
||||
|
||||
case _T('p'): // AM or PM string
|
||||
{
|
||||
wxString am, pm, token = GetAlphaToken(input);
|
||||
|
||||
GetAmPmStrings(&am, &pm);
|
||||
if ( token.CmpNoCase(pm) == 0 )
|
||||
{
|
||||
isPM = TRUE;
|
||||
}
|
||||
else if ( token.CmpNoCase(am) != 0 )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case _T('r'): // time as %I:%M:%S %p
|
||||
{
|
||||
wxDateTime dt;
|
||||
input = dt.ParseFormat(input, _T("%I:%M:%S %p"));
|
||||
if ( !input )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
haveHour = haveMin = haveSec = TRUE;
|
||||
|
||||
Tm tm = dt.GetTm();
|
||||
hour = tm.hour;
|
||||
min = tm.min;
|
||||
sec = tm.sec;
|
||||
}
|
||||
break;
|
||||
|
||||
case _T('R'): // time as %H:%M
|
||||
{
|
||||
wxDateTime dt;
|
||||
input = dt.ParseFormat(input, _T("%H:%M"));
|
||||
if ( !input )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
haveHour = haveMin = TRUE;
|
||||
|
||||
Tm tm = dt.GetTm();
|
||||
hour = tm.hour;
|
||||
min = tm.min;
|
||||
}
|
||||
|
||||
case _T('S'): // second as a decimal number (00-61)
|
||||
if ( !GetNumericToken(input, &num) || (num > 61) )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
haveSec = TRUE;
|
||||
sec = (wxDateTime_t)num;
|
||||
break;
|
||||
|
||||
case _T('T'): // time as %H:%M:%S
|
||||
{
|
||||
wxDateTime dt;
|
||||
input = dt.ParseFormat(input, _T("%H:%M:%S"));
|
||||
if ( !input )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
haveHour = haveMin = haveSec = TRUE;
|
||||
|
||||
Tm tm = dt.GetTm();
|
||||
hour = tm.hour;
|
||||
min = tm.min;
|
||||
sec = tm.sec;
|
||||
}
|
||||
|
||||
case _T('w'): // weekday as a number (0-6), Sunday = 0
|
||||
if ( !GetNumericToken(input, &num) || (wday > 6) )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
haveWDay = TRUE;
|
||||
wday = (WeekDay)num;
|
||||
break;
|
||||
|
||||
case _T('x'): // locale default date representation
|
||||
#ifdef HAVE_STRPTIME
|
||||
// try using strptime() - it may fail even if the input is
|
||||
// correct but the date is out of range, so we will fall back
|
||||
// to our generic code anyhow (FIXME !Unicode friendly)
|
||||
{
|
||||
struct tm tm;
|
||||
const wxChar *result = strptime(input, "%x", &tm);
|
||||
if ( result )
|
||||
{
|
||||
input = result;
|
||||
|
||||
haveDay = haveMon = haveYear = TRUE;
|
||||
|
||||
year = 1900 + tm.tm_year;
|
||||
mon = (Month)tm.tm_mon;
|
||||
mday = tm.tm_mday;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // HAVE_STRPTIME
|
||||
|
||||
// TODO query the LOCALE_IDATE setting under Win32
|
||||
{
|
||||
wxDateTime dt;
|
||||
|
||||
wxString fmtDate;
|
||||
if ( IsWestEuropeanCountry(GetCountry()) ||
|
||||
GetCountry() == Russia )
|
||||
{
|
||||
fmtDate = _T("%d/%m/%y");
|
||||
}
|
||||
else // assume USA
|
||||
{
|
||||
fmtDate = _T("%m/%d/%y");
|
||||
}
|
||||
|
||||
const wxChar *result = dt.ParseFormat(input, fmtDate);
|
||||
if ( !result )
|
||||
{
|
||||
// bad luck
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
Tm tm = dt.GetTm();
|
||||
|
||||
haveDay = haveMon = haveYear = TRUE;
|
||||
|
||||
year = tm.year;
|
||||
mon = tm.mon;
|
||||
mday = tm.mday;
|
||||
|
||||
input = result;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case _T('X'): // locale default time representation
|
||||
#ifdef HAVE_STRPTIME
|
||||
{
|
||||
// use strptime() to do it for us (FIXME !Unicode friendly)
|
||||
struct tm tm;
|
||||
input = strptime(input, "%X", &tm);
|
||||
if ( !input )
|
||||
{
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
haveHour = haveMin = haveSec = TRUE;
|
||||
|
||||
hour = tm.tm_hour;
|
||||
min = tm.tm_min;
|
||||
sec = tm.tm_sec;
|
||||
}
|
||||
#else // !HAVE_STRPTIME
|
||||
// TODO under Win32 we can query the LOCALE_ITIME system
|
||||
// setting which says whether the default time format is
|
||||
// 24 or 12 hour
|
||||
{
|
||||
// try to parse what follows as "%H:%M:%S" and, if this
|
||||
// fails, as "%I:%M:%S %p" - this should catch the most
|
||||
// common cases
|
||||
wxDateTime dt;
|
||||
|
||||
const wxChar *result = dt.ParseFormat(input, _T("%T"));
|
||||
if ( !result )
|
||||
{
|
||||
result = dt.ParseFormat(input, _T("%r"));
|
||||
}
|
||||
|
||||
if ( !result )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
haveHour = haveMin = haveSec = TRUE;
|
||||
|
||||
Tm tm = dt.GetTm();
|
||||
hour = tm.hour;
|
||||
min = tm.min;
|
||||
sec = tm.sec;
|
||||
|
||||
input = result;
|
||||
}
|
||||
#endif // HAVE_STRPTIME/!HAVE_STRPTIME
|
||||
break;
|
||||
|
||||
case _T('y'): // year without century (00-99)
|
||||
if ( !GetNumericToken(input, &num) || (num > 99) )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
haveYear = TRUE;
|
||||
year = 1900 + num;
|
||||
break;
|
||||
|
||||
case _T('Y'): // year with century
|
||||
if ( !GetNumericToken(input, &num) || !num || (num > 366) )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
|
||||
haveYDay = TRUE;
|
||||
yday = (wxDateTime_t)num;
|
||||
break;
|
||||
|
||||
case _T('Z'): // timezone name
|
||||
wxFAIL_MSG(_T("TODO"));
|
||||
break;
|
||||
|
||||
case _T('%'): // a percent sign
|
||||
if ( *input++ != _T('%') )
|
||||
{
|
||||
// no match
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0: // the end of string
|
||||
wxFAIL_MSG(_T("unexpected format end"));
|
||||
|
||||
// fall through
|
||||
|
||||
default: // not a known format spec
|
||||
return (wxChar *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// format matched, try to construct a date from what we have now
|
||||
Tm tmDef;
|
||||
if ( dateDef.IsValid() )
|
||||
{
|
||||
// take this date as default
|
||||
tmDef = dateDef.GetTm();
|
||||
}
|
||||
else if ( IsValid() )
|
||||
{
|
||||
// if this date is valid, don't change it
|
||||
tmDef = GetTm();
|
||||
}
|
||||
else
|
||||
{
|
||||
// no default and this date is invalid - fall back to Today()
|
||||
tmDef = Today().GetTm();
|
||||
}
|
||||
|
||||
Tm tm = tmDef;
|
||||
|
||||
// set the date
|
||||
if ( haveYear )
|
||||
{
|
||||
tm.year = year;
|
||||
}
|
||||
|
||||
// TODO we don't check here that the values are consistent, if both year
|
||||
// day and month/day were found, we just ignore the year day and we
|
||||
// also always ignore the week day
|
||||
if ( haveMon && haveDay )
|
||||
{
|
||||
tm.mon = mon;
|
||||
tm.mday = mday;
|
||||
}
|
||||
else if ( haveYDay )
|
||||
{
|
||||
Tm tm2 = wxDateTime(1, Jan, tm.year).SetToYearDay(yday).GetTm();
|
||||
|
||||
tm.mon = tm2.mon;
|
||||
tm.mday = tm2.mday;
|
||||
}
|
||||
|
||||
// deal with AM/PM
|
||||
if ( haveHour && hourIsIn12hFormat && isPM )
|
||||
{
|
||||
// translate to 24hour format
|
||||
hour += 12;
|
||||
}
|
||||
//else: either already in 24h format or no translation needed
|
||||
|
||||
// set the time
|
||||
if ( haveHour )
|
||||
{
|
||||
tm.hour = hour;
|
||||
}
|
||||
|
||||
if ( haveMin )
|
||||
{
|
||||
tm.min = min;
|
||||
}
|
||||
|
||||
if ( haveSec )
|
||||
{
|
||||
tm.sec = sec;
|
||||
}
|
||||
|
||||
Set(tm);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
const wxChar *wxDateTime::ParseDateTime(const wxChar *date)
|
||||
{
|
||||
wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") );
|
||||
|
||||
// find a public domain version of strptime() somewhere?
|
||||
// there is a public domain version of getdate.y, but it only works for
|
||||
// English...
|
||||
wxFAIL_MSG(_T("TODO"));
|
||||
|
||||
return (wxChar *)NULL;
|
||||
@ -2349,7 +2958,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
|
||||
}
|
||||
else // not a number
|
||||
{
|
||||
mon = GetMonthFromName(token);
|
||||
mon = GetMonthFromName(token, Name_Full | Name_Abbr);
|
||||
if ( mon != Inv_Month )
|
||||
{
|
||||
// it's a month
|
||||
@ -2362,7 +2971,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
|
||||
}
|
||||
else
|
||||
{
|
||||
wday = GetWeekDayFromName(token);
|
||||
wday = GetWeekDayFromName(token, Name_Full | Name_Abbr);
|
||||
if ( wday != Inv_WeekDay )
|
||||
{
|
||||
// a week day
|
||||
@ -2491,11 +3100,71 @@ const wxChar *wxDateTime::ParseTime(const wxChar *time)
|
||||
{
|
||||
wxCHECK_MSG( time, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") );
|
||||
|
||||
// this function should be able to parse different time formats as well as
|
||||
// timezones (take the code out from ParseRfc822Date()) and AM/PM.
|
||||
wxFAIL_MSG(_T("TODO"));
|
||||
// first try some extra things
|
||||
static const struct
|
||||
{
|
||||
const wxChar *name;
|
||||
wxDateTime_t hour;
|
||||
} stdTimes[] =
|
||||
{
|
||||
{ wxTRANSLATE("noon"), 12 },
|
||||
{ wxTRANSLATE("midnight"), 00 },
|
||||
// anything else?
|
||||
};
|
||||
|
||||
return (wxChar *)NULL;
|
||||
for ( size_t n = 0; n < WXSIZEOF(stdTimes); n++ )
|
||||
{
|
||||
wxString timeString = wxGetTranslation(stdTimes[n].name);
|
||||
size_t len = timeString.length();
|
||||
if ( timeString.CmpNoCase(wxString(time, len)) == 0 )
|
||||
{
|
||||
Set(stdTimes[n].hour, 0, 0);
|
||||
|
||||
return time + len;
|
||||
}
|
||||
}
|
||||
|
||||
// try all time formats we may think about starting with the standard one
|
||||
const wxChar *result = ParseFormat(time, _T("%X"));
|
||||
if ( !result )
|
||||
{
|
||||
// normally, it's the same, but why not try it?
|
||||
result = ParseFormat(time, _T("%H:%M:%S"));
|
||||
}
|
||||
|
||||
if ( !result )
|
||||
{
|
||||
// 12hour with AM/PM?
|
||||
result = ParseFormat(time, _T("%I:%M:%S %p"));
|
||||
}
|
||||
|
||||
if ( !result )
|
||||
{
|
||||
// without seconds?
|
||||
result = ParseFormat(time, _T("%H:%M"));
|
||||
}
|
||||
|
||||
if ( !result )
|
||||
{
|
||||
// 12hour with AM/PM but without seconds?
|
||||
result = ParseFormat(time, _T("%I:%M %p"));
|
||||
}
|
||||
|
||||
if ( !result )
|
||||
{
|
||||
// just the hour?
|
||||
result = ParseFormat(time, _T("%H"));
|
||||
}
|
||||
|
||||
if ( !result )
|
||||
{
|
||||
// just the hour and AM/PM?
|
||||
result = ParseFormat(time, _T("%I %p"));
|
||||
}
|
||||
|
||||
// TODO: parse timezones
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
Loading…
Reference in New Issue
Block a user