LocalTime::LocalTime (string s)
{
- /* 2013-01-05T18:06:59 or 2013-01-05T18:06:59.123 or 2013-01-05T18:06:59+04:00 or 2013-01-05T18:06:59.123+04:00 */
- /* 0123456789012345678 or 01234567890123456789012 or 0123456789012345678901234 or 01234567890123456789012345678 */
+ /* 2013-01-05T18:06:59[.frac][TZ]
+ * Where .frac is fractional seconds
+ * TZ is something like +04:00
+ */
if (s.length() < 19) {
throw TimeFormatError (s);
}
- bool with_millisecond = false;
- bool with_tz = false;
-
- switch (s.length ()) {
- case 19:
- break;
- case 23:
- with_millisecond = true;
- break;
- case 25:
- with_tz = true;
- break;
- case 29:
- with_millisecond = with_tz = true;
- break;
- default:
- throw TimeFormatError (s);
- }
-
- int const tz_pos = with_millisecond ? 23 : 19;
+ /* Date and time with whole seconds */
- /* Check incidental characters */
if (s[4] != '-' || s[7] != '-' || s[10] != 'T' || s[13] != ':' || s[16] != ':') {
- throw TimeFormatError (s);
- }
- if (with_millisecond && s[19] != '.') {
- throw TimeFormatError (s);
- }
- if (with_tz && s[tz_pos] != '+' && s[tz_pos] != '-') {
- throw TimeFormatError (s);
+ throw TimeFormatError(s);
}
_year = lexical_cast<int>(s.substr(0, 4));
_hour = lexical_cast<int>(s.substr(11, 2));
_minute = lexical_cast<int>(s.substr(14, 2));
_second = lexical_cast<int>(s.substr(17, 2));
- _millisecond = with_millisecond ? lexical_cast<int>(s.substr(20, 3)) : 0;
- _offset.set_hour(with_tz ? lexical_cast<int>(s.substr(tz_pos + 1, 2)) : 0);
- _offset.set_minute(with_tz ? lexical_cast<int>(s.substr(tz_pos + 4, 2)) : 0);
+ size_t pos = 19;
+
+ /* Fractional seconds */
+ if (s.length() > pos && s[pos] == '.') {
+ auto end = s.find('+', pos);
+ if (end == std::string::npos) {
+ end = s.find('-', pos);
+ }
+ if (end == std::string::npos) {
+ end = s.length();
+ }
+ auto const length = end - pos;
+ _millisecond = lexical_cast<int>(s.substr(pos + 1, std::min(static_cast<size_t>(3), length - 1)));
+ pos = end;
+ } else {
+ _millisecond = 0;
+ }
- if (with_tz && s[tz_pos] == '-') {
- _offset.set_hour(-_offset.hour());
- _offset.set_minute(-_offset.minute());
+ /* Timezone */
+ if (pos != s.length() && s[pos] != 'Z') {
+ if (s[pos] != '+' && s[pos] != '-') {
+ throw TimeFormatError(s);
+ }
+ if ((s.length() - pos) != 6) {
+ throw TimeFormatError(s);
+ }
+
+ _offset.set_hour(lexical_cast<int>(s.substr(pos + 1, 2)));
+ _offset.set_minute(lexical_cast<int>(s.substr(pos + 4, 2)));
+
+ if (s[pos] == '-') {
+ _offset.set_hour(-_offset.hour());
+ _offset.set_minute(-_offset.minute());
+ }
}
}
string
-LocalTime::as_string (bool with_millisecond) const
+LocalTime::as_string(bool with_millisecond, bool with_timezone) const
{
char buffer[32];
- snprintf (
+
+ auto const written = snprintf(
buffer, sizeof (buffer),
- "%sT%s%s%02d:%02d",
- date().c_str(), time_of_day(true, with_millisecond).c_str(), (_offset.hour() >= 0 ? "+" : "-"), abs(_offset.hour()), abs(_offset.minute())
+ "%sT%s",
+ date().c_str(), time_of_day(true, with_millisecond).c_str()
);
+
+ DCP_ASSERT(written < 32);
+
+ if (with_timezone) {
+ snprintf(
+ buffer + written, sizeof(buffer) - written,
+ "%s%02d:%02d", (_offset.hour() >= 0 ? "+" : "-"), abs(_offset.hour()), abs(_offset.minute())
+ );
+ }
return buffer;
}
bool
LocalTime::operator== (LocalTime const & other) const
{
- return _year == other._year && _month == other._month && _day == other._day &&
- _hour == other._hour && _second == other._second && _millisecond == other._millisecond &&
- _offset == other._offset;
+ auto a = as_utc();
+ auto b = other.as_utc();
+
+ return a.year() == b.year() && a.month() == b.month() && a.day() == b.day() &&
+ a.hour() == b.hour() && a.minute() == b.minute() && a.second() == b.second() && a.millisecond() == b.millisecond();
}
bool
LocalTime::operator< (LocalTime const & other) const
{
- DCP_ASSERT(_offset == other._offset);
+ auto a = as_utc();
+ auto b = other.as_utc();
- if (_year != other._year) {
- return _year < other._year;
+ if (a.year() != b.year()) {
+ return a.year() < b.year();
}
- if (_month != other._month) {
- return _month < other._month;
+ if (a.month() != b.month()) {
+ return a.month() < b.month();
}
- if (_day != other._day) {
- return _day < other._day;
+ if (a.day() != b.day()) {
+ return a.day() < b.day();
}
- if (_hour != other._hour) {
- return _hour < other._hour;
+ if (a.hour() != b.hour()) {
+ return a.hour() < b.hour();
}
- if (_second != other._second) {
- return _second < other._second;
+ if (a.minute() != b.minute()) {
+ return a.minute() < other.minute();
}
- return _millisecond < other._millisecond;
+ if (a.second() != b.second()) {
+ return a.second() < b.second();
+ }
+ return a.millisecond() < b.millisecond();
}
+bool
+LocalTime::operator<=(LocalTime const& other) const
+{
+ return *this < other || *this == other;
+}
+
+
+
bool
LocalTime::operator>(LocalTime const & other) const
{
- DCP_ASSERT(_offset == other._offset);
+ auto a = as_utc();
+ auto b = other.as_utc();
- if (_year != other._year) {
- return _year > other._year;
+ if (a.year() != b.year()) {
+ return a.year() > b.year();
+ }
+ if (a.month() != b.month()) {
+ return a.month() > b.month();
}
- if (_month != other._month) {
- return _month > other._month;
+ if (a.day() != b.day()) {
+ return a.day() > b.day();
}
- if (_day != other._day) {
- return _day > other._day;
+ if (a.hour() != b.hour()) {
+ return a.hour() > b.hour();
}
- if (_hour != other._hour) {
- return _hour > other._hour;
+ if (a.minute() != b.minute()) {
+ return a.minute() > b.minute();
}
- if (_second != other._second) {
- return _second > other._second;
+ if (a.second() != b.second()) {
+ return a.second() > b.second();
}
- return _millisecond > other._millisecond;
+ return a.millisecond() > b.millisecond();
+}
+
+
+bool
+LocalTime::operator>=(LocalTime const& other) const
+{
+ return *this > other || *this == other;
}
}
+LocalTime
+LocalTime::as_utc() const
+{
+ auto t = *this;
+ t.add(boost::posix_time::time_duration(-_offset.hour(), -_offset.minute(), 0));
+ return t;
+}
+