diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp index 4f357a1937..847e255f7f 100644 --- a/src/libqof/qof/gnc-date.cpp +++ b/src/libqof/qof/gnc-date.cpp @@ -155,20 +155,34 @@ gnc_tm_free (struct tm* time) struct tm* gnc_localtime (const time64 *secs) { - auto time = static_cast(calloc(1, sizeof(struct tm))); - if (gnc_localtime_r (secs, time) == NULL) + try + { + auto time = static_cast(calloc(1, sizeof(struct tm))); + if (gnc_localtime_r (secs, time) == NULL) + { + gnc_tm_free (time); + return NULL; + } + return time; + } + catch(std::invalid_argument) { - gnc_tm_free (time); return NULL; } - return time; } struct tm* gnc_localtime_r (const time64 *secs, struct tm* time) { - *time = static_cast(GncDateTime(*secs)); - return time; + try + { + *time = static_cast(GncDateTime(*secs)); + return time; + } + catch(std::invalid_argument) + { + return NULL; + } } static void @@ -232,34 +246,48 @@ normalize_struct_tm (struct tm* time) struct tm* gnc_gmtime (const time64 *secs) { - auto time = static_cast(calloc(1, sizeof(struct tm))); - GncDateTime gncdt(*secs); - *time = static_cast(gncdt); - auto gmtoff = gncdt.offset(); - time->tm_hour -= gmtoff / 3600; - time->tm_min -= (gmtoff % 3600 / 60); - time->tm_sec -= gmtoff % 60; - normalize_struct_tm(time); - return time; + try + { + auto time = static_cast(calloc(1, sizeof(struct tm))); + GncDateTime gncdt(*secs); + *time = gncdt.utc_tm(); + return time; + } + catch(std::invalid_argument) + { + return NULL; + } + } time64 gnc_mktime (struct tm* time) { - normalize_struct_tm (time); - auto ldt = gnc_get_LDT (time->tm_year + 1900, time->tm_mon + 1, - time->tm_mday, time->tm_hour, time->tm_min, - time->tm_sec); - return time64_from_date_time(ldt); + try + { + normalize_struct_tm (time); + GncDateTime gncdt(*time); + return static_cast(gncdt) - gncdt.offset(); + } + catch(std::invalid_argument) + { + return 0; + } } time64 gnc_timegm (struct tm* time) { - auto newtime = *time; - normalize_struct_tm(time); - auto pdt = boost::posix_time::ptime_from_tm(*time); - return time64_from_date_time(pdt); + try + { + normalize_struct_tm(time); + return static_cast(GncDateTime(*time)); + } + catch(std::invalid_argument) + { + return 0; + } + } char* diff --git a/src/libqof/qof/gnc-datetime.cpp b/src/libqof/qof/gnc-datetime.cpp index 8d2f097049..40ac1a689b 100644 --- a/src/libqof/qof/gnc-datetime.cpp +++ b/src/libqof/qof/gnc-datetime.cpp @@ -81,21 +81,35 @@ GncDateImpl::ymd() const static LDT LDT_from_unix_local(const time64 time) { - PTime temp(unix_epoch.date(), - boost::posix_time::hours(time / 3600) + - boost::posix_time::seconds(time % 3600)); - auto tz = tzp.get(temp.date().year()); - return LDT(temp, tz); + try + { + PTime temp(unix_epoch.date(), + boost::posix_time::hours(time / 3600) + + boost::posix_time::seconds(time % 3600)); + auto tz = tzp.get(temp.date().year()); + return LDT(temp, tz); + } + catch(boost::gregorian::bad_year) + { + throw(std::invalid_argument("Time value is outside the supported year range.")); + } } static LDT LDT_from_struct_tm(const struct tm tm) { - auto tdate = boost::gregorian::date_from_tm(tm); - auto tdur = boost::posix_time::time_duration(tm.tm_hour, tm.tm_min, - tm.tm_sec, 0); - auto tz = tzp.get(tdate.year()); - return LDT(PTime(tdate, tdur), tz); + try + { + auto tdate = boost::gregorian::date_from_tm(tm); + auto tdur = boost::posix_time::time_duration(tm.tm_hour, tm.tm_min, + tm.tm_sec, 0); + auto tz = tzp.get(tdate.year()); + return LDT(PTime(tdate, tdur), tz); + } + catch(boost::gregorian::bad_year) + { + throw(std::invalid_argument("Time value is outside the supported year range.")); + } } class GncDateTimeImpl @@ -113,6 +127,7 @@ public: void now() { m_time = boost::local_time::local_sec_clock::local_time(tzp.get(boost::gregorian::day_clock::local_day().year())); } long offset() const; long nsecs() const; + struct tm utc_tm() const { return to_tm(m_time.utc_time()); } std::unique_ptr date() const; std::string format(const char* format) const; private: @@ -157,7 +172,11 @@ GncDateTimeImpl::operator time64() const GncDateTimeImpl::operator struct tm() const { - return to_tm(m_time); + struct tm time = to_tm(m_time); +#if HAVE_STRUCT_TM_GMTOFF + time.tm_gmtoff = offset(); +#endif + return time; } long @@ -252,6 +271,12 @@ GncDateTime::nsecs() const return m_impl->nsecs(); } +struct tm +GncDateTime::utc_tm() const +{ + return m_impl->utc_tm(); +} + GncDate GncDateTime::date() const { diff --git a/src/libqof/qof/gnc-datetime.hpp b/src/libqof/qof/gnc-datetime.hpp index e2fe6a704b..46dd83d896 100644 --- a/src/libqof/qof/gnc-datetime.hpp +++ b/src/libqof/qof/gnc-datetime.hpp @@ -123,8 +123,7 @@ public: void now(); /** Cast the GncDateTime to a time64, seconds from the POSIX epoch. */ explicit operator time64() const; -/** Cast the GncDateTime to a struct tm. Timezone and offset fields - * are not filled. +/** Cast the GncDateTime to a struct tm. Timezone field isn't filled. */ explicit operator struct tm() const; /** Obtain the UTC offset in seconds @@ -137,6 +136,10 @@ public: * with the time. */ long nsecs() const; +/** Obtain a struct tm representing the time in UTC. + * @return struct tm + */ + struct tm utc_tm() const; /** Obtain the date from the time, as a GncDate, in the current timezone. * @return GncDate represented by the GncDateTime. */