From: Mikko Rasa Date: Mon, 15 Dec 2008 11:33:48 +0000 (+0000) Subject: Add support for time zones X-Git-Tag: 1.1~8 X-Git-Url: http://git.tdb.fi/?p=libs%2Fcore.git;a=commitdiff_plain;h=3fd9d04e84cdd72aabe8f9878f9e8ff006275bb6 Add support for time zones Fix bugs in DateTime addition operations Add subtraction operators for DateTime --- diff --git a/source/time/datetime.cpp b/source/time/datetime.cpp index 2d7c195..283a7c6 100644 --- a/source/time/datetime.cpp +++ b/source/time/datetime.cpp @@ -1,9 +1,11 @@ /* $Id$ */ +#include #include #include #include "../core/except.h" #include "datetime.h" #include "timestamp.h" +#include "units.h" using namespace std; @@ -43,57 +45,35 @@ inline int cmp_(T a, T b) namespace Msp { namespace Time { -DateTime::DateTime(const TimeStamp &ts): - year(1970), - month(1), - mday(1), - hour(0), - minute(0), - second(0), - usec(0) +DateTime::DateTime(const TimeStamp &ts) { - add_raw(ts.raw()); + init(ts); } -DateTime::DateTime(int y, unsigned char m, unsigned char d): - year(y), - month(m), - mday(d), - hour(0), - minute(0), - second(0), - usec(0) +DateTime::DateTime(const TimeStamp &ts, const TimeZone &tz) { - validate(); + init(ts); + convert_timezone(tz); } -DateTime::DateTime(int y, unsigned char m, unsigned char d, unsigned char h, unsigned char n, unsigned char s): - year(y), - month(m), - mday(d), - hour(h), - minute(n), - second(s), - usec(0) +DateTime::DateTime(int y, unsigned char m, unsigned char d) { - validate(); + init(y, m, d, 0, 0, 0, 0); } -DateTime::DateTime(int y, unsigned char m, unsigned char d, unsigned char h, unsigned char n, unsigned char s, unsigned u): - year(y), - month(m), - mday(d), - hour(h), - minute(n), - second(s), - usec(u) +DateTime::DateTime(int y, unsigned char m, unsigned char d, unsigned char h, unsigned char n, unsigned char s) { - validate(); + init(y, m, d, h, n, s, 0); +} + +DateTime::DateTime(int y, unsigned char m, unsigned char d, unsigned char h, unsigned char n, unsigned char s, unsigned u) +{ + init(y, m, d, h, n, s, u); } void DateTime::add_days(int days) { - unsigned new_year=year; + int new_year=year; /* Leap years have a 400 year cycle, so any 400 consecutive years have a constant number of days (400*365+97=146097) */ @@ -116,6 +96,7 @@ void DateTime::add_days(int days) new_year+=cycles*4; // See how many non-leap-years we counted as leap years and reclaim the lost days + // XXX This breaks with negative years unsigned missed_leap_days=((year-fudge)%100+cycles*4)/100; if((year-fudge)%400+cycles*4>=400) --missed_leap_days; @@ -133,8 +114,8 @@ void DateTime::add_days(int days) // We passed a leap year - decrement days if(days==0) { + days=is_leap_year(new_year-fudge)?365:364; --new_year; - days=is_leap_year(new_year)?365:364; } else --days; @@ -157,6 +138,17 @@ void DateTime::add_days(int days) mday+=days; } +void DateTime::set_timezone(const TimeZone &tz) +{ + zone=tz; +} + +void DateTime::convert_timezone(const TimeZone &tz) +{ + add_raw((zone.get_offset()-tz.get_offset()).raw()); + zone=tz; +} + DateTime DateTime::operator+(const TimeDelta &td) const { DateTime dt(*this); @@ -170,6 +162,19 @@ DateTime &DateTime::operator+=(const TimeDelta &td) return *this; } +DateTime DateTime::operator-(const TimeDelta &td) const +{ + DateTime dt(*this); + dt.add_raw(-td.raw()); + return dt; +} + +DateTime &DateTime::operator-=(const TimeDelta &td) +{ + add_raw(-td.raw()); + return *this; +} + int DateTime::cmp(const DateTime &dt) const { if(int c=cmp_(year, dt.year)) @@ -234,7 +239,7 @@ string DateTime::format(const string &fmt) const else if(*i=='y') ss<(offs/Time::min)); + ss<<(offs(raw/86400000000LL); raw%=86400000000LL; if(raw<0) { - ++days; + --days; raw+=86400000000LL; } diff --git a/source/time/datetime.h b/source/time/datetime.h index 57ca89d..5f9e8c6 100644 --- a/source/time/datetime.h +++ b/source/time/datetime.h @@ -3,6 +3,7 @@ #define MSP_TIME_DATETIME_H_ #include +#include "timezone.h" #include "types.h" namespace Msp { @@ -24,6 +25,7 @@ class DateTime { public: DateTime(const TimeStamp &); + DateTime(const TimeStamp &, const TimeZone &); DateTime(int, unsigned char, unsigned char); DateTime(int, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char); DateTime(int, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned); @@ -37,9 +39,13 @@ public: unsigned get_usec() const { return usec; } void add_days(int); + void set_timezone(const TimeZone &); + void convert_timezone(const TimeZone &); DateTime operator+(const TimeDelta &) const; DateTime &operator+=(const TimeDelta &); + DateTime operator-(const TimeDelta &) const; + DateTime &operator-=(const TimeDelta &); bool operator==(const DateTime &d) const { return cmp(d)==0; } bool operator!=(const DateTime &d) const { return cmp(d)!=0; } @@ -51,6 +57,7 @@ public: int cmp(const DateTime &) const; TimeStamp get_timestamp() const; std::string format(const std::string &) const; + std::string format_rfc3339() const; private: int year; unsigned char month; @@ -59,7 +66,10 @@ private: unsigned char minute; unsigned char second; unsigned usec; + TimeZone zone; + void init(const TimeStamp &); + void init(int, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char, unsigned); void add_raw(RawTime); void normalize(); void validate() const; diff --git a/source/time/timezone.cpp b/source/time/timezone.cpp new file mode 100644 index 0000000..fd2487b --- /dev/null +++ b/source/time/timezone.cpp @@ -0,0 +1,80 @@ +/* $Id$ + +This file is part of libmspcore +Copyright © 2008 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#include +#include +#include +#include "timezone.h" +#include "units.h" + +using namespace std; + +namespace { + +using Msp::Time::TimeZone; + +TimeZone get_local_timezone() +{ +#ifdef WIN32 + TIME_ZONE_INFORMATION tzinfo; + DWORD dst=GetTimeZoneInformation(&tzinfo); + if(dst==TIME_ZONE_ID_INVALID) + throw SystemError("Failed to get time zone information", GetLastError()); + + int offset=tzinfo.Bias; + if(dst==TIME_ZONE_ID_STANDARD) + offset+=tzinfo.StandardBias; + else if(dst==TIME_ZONE_ID_DAYLIGHT) + offset+=tzinfo.DaylightBias; + + return TimeZone(offset); +#else + tzset(); + return TimeZone(timezone/60); +#endif +} + +} + +namespace Msp { +namespace Time { + +TimeZone::TimeZone(): + name("UTC") +{ } + +TimeZone::TimeZone(int minutes_west): + offset(minutes_west*min) +{ + if(minutes_west) + { + ostringstream ss; + ss.fill('0'); + int m=abs(minutes_west); + ss<<"UTC"<<(minutes_west<0 ? '-' : '+')<