Add GncDate and GncDateTime constructors and accessors:

GncDateImpl constructor and ymd accessor for GncDate
Std::string constructor and nsecs and GDate accessors for GncDateTime.
This commit is contained in:
John Ralls committed 2015-04-28 13:40:48 -07:00
1 parent 3f87f56e2e
commit ab72874ec1
4 files changed
+151 -5

No files matched your search

+78
View File
@@ -44,6 +44,7 @@ static const TimeZoneProvider tzp;
// For converting to/from POSIX time.
static const PTime unix_epoch (Date(1970, boost::gregorian::Jan, 1),
boost::posix_time::seconds(0));
static const TZ_Ptr utc_zone(new boost::local_time::posix_time_zone("UTC-0"));
/* To ensure things aren't overly screwed up by setting the nanosecond clock for boost::date_time. Don't do it, though, it doesn't get us anything and slows down the date/time library. */
#ifndef BOOST_DATE_TIME_HAS_NANOSECONDS
@@ -63,10 +64,18 @@ public:
GncDateImpl(Date d) : m_greg(d) {}
void today() { m_greg = boost::gregorian::day_clock::local_day(); }
ymd ymd() const;
private:
Date m_greg;
};
ymd
GncDateImpl::ymd() const
{
auto boost_ymd = m_greg.year_month_day();
return {boost_ymd.year, boost_ymd.month.as_number(), boost_ymd.day};
}
/** Private implementation of GncDateTime. See the documentation for that class.
*/
static LDT
@@ -95,6 +104,7 @@ public:
GncDateTimeImpl() : m_time(unix_epoch, tzp.get(unix_epoch.date().year())) {}
GncDateTimeImpl(const time64 time) : m_time(LDT_from_unix_local(time)) {}
GncDateTimeImpl(const struct tm tm) : m_time(LDT_from_struct_tm(tm)) {}
GncDateTimeImpl(const std::string str);
GncDateTimeImpl(PTime&& pt) : m_time(pt, tzp.get(pt.date().year())) {}
GncDateTimeImpl(LDT&& ldt) : m_time(ldt) {}
@@ -102,11 +112,41 @@ public:
operator struct tm() const;
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;
std::unique_ptr<GncDateImpl> date() const;
std::string format(const char* format) const;
private:
LDT m_time;
};
GncDateTimeImpl::GncDateTimeImpl(const std::string str) :
m_time(unix_epoch, utc_zone)
{
if (str.empty()) return;
using std::string;
using PTZ = boost::local_time::posix_time_zone;
TZ_Ptr tzptr;
auto tzpos = str.find_first_of("+-", str.find(":"));
if (tzpos != str.npos)
{
string tzstr = "XXX" + str.substr(tzpos);
if (tzstr.length() > 6 && tzstr[6] != ':') //6 for XXXsHH, s is + or -
tzstr.insert(6, ":");
if (tzstr.length() > 9 && tzstr[9] != ':') //9 for XXXsHH:MM
tzstr.insert(9, ":");
tzptr.reset(new PTZ(tzstr));
if (str[tzpos - 1] == ' ') --tzpos;
}
else
{
tzptr = utc_zone;
}
auto pdt = boost::posix_time::time_from_string(str.substr(0, tzpos));
m_time = LDT(pdt, tzptr);
}
GncDateTimeImpl::operator time64() const
{
auto duration = m_time.utc_time() - unix_epoch;
@@ -127,6 +167,18 @@ GncDateTimeImpl::offset() const
return offset.total_seconds();
}
long
GncDateTimeImpl::nsecs() const
{
return (m_time.utc_time() - unix_epoch).ticks() % ticks_per_second;
}
std::unique_ptr<GncDateImpl>
GncDateTimeImpl::date() const
{
return std::unique_ptr<GncDateImpl>(new GncDateImpl(m_time.local_time().date()));
}
std::string
GncDateTimeImpl::format(const char* format) const
{
@@ -143,19 +195,33 @@ GncDateTimeImpl::format(const char* format) const
GncDate::GncDate() : m_impl{new GncDateImpl} {}
GncDate::GncDate(int year, int month, int day) :
m_impl(new GncDateImpl(year, month, day)) {}
GncDate::GncDate(std::unique_ptr<GncDateImpl> impl) :
m_impl(std::move(impl)) {}
GncDate::GncDate(GncDate&&) = default;
GncDate::~GncDate() = default;
GncDate&
GncDate::operator=(GncDate&&) = default;
void
GncDate::today()
{
m_impl->today();
}
ymd
GncDate::ymd() const
{
return m_impl->ymd();
}
GncDateTime::GncDateTime() : m_impl(new GncDateTimeImpl) {}
GncDateTime::GncDateTime(const time64 time) :
m_impl(new GncDateTimeImpl(time)) {}
GncDateTime::GncDateTime(const struct tm tm) :
m_impl(new GncDateTimeImpl(tm)) {}
GncDateTime::GncDateTime(const std::string str) :
m_impl(new GncDateTimeImpl(str)) {}
GncDateTime::~GncDateTime() = default;
void
@@ -180,6 +246,18 @@ GncDateTime::offset() const
return m_impl->offset();
}
long
GncDateTime::nsecs() const
{
return m_impl->nsecs();
}
GncDate
GncDateTime::date() const
{
return std::move(GncDate(m_impl->date()));
}
std::string
GncDateTime::format(const char* format) const
{
+59 -4
View File
@@ -27,6 +27,14 @@
#include <cstdint>
#include <memory>
#include <string>
typedef struct
{
int year; //1400-9999
int month; //1-12
int day; //1-31
} ymd;
class GncDateImpl;
class GncDateTimeImpl;
@@ -34,8 +42,7 @@ using time64 = int64_t;
class GncDate
{
public:
/** Construct a GncDate representing the current day.
public:/** Construct a GncDate representing the current day.
*/
GncDate();;
/** Construct a GncDate representing the given year, month, and day in
@@ -52,14 +59,21 @@ public:
* of the constrained range.
*/
GncDate(int year, int month, int day);
GncDate(std::unique_ptr<GncDateImpl> impl);
GncDate(GncDate&&);
~GncDate();
GncDate& operator=(GncDate&&);
/** Set the date object to the computer clock's current day. */
void today();
/** Get the year, month, and day from the date as a ymd.
@return ymd struct
*/
ymd ymd() const;
/** Test that the Date has an implementation. */
bool isnull (void) { return m_impl == nullptr; }
private:
std::unique_ptr<GncDateImpl> m_impl;
std::unique_ptr<GncDateImpl> m_impl;
};
/** GnuCash DateTime class
@@ -88,13 +102,54 @@ public:
* @exception std::invalid_argument if the year is outside the constraints.
*/
GncDateTime(const time64 time);
/** Construct a GncDateTime in the current timezone representing the
* standard struct tm provided.
* @param tm: A C-standard struct tm representing the date and
* time. Note that the timezone and offset are ignored on those
* systems which include them in struct tm.
* @exception std::invalid_argument if the year is outside the constraints.
*/
GncDateTime(const struct tm tm);
/** Construct a GncDateTime
* @param str: A string representing the date and time in some
* recognizable format. Note that if a timezone is not specified the
* default is UTC, not the local one.
* @exception std::invalid_argument if the year is outside the constraints.
*/
GncDateTime(const std::string str);
~GncDateTime();
/** Set the GncDateTime to the date and time indicated in the computer's clock.
*/
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.
*/
explicit operator struct tm() const;
long offset() const;
/** Obtain the UTC offset in seconds
* @return seconds difference between this local time and UTC. West
* is negative.
*/
long offset()const;
/** Obtain the fractional seconds from the GncDateTime
* @return Fractional seconds, represented as nanoseconds, associated
* with the time.
*/
long nsecs() const;
/** Obtain the date from the time, as a GncDate, in the current timezone.
* @return GncDate represented by the GncDateTime.
*/
GncDate date() const;
/** Test if the GncDateTime has a member pointer. Testing only. */
bool isnull (void) { return m_impl == nullptr; }
/** Format the GncDateTime into a std::string
* @return a std::string containing a representation of the date
* according to the format. Consult the boost::date_time
* documentation for format characters; while they mostly compy with
* POSIX there are a few differences.
*/
std::string format(const char* format) const;
private:
+3 -1
View File
@@ -95,7 +95,9 @@ test_gnc_datetime_CPPFLAGS =\
-I$(GTEST_HEADERS) \
-I$(top_srcdir)/src \
$(BOOST_CPPFLAGS)
test_gnc_datetime_LDADD = $(GTEST_LIBS)
test_gnc_datetime_LDADD = \
-lboost_date_time \
$(GTEST_LIBS)
if !GOOGLE_TEST_LIBS
nodist_test_gnc_datetime_SOURCES = \
$(GTEST_SRC)/src/gtest_main.cc
@@ -76,3 +76,14 @@ TEST(gnc_datetime_functions, test_format)
//Date only to finesse timezone issues. It will still fail in +12 DST.
EXPECT_EQ(atime.format("%d-%m-%Y"), "13-11-2045");
}
//This is a bit convoluted because it uses GncDate's GncDateImpl constructor and ymd() function. There's no good way to test the former without violating the privacy of the implementation.
TEST(gnc_datetime_functions, test_date)
{
GncDateTime atime(2394187200); //2045-11-13 12:00:00 Z
GncDate gncd = std::move(atime.date());
auto ymd = gncd.ymd();
EXPECT_EQ(ymd.year, 2045);
EXPECT_EQ(ymd.month, 11);
EXPECT_EQ(ymd.day, 13);
}