From 73f75393e9f451add7a8bc02739119966c5c4cea Mon Sep 17 00:00:00 2001 From: Martchus Date: Sun, 3 Dec 2017 14:46:10 +0100 Subject: [PATCH] WIP --- chrono/datetime.h | 51 +++++++++++++++++++++++++++++++++++++++++++ chrono/timespan.h | 2 ++ tests/chronotests.cpp | 4 ++++ 3 files changed, 57 insertions(+) diff --git a/chrono/datetime.h b/chrono/datetime.h index e461df7..4231843 100644 --- a/chrono/datetime.h +++ b/chrono/datetime.h @@ -49,6 +49,8 @@ enum class DatePart { Day /**< day */ }; +struct Date; + class CPP_UTILITIES_EXPORT DateTime { public: explicit constexpr DateTime(); @@ -70,6 +72,7 @@ public: int day() const; int dayOfYear() const; constexpr DayOfWeek dayOfWeek() const; + constexpr Date date() const; constexpr int hour() const; constexpr int minute() const; constexpr int second() const; @@ -505,6 +508,54 @@ inline DateTime &DateTime::operator-=(const TimeSpan &timeSpan) m_ticks -= timeSpan.m_ticks; return *this; } + +struct Date { + constexpr Date(DateTime dateTime); + + int year; + int month; + int day; +}; + +constexpr Date::Date(DateTime dateTime) + : year(0) + , month(0) + , day(0) +{ + const int fullDays = dateTime.totalTicks() / TimeSpan::m_ticksPerDay; + const int full400YearBlocks = fullDays / DateTime::m_daysPer400Years; + const int daysMinusFull400YearBlocks = fullDays - full400YearBlocks * m_daysPer400Years; + int full100YearBlocks = daysMinusFull400YearBlocks / m_daysPer100Years; + if (full100YearBlocks == 4) { + full100YearBlocks = 3; + } + const int daysMinusFull100YearBlocks = daysMinusFull400YearBlocks - full100YearBlocks * m_daysPer100Years; + const int full4YearBlocks = daysMinusFull100YearBlocks / m_daysPer4Years; + const int daysMinusFull4YearBlocks = daysMinusFull100YearBlocks - full4YearBlocks * m_daysPer4Years; + int full1YearBlocks = daysMinusFull4YearBlocks / m_daysPerYear; + if (full1YearBlocks == 4) { + full1YearBlocks = 3; + } + if (part == DatePart::Year) { + return full400YearBlocks * 400 + full100YearBlocks * 100 + full4YearBlocks * 4 + full1YearBlocks + 1; + } + const int restDays = daysMinusFull4YearBlocks - full1YearBlocks * m_daysPerYear; + if (part == DatePart::DayOfYear) { // day + return restDays + 1; + } + const int *const daysToMonth = (full1YearBlocks == 3 && (full4YearBlocks != 24 || full100YearBlocks == 3)) ? m_daysToMonth366 : m_daysToMonth365; + int month = 1; + while (restDays >= daysToMonth[month]) { + ++month; + } + if (part == DatePart::Month) { + return month; + } else if (part == DatePart::Day) { + return restDays - daysToMonth[month - 1] + 1; + } + return 0; +} + } // namespace ChronoUtilities namespace std { diff --git a/chrono/timespan.h b/chrono/timespan.h index 04a2fc4..0b5235e 100644 --- a/chrono/timespan.h +++ b/chrono/timespan.h @@ -14,6 +14,7 @@ namespace ChronoUtilities { class DateTime; +struct Date; /*! * \brief Specifies the output format. @@ -27,6 +28,7 @@ enum class TimeSpanOutputFormat { class CPP_UTILITIES_EXPORT TimeSpan { friend class DateTime; + friend struct Date; public: explicit constexpr TimeSpan(); diff --git a/tests/chronotests.cpp b/tests/chronotests.cpp index cb07ddc..3f6f39d 100644 --- a/tests/chronotests.cpp +++ b/tests/chronotests.cpp @@ -105,6 +105,10 @@ void ChronoTests::testDateTime() const auto delta = DateTime::gmtNow() - DateTime::exactGmtNow(); CPPUNIT_ASSERT(delta < TimeSpan::fromSeconds(2) && delta > TimeSpan::fromSeconds(-2)); #endif + + // test boundaries + CPPUNIT_ASSERT_EQUAL("0001-01-01 00:00:00"s, DateTime().toString()); + CPPUNIT_ASSERT_EQUAL("58456-05-28 05:36:10.955"s, DateTime::eternity().toString()); } /*!