- Simplified and debugged ISO8601::resolve method regarding UTC, local and
  specified time offsets.
This commit is contained in:
Paul Beckingham
2014-03-14 23:48:56 -04:00
parent f05b01f9fa
commit 122cc2f56d

View File

@@ -603,6 +603,8 @@ bool ISO8601d::validate ()
// long tm_gmtoff; offset from UTC in seconds // long tm_gmtoff; offset from UTC in seconds
void ISO8601d::resolve () void ISO8601d::resolve ()
{ {
//std::cout << "# start ------------------------\n";
// Don't touch the original values. // Don't touch the original values.
int year = _year; int year = _year;
int month = _month; int month = _month;
@@ -613,55 +615,69 @@ void ISO8601d::resolve ()
int seconds = _seconds; int seconds = _seconds;
int offset = _offset; int offset = _offset;
bool utc = _utc; bool utc = _utc;
//std::cout << "# input\n"
// << "# year=" << year << "\n"
// << "# month=" << month << "\n"
// << "# week=" << week << "\n"
// << "# weekday=" << weekday << "\n"
// << "# julian=" << julian << "\n"
// << "# day=" << day << "\n"
// << "# seconds=" << seconds << "\n"
// << "# offset=" << offset << "\n"
// << "# utc=" << utc << "\n";
struct tm t = {0}; // Get current time.
// Requests that mktime determine summer time effect.
t.tm_isdst = -1;
// Determine local time.
time_t now = time (NULL); time_t now = time (NULL);
struct tm* local_now = localtime (&now); //std::cout << "# now=" << now << "\n";
struct tm* utc_now = gmtime (&now);
// What is a complete TZ? // A UTC offset needs to be accommodated. Once the offset is subtracted,
// utc // only local and UTC times remain.
// offset if (offset)
// local (get default)
if (utc)
offset = 0;
else if (! offset)
{ {
#ifdef HAVE_TM_GMTOFF seconds -= offset;
offset = local_now->tm_gmtoff - (local_now->tm_isdst == 1 ? 3600 : 0); now -= offset;
#else utc = true;
// TODO Umm...
#endif
} }
// Subtract the offset, to project local to UTC. // Get 'now' in the relevant location.
seconds -= offset; struct tm* t_now = utc ? gmtime (&now) : localtime (&now);
//std::cout << "# t_now\n"
// << "# tm_year=" << t_now->tm_year << "\n"
// << "# tm_mon=" << t_now->tm_mon << "\n"
// << "# tm_mday=" << t_now->tm_mday << "\n"
// << "# tm_hour=" << t_now->tm_hour << "\n"
// << "# tm_min=" << t_now->tm_min << "\n"
// << "# tm_sec=" << t_now->tm_sec << "\n"
// << "# tm_isdst=" << t_now->tm_isdst << "\n";
// If the time is specified without a date, if it is earlier than 'now', then int seconds_now = (t_now->tm_hour * 3600) +
// it refers to tomorrow. (t_now->tm_min * 60) +
int seconds_utc_now = utc_now->tm_hour * 3600 + t_now->tm_sec;
utc_now->tm_min * 60 + //std::cout << "# seconds_now=" << seconds_now << "\n";
utc_now->tm_sec;
// Project forward one day if the specified seconds are earlier in the day
// than the current seconds.
if (year == 0 && if (year == 0 &&
month == 0 && month == 0 &&
day == 0 && day == 0 &&
week == 0 && week == 0 &&
weekday == 0 && weekday == 0 &&
seconds < seconds_utc_now) seconds < seconds_now)
{ {
//std::cout << "# earlier today, therefore seconds += 86400\n"
// << "# seconds=" << seconds << "\n";
seconds += 86400; seconds += 86400;
} }
// Conversion of week + weekday to julian. // Convert week + weekday --> julian.
if (week) if (week)
{ {
julian = (week * 7) + weekday - dayOfWeek (year, 1, 4) - 3; julian = (week * 7) + weekday - dayOfWeek (year, 1, 4) - 3;
//std::cout << "# week=" << week << " weekday=" << weekday << " specified\n"
// << "# julian=" << julian << "\n";
} }
// Provide default values for year, month, day.
else else
{ {
// Default values for year, month, day: // Default values for year, month, day:
@@ -673,9 +689,9 @@ void ISO8601d::resolve ()
// //
if (year == 0) if (year == 0)
{ {
year = local_now->tm_year + 1900; year = t_now->tm_year + 1900;
month = local_now->tm_mon + 1; month = t_now->tm_mon + 1;
day = local_now->tm_mday; day = t_now->tm_mday;
} }
else else
{ {
@@ -688,43 +704,75 @@ void ISO8601d::resolve ()
day = 1; day = 1;
} }
} }
//std::cout << "# Applied default y m d\n"
// << "# year=" << year << "\n"
// << "# month=" << month << "\n"
// << "# day=" << day << "\n";
if (julian) if (julian)
{ {
month = 1; month = 1;
day = julian; day = julian;
//std::cout << "# julian=" << julian << " specified\n"
// << "# month=" << month << "\n"
// << "# day=" << day << "\n";
} }
struct tm t = {0};
t.tm_isdst = -1; // Requests that mktime/gmtime determine summer time effect.
t.tm_year = year - 1900; t.tm_year = year - 1900;
t.tm_mon = month - 1; t.tm_mon = month - 1;
t.tm_mday = day; t.tm_mday = day;
// What is a complete time spec? if (seconds > 86400)
// seconds
if (seconds)
{ {
if (seconds > 86400) //std::cout << "# seconds=" << seconds << " is more than a day\n";
{ int days = seconds / 86400;
int days = seconds / 86400; t.tm_mday += days;
t.tm_mday += days; seconds %= 86400;
seconds -= days * 86400; //std::cout << "# t.tm_mday=" << t.tm_mday << "\n"
} // << "# seconds=" << seconds << "\n";
}
t.tm_hour = seconds / 3600; t.tm_hour = seconds / 3600;
t.tm_min = (seconds % 3600) / 60; t.tm_min = (seconds % 3600) / 60;
t.tm_sec = seconds % 60; t.tm_sec = seconds % 60;
}
else
{
// User-provided default.
t.tm_hour = _default_seconds / 3600;
t.tm_min = (_default_seconds % 3600) / 60;
t.tm_sec = _default_seconds % 60;
}
_value = timegm (&t); //std::cout << "# Final t\n"
// << "# tm_year=" << t.tm_year << "\n"
// << "# tm_mon=" << t.tm_mon << "\n"
// << "# tm_mday=" << t.tm_mday << "\n"
// << "# tm_hour=" << t.tm_hour << "\n"
// << "# tm_min=" << t.tm_min << "\n"
// << "# tm_sec=" << t.tm_sec << "\n"
// << "# tm_isdst=" << t.tm_isdst << "\n";
_value = utc ? timegm (&t) : timelocal (&t);
//std::cout << "# _value " << _value << "\n";
//std::cout << "# end --------------------------\n";
//dump ();
} }
////////////////////////////////////////////////////////////////////////////////
/*
void ISO8601d::dump ()
{
std::cout << "# Y=" << _year
<< " M=" << _month
<< " W=" << _week
<< " WD=" << _weekday
<< " J=" << _julian
<< " d=" << _day
<< " s=" << _seconds
<< " o=" << _offset
<< " Z=" << _utc
<< " ambi=" << _ambiguity
<< " --> " << _value
<< "\n";
}
*/
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
ISO8601p::ISO8601p () ISO8601p::ISO8601p ()
{ {