- 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
void ISO8601d::resolve ()
{
//std::cout << "# start ------------------------\n";
// Don't touch the original values.
int year = _year;
int month = _month;
@@ -613,55 +615,69 @@ void ISO8601d::resolve ()
int seconds = _seconds;
int offset = _offset;
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};
// Requests that mktime determine summer time effect.
t.tm_isdst = -1;
// Determine local time.
// Get current time.
time_t now = time (NULL);
struct tm* local_now = localtime (&now);
struct tm* utc_now = gmtime (&now);
//std::cout << "# now=" << now << "\n";
// What is a complete TZ?
// utc
// offset
// local (get default)
if (utc)
offset = 0;
else if (! offset)
// A UTC offset needs to be accommodated. Once the offset is subtracted,
// only local and UTC times remain.
if (offset)
{
#ifdef HAVE_TM_GMTOFF
offset = local_now->tm_gmtoff - (local_now->tm_isdst == 1 ? 3600 : 0);
#else
// TODO Umm...
#endif
seconds -= offset;
now -= offset;
utc = true;
}
// Subtract the offset, to project local to UTC.
seconds -= offset;
// Get 'now' in the relevant location.
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
// it refers to tomorrow.
int seconds_utc_now = utc_now->tm_hour * 3600 +
utc_now->tm_min * 60 +
utc_now->tm_sec;
int seconds_now = (t_now->tm_hour * 3600) +
(t_now->tm_min * 60) +
t_now->tm_sec;
//std::cout << "# seconds_now=" << seconds_now << "\n";
// Project forward one day if the specified seconds are earlier in the day
// than the current seconds.
if (year == 0 &&
month == 0 &&
day == 0 &&
week == 0 &&
weekday == 0 &&
seconds < seconds_utc_now)
seconds < seconds_now)
{
//std::cout << "# earlier today, therefore seconds += 86400\n"
// << "# seconds=" << seconds << "\n";
seconds += 86400;
}
// Conversion of week + weekday to julian.
// Convert week + weekday --> julian.
if (week)
{
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
{
// Default values for year, month, day:
@@ -673,9 +689,9 @@ void ISO8601d::resolve ()
//
if (year == 0)
{
year = local_now->tm_year + 1900;
month = local_now->tm_mon + 1;
day = local_now->tm_mday;
year = t_now->tm_year + 1900;
month = t_now->tm_mon + 1;
day = t_now->tm_mday;
}
else
{
@@ -688,43 +704,75 @@ void ISO8601d::resolve ()
day = 1;
}
}
//std::cout << "# Applied default y m d\n"
// << "# year=" << year << "\n"
// << "# month=" << month << "\n"
// << "# day=" << day << "\n";
if (julian)
{
month = 1;
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_mon = month - 1;
t.tm_mday = day;
// What is a complete time spec?
// seconds
if (seconds)
if (seconds > 86400)
{
if (seconds > 86400)
{
int days = seconds / 86400;
t.tm_mday += days;
seconds -= days * 86400;
}
//std::cout << "# seconds=" << seconds << " is more than a day\n";
int days = seconds / 86400;
t.tm_mday += days;
seconds %= 86400;
//std::cout << "# t.tm_mday=" << t.tm_mday << "\n"
// << "# seconds=" << seconds << "\n";
}
t.tm_hour = seconds / 3600;
t.tm_min = (seconds % 3600) / 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 ()
{