]> git.tdb.fi Git - libs/core.git/blobdiff - source/time/datetime.cpp
Add support for time zones
[libs/core.git] / source / time / datetime.cpp
index 2d7c19585cefeea0838b045643a9b9aaac588db7..283a7c6c7578c73484224e27615f92fe78d7ee79 100644 (file)
@@ -1,9 +1,11 @@
 /* $Id$ */
+#include <cstdlib>
 #include <sstream>
 #include <iomanip>
 #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<<setw(2)<<year%100;
                        else if(*i=='Y')
-                               ss<<year;
+                               ss<<setw(4)<<internal<<year;
                        else if(*i=='%')
                                ss<<'%';
                }
@@ -245,13 +250,53 @@ string DateTime::format(const string &fmt) const
        return ss.str();
 }
 
+string DateTime::format_rfc3339() const
+{
+       string result=format("%Y-%m-%dT%H:%M:%S");
+       if(const TimeDelta &offs=zone.get_offset())
+       {
+               ostringstream ss;
+               ss.fill('0');
+               int m=abs(static_cast<int>(offs/Time::min));
+               ss<<(offs<zero ? '+' : '-')<<setw(2)<<m/60<<':'<<setw(2)<<m%60;
+               result+=ss.str();
+       }
+       else
+               result+='Z';
+       return result;
+}
+
+void DateTime::init(const TimeStamp &ts)
+{
+       year=1970;
+       month=1;
+       mday=1;
+       hour=0;
+       minute=0;
+       second=0;
+       usec=0;
+       add_raw(ts.raw());
+}
+
+void DateTime::init(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;
+       validate();
+}
+
 void DateTime::add_raw(RawTime raw)
 {
        int days=static_cast<int>(raw/86400000000LL);
        raw%=86400000000LL;
        if(raw<0)
        {
-               ++days;
+               --days;
                raw+=86400000000LL;
        }