Refactor time zone parsing into a separate function from ParseRfc822Date()

For now, the new function is private and undocumented.
This commit is contained in:
Lauri Nurmi 2022-03-09 18:03:02 +02:00
parent 770cf26afe
commit 136b1713e1
2 changed files with 108 additions and 93 deletions

View File

@ -1150,6 +1150,10 @@ private:
// assign the preferred first day of a week to flags, if necessary
void UseEffectiveWeekDayFlags(WeekFlags &flags) const;
// parse time zone (e.g. "+0100") between [iterator,dateEnd)
bool ParseRFC822TimeZone(wxString::const_iterator* iterator,
const wxString::const_iterator& dateEnd);
// the internal representation of the time is the amount of milliseconds
// elapsed since the origin which is set by convention to the UNIX/C epoch
// value: the midnight of January 1, 1970 (UTC)

View File

@ -736,6 +736,106 @@ wxString wxDateTime::Format(const wxString& formatp, const TimeZone& tz) const
return res;
}
bool
wxDateTime::ParseRFC822TimeZone(wxString::const_iterator *iterator,
const wxString::const_iterator &pEnd)
{
wxString::const_iterator& p = *iterator;
int offset = 0; // just to suppress warnings
if ( *p == '-' || *p == '+' )
{
// the explicit offset given: it has the form of hhmm
bool plus = *p++ == '+';
if ( p == pEnd || !wxIsdigit(*p) ||
p + 1 == pEnd || !wxIsdigit(*(p + 1)) )
return false;
// hours
offset = MIN_PER_HOUR*(10*(*p - '0') + (*(p + 1) - '0'));
p += 2;
if ( p == pEnd || !wxIsdigit(*p) ||
p + 1 == pEnd || !wxIsdigit(*(p + 1)) )
return false;
// minutes
offset += 10*(*p - '0') + (*(p + 1) - '0');
if ( !plus )
offset = -offset;
p += 2;
}
else // not numeric
{
// the symbolic timezone given: may be either military timezone or one
// of standard abbreviations
if ( p + 1 == pEnd )
{
// military: Z = UTC, J unused, A = -1, ..., Y = +12
static const int offsets[26] =
{
//A B C D E F G H I J K L M
-1, -2, -3, -4, -5, -6, -7, -8, -9, 0, -10, -11, -12,
//N O P R Q S T U V W Z Y Z
+1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, 0
};
if ( *p < wxT('A') || *p > wxT('Z') || *p == wxT('J') )
return false;
offset = offsets[*p++ - 'A'];
}
else
{
// abbreviation
const wxString tz(p, pEnd);
if ( tz == wxT("UT") || tz == wxT("UTC") || tz == wxT("GMT") )
offset = 0;
else if ( tz == wxT("AST") )
offset = AST - GMT0;
else if ( tz == wxT("ADT") )
offset = ADT - GMT0;
else if ( tz == wxT("EST") )
offset = EST - GMT0;
else if ( tz == wxT("EDT") )
offset = EDT - GMT0;
else if ( tz == wxT("CST") )
offset = CST - GMT0;
else if ( tz == wxT("CDT") )
offset = CDT - GMT0;
else if ( tz == wxT("MST") )
offset = MST - GMT0;
else if ( tz == wxT("MDT") )
offset = MDT - GMT0;
else if ( tz == wxT("PST") )
offset = PST - GMT0;
else if ( tz == wxT("PDT") )
offset = PDT - GMT0;
else
return false;
p += tz.length();
}
// make it minutes
offset *= MIN_PER_HOUR;
}
// As always, dealing with the time zone is the most interesting part: we
// can't just use MakeFromTimeZone() here because it wouldn't handle the
// DST correctly because the TZ specified in the string is DST-invariant
// and so we have to manually shift to the UTC first and then convert to
// the local TZ.
*this -= wxTimeSpan::Minutes(offset);
MakeFromUTC();
return true;
}
// this function parses a string in (strict) RFC 822 format: see the section 5
// of the RFC for the detailed description, but briefly it's something of the
// form "Sat, 18 Dec 1999 00:48:30 +0100"
@ -889,102 +989,13 @@ wxDateTime::ParseRfc822Date(const wxString& originalDate, wxString::const_iterat
if ( *p++ != ' ' )
return false;
// 7. now the interesting part: the timezone
int offset = 0; // just to suppress warnings
if ( *p == '-' || *p == '+' )
{
// the explicit offset given: it has the form of hhmm
bool plus = *p++ == '+';
if ( p == pEnd || !wxIsdigit(*p) ||
p + 1 == pEnd || !wxIsdigit(*(p + 1)) )
return false;
// hours
offset = MIN_PER_HOUR*(10*(*p - '0') + (*(p + 1) - '0'));
p += 2;
if ( p == pEnd || !wxIsdigit(*p) ||
p + 1 == pEnd || !wxIsdigit(*(p + 1)) )
return false;
// minutes
offset += 10*(*p - '0') + (*(p + 1) - '0');
if ( !plus )
offset = -offset;
p += 2;
}
else // not numeric
{
// the symbolic timezone given: may be either military timezone or one
// of standard abbreviations
if ( p + 1 == pEnd )
{
// military: Z = UTC, J unused, A = -1, ..., Y = +12
static const int offsets[26] =
{
//A B C D E F G H I J K L M
-1, -2, -3, -4, -5, -6, -7, -8, -9, 0, -10, -11, -12,
//N O P R Q S T U V W Z Y Z
+1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, 0
};
if ( *p < wxT('A') || *p > wxT('Z') || *p == wxT('J') )
return false;
offset = offsets[*p++ - 'A'];
}
else
{
// abbreviation
const wxString tz(p, pEnd);
if ( tz == wxT("UT") || tz == wxT("UTC") || tz == wxT("GMT") )
offset = 0;
else if ( tz == wxT("AST") )
offset = AST - GMT0;
else if ( tz == wxT("ADT") )
offset = ADT - GMT0;
else if ( tz == wxT("EST") )
offset = EST - GMT0;
else if ( tz == wxT("EDT") )
offset = EDT - GMT0;
else if ( tz == wxT("CST") )
offset = CST - GMT0;
else if ( tz == wxT("CDT") )
offset = CDT - GMT0;
else if ( tz == wxT("MST") )
offset = MST - GMT0;
else if ( tz == wxT("MDT") )
offset = MDT - GMT0;
else if ( tz == wxT("PST") )
offset = PST - GMT0;
else if ( tz == wxT("PDT") )
offset = PDT - GMT0;
else
return false;
p += tz.length();
}
// make it minutes
offset *= MIN_PER_HOUR;
}
// the spec was correct, construct the date from the values we found
Set(day, mon, year, hour, min, sec);
// As always, dealing with the time zone is the most interesting part: we
// can't just use MakeFromTimeZone() here because it wouldn't handle the
// DST correctly because the TZ specified in the string is DST-invariant
// and so we have to manually shift to the UTC first and then convert to
// the local TZ.
*this -= wxTimeSpan::Minutes(offset);
MakeFromUTC();
// 7. now the interesting part: the timezone
if ( !ParseRFC822TimeZone(&p, pEnd) )
return false;
if ( end )
*end = originalDate.begin() + (p - date.begin());