From: Mikko Rasa Date: Mon, 26 Mar 2007 20:08:11 +0000 (+0000) Subject: Added DateTime X-Git-Tag: 1.0~28 X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=80bbee2f401b4af71cb1b80508bdb0d2bb61fa40;p=libs%2Fcore.git Added DateTime Reworked operator<< for TimeDelta --- diff --git a/source/time/datetime.cpp b/source/time/datetime.cpp new file mode 100644 index 0000000..4fcec96 --- /dev/null +++ b/source/time/datetime.cpp @@ -0,0 +1,267 @@ +/* $Id$ */ +#include +#include +#include +#include "datetime.h" +#include "timestamp.h" + +using namespace std; + +namespace { + +inline bool is_leap_year(int32_t y) +{ return y%4==0 && (y%100 || y%400==0); } + +inline uint8_t month_days(int32_t y, uint8_t m) +{ + switch(m) + { + case 4: + case 6: + case 9: + case 11: + return 30; + case 2: + return is_leap_year(y)?29:28; + default: + return 31; + } +} + +template +inline int cmp_(T a, T b) +{ + if(ab) + return 1; + return 0; +} + +} + +#include +using namespace std; + +namespace Msp { +namespace Time { + +DateTime::DateTime(const TimeStamp &ts): + year(1970), + month(1), + mday(1), + hour(0), + minute(0), + second(0), + usec(0) +{ + add_raw(ts.raw()); +} + +DateTime::DateTime(int32_t y, uint8_t m, uint8_t d): + year(y), + month(m), + mday(d), + hour(0), + minute(0), + second(0), + usec(0) +{ } + +void DateTime::add_days(int32_t days) +{ + unsigned new_year=year; + + /* Leap years have a 400 year cycle, so any 400 consecutive years have a + constant number of days */ + new_year+=days/146097*400; + days%=146097; + + if(days<0) + { + new_year-=400; + days+=146097; + } + + // Fudge factor for leap day + int fudge=(month<=2)?1:0; + + // (Almost) every 4 year cycle has 1 leap year and 3 normal years + unsigned cycles=days/1461; + days%=1461; + + new_year+=cycles*4; + + // See how many non-leap-years we counted as leap years and reclaim the lost days + unsigned missed_leap_days=((year-fudge)%100+cycles*4)/100; + if((year-fudge)%400+cycles*4>=400) + --missed_leap_days; + + days+=missed_leap_days; + + // Count single years from the 4 year cycle + cycles=days/365; + days%=365; + + new_year+=cycles; + + if((year-fudge)%4+cycles>=4) + { + // We passed a leap year - decrement days + if(days==0) + { + --new_year; + days=is_leap_year(new_year)?365:364; + } + else + --days; + } + + year=new_year; + + // Step months + while(mday+days>month_days(year, month)) + { + days-=month_days(year, month); + ++month; + if(month>12) + { + ++year; + month=1; + } + } + + mday+=days; +} + +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)) + return c; + if(int c=cmp_(month, dt.month)) + return c; + if(int c=cmp_(mday, dt.mday)) + return c; + if(int c=cmp_(hour, dt.hour)) + return c; + if(int c=cmp_(minute, dt.minute)) + return c; + if(int c=cmp_(second, dt.second)) + return c; + if(int c=cmp_(usec, dt.usec)) + return c; + return 0; +} + +TimeStamp DateTime::get_timestamp() const +{ + if(year<-289701 || year>293641) + throw Exception("DateTime is not representable as a TimeStamp"); + + int64_t raw=(((hour*60LL)+minute)*60+second)*1000000+usec; + int days=(year-1970)*365; + days+=(year-1)/4-(year-1)/100+(year-1)/400-477; + for(unsigned i=1; i=12) ? "PM" : "AM"); + else if(*i=='S') + ss<month_days(year, month)) + { + mday-=month_days(year, month); + ++month; + if(month>12) + { + ++year; + month=1; + } + } +} + +} // namespace Time +} // namespace Msp diff --git a/source/time/datetime.h b/source/time/datetime.h new file mode 100644 index 0000000..4f439e6 --- /dev/null +++ b/source/time/datetime.h @@ -0,0 +1,70 @@ +/* $Id$ */ +#ifndef MSP_TIME_DATETIME_H_ +#define MSP_TIME_DATETIME_H_ + +#include +#include + +namespace Msp { +namespace Time { + +class TimeDelta; +class TimeStamp; + +/** +Provides handling of arbitary dates and times. Can represent a moment of time +in the range of about ±2.1×10⁹ years. It can also be formatted into a string +for presentation to the user. + +Due to the complex internal representation, arithmetic operations on a DateTime +are relatively slow. For purposes of internal scheduling in a program, a +TimeStamp is a better choice. +*/ +class DateTime +{ +public: + DateTime(const TimeStamp &); + DateTime(int32_t, uint8_t, uint8_t); + DateTime(int32_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t); + DateTime(int32_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint32_t); + + int32_t get_year() const { return year; } + uint8_t get_month() const { return month; } + uint8_t get_mday() const { return mday; } + uint8_t get_hour() const { return hour; } + uint8_t get_minute() const { return minute; } + uint8_t get_second() const { return second; } + uint32_t get_usec() const { return usec; } + + void add_days(int32_t); + + 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; } + bool operator<(const DateTime &d) const { return cmp(d)<0; } + bool operator<=(const DateTime &d) const { return cmp(d)<=0; } + bool operator>(const DateTime &d) const { return cmp(d)>0; } + bool operator>=(const DateTime &d) const { return cmp(d)>=0; } + + int cmp(const DateTime &) const; + TimeStamp get_timestamp() const; + std::string format(const std::string &) const; +private: + int32_t year; + uint8_t month; + uint8_t mday; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint32_t usec; + + void add_raw(int64_t); + void normalize(); +}; + +} // namespace Time +} // namespace Msp + +#endif diff --git a/source/time/timedelta.cpp b/source/time/timedelta.cpp index acf9eef..f7b037e 100644 --- a/source/time/timedelta.cpp +++ b/source/time/timedelta.cpp @@ -4,88 +4,72 @@ Copyright © 2006 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ #include +#include #include "timedelta.h" #include "units.h" using namespace std; -namespace Msp { -namespace Time { +namespace { void print_part(ostream &out, int64_t &value, int64_t unit, char sep, bool &first) { - if(value>=unit || !first) - { - if(first) - out< inline TimeDelta operator*(T a, const TimeDelta &t) { return t*a; } +extern std::ostream &operator<<(std::ostream &, const TimeDelta &); + } // namespace Time } // namespace Msp diff --git a/source/time/timestamp.h b/source/time/timestamp.h index 984333d..1e1b275 100644 --- a/source/time/timestamp.h +++ b/source/time/timestamp.h @@ -13,9 +13,10 @@ namespace Msp { namespace Time { /** -Represents a moment in time, such as the last tick. This class is NOT intended -to be used for storing arbitary user-defined times, I'll add a DateTime class -if the need arises. +Represents a moment in time. The main source of TimeStamps is the now() +function. + +For representing user-specified times, use the DateTime class. */ class TimeStamp { @@ -33,8 +34,8 @@ public: explicit TimeStamp(int64_t u): usec(u) { } /** - Returns the raw number stored inside the TimeStamp. This should only be used - for serialization and the result should not be interpreted in any way. + Returns the raw number stored inside the TimeStamp. This value should be + considered opaque and only be used for serialization. */ int64_t raw() const { return usec; } diff --git a/source/time/utils.cpp b/source/time/utils.cpp index d6b6332..ad0d245 100644 --- a/source/time/utils.cpp +++ b/source/time/utils.cpp @@ -9,11 +9,14 @@ Distributed under the LGPL #include #include #endif +#include "datetime.h" #include "timedelta.h" #include "timestamp.h" #include "units.h" #include "utils.h" +using namespace std; + namespace Msp { namespace Time { @@ -50,6 +53,11 @@ TimeStamp now() #endif } +string format_now(const string &fmt) +{ + return DateTime(now()).format(fmt); +} + /** Returns the CPU time used by the program so far. */ diff --git a/source/time/utils.h b/source/time/utils.h index e16cb65..bc04bad 100644 --- a/source/time/utils.h +++ b/source/time/utils.h @@ -13,6 +13,7 @@ class TimeDelta; class TimeStamp; extern TimeStamp now(); +extern std::string format_now(const std::string &); extern TimeDelta get_cpu_time(); extern int sleep(const TimeDelta &);