aboutsummaryrefslogtreecommitdiff
path: root/extension/src/openvic2/Date.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'extension/src/openvic2/Date.cpp')
-rw-r--r--extension/src/openvic2/Date.cpp190
1 files changed, 118 insertions, 72 deletions
diff --git a/extension/src/openvic2/Date.cpp b/extension/src/openvic2/Date.cpp
index e1cef72..bb891fd 100644
--- a/extension/src/openvic2/Date.cpp
+++ b/extension/src/openvic2/Date.cpp
@@ -1,115 +1,161 @@
-#include <sstream>
-#include "Date.hpp"
+#include "openvic2/Date.hpp"
+
+#include <cctype>
+#include <algorithm>
+
+#include "openvic2/Logger.hpp"
using namespace OpenVic2;
-bool Timespan::operator< (Timespan const& other) const { return days < other.days; }
-bool Timespan::operator> (Timespan const& other) const { return days > other.days; }
-bool Timespan::operator<= (Timespan const& other) const { return days <= other.days; }
-bool Timespan::operator>= (Timespan const& other) const { return days >= other.days; }
-bool Timespan::operator== (Timespan const& other) const { return days == other.days; }
-bool Timespan::operator!= (Timespan const& other) const { return days != other.days; }
+Timespan::Timespan(day_t value) : days{value} {}
+
+bool Timespan::operator<(Timespan other) const { return days < other.days; };
+bool Timespan::operator>(Timespan other) const { return days > other.days; };
+bool Timespan::operator<=(Timespan other) const { return days <= other.days; };
+bool Timespan::operator>=(Timespan other) const { return days >= other.days; };
+bool Timespan::operator==(Timespan other) const { return days == other.days; };
+bool Timespan::operator!=(Timespan other) const { return days != other.days; };
+
+Timespan Timespan::operator+(Timespan other) const { return days + other.days; }
+
+Timespan Timespan::operator-(Timespan other) const { return days - other.days; }
-Timespan Timespan::operator+ (Timespan const& other) const { return Timespan(days + other.days); }
-Timespan Timespan::operator- (Timespan const& other) const { return Timespan(days - other.days); }
-Timespan Timespan::operator* (int64_t const& factor) const { return Timespan(days * factor); }
-Timespan Timespan::operator/ (int64_t const& factor) const { return Timespan(days / factor); }
+Timespan Timespan::operator*(day_t factor) const { return days * factor; }
-Timespan& Timespan::operator+= (Timespan const& other) {
+Timespan Timespan::operator/(day_t factor) const { return days / factor; }
+
+Timespan& Timespan::operator+=(Timespan other) {
days += other.days;
return *this;
}
-Timespan& Timespan::operator-= (Timespan const& other) {
+
+Timespan& Timespan::operator-=(Timespan other) {
days -= other.days;
return *this;
}
-Timespan::operator std::string() const {
- return std::to_string(days);
+Timespan& Timespan::operator++() {
+ days++;
+ return *this;
}
-std::ostream &operator<<(std::ostream &out, Timespan const& timespan) {
- return out << static_cast<std::string>(timespan);
+
+Timespan Timespan::operator++(int) {
+ Timespan old = *this;
+ ++(*this);
+ return old;
}
-Timespan fromYearZero(year_t year, month_t month, date_t day) {
- int64_t daysElapsed = year * DAYS_IN_YEAR;
- size_t daysSinceMonthStart = (day == 0) ? 0 : day - 1; //Underflow protection
- for (size_t x = 0; x < month && x < MONTHS_IN_YEAR; x++) {
- daysElapsed += DAYS_IN_MONTH[x];
- }
- daysElapsed += daysSinceMonthStart;
- return Timespan(daysElapsed);
+Timespan::operator day_t() const {
+ return days;
}
-//This function is not set up to handle dates before Year 0
-YearMonthDayBundle toGregorianDate(Timespan const& timespan) {
- year_t year = 0;
- month_t month = 0;
- date_t day = 0;
+Timespan::operator double() const {
+ return days;
+}
- if (timespan >= 0) {
- year = timespan.days / DAYS_IN_YEAR;
- int64_t remainingDays = timespan.days % DAYS_IN_YEAR;
+Timespan::operator std::string() const {
+ return std::to_string(days);
+}
+
+std::ostream& OpenVic2::operator<<(std::ostream& out, Timespan timespan) {
+ return out << static_cast<std::string>(timespan);
+}
- for (size_t x = 0; x < MONTHS_IN_YEAR && remainingDays >= DAYS_IN_MONTH[x]; x++) {
- remainingDays -= DAYS_IN_MONTH[x];
- month++;
- }
+Timespan Date::_dateToTimespan(year_t year, month_t month, day_t day) {
+ month = std::clamp<month_t>(month, 1, MONTHS_IN_YEAR);
+ day = std::clamp<day_t>(day, 1, DAYS_IN_MONTH[month - 1]);
+ return year * DAYS_IN_YEAR + DAYS_UP_TO_MONTH[month - 1] + day - 1;
+}
- //Corrects month and day to be 1-indexed
- month++;
- day++;
+Date::Date(Timespan total_days) : timespan{ total_days } {
+ if (timespan < 0) {
+ Logger::error("Invalid timespan for date: ", timespan, " (cannot be negative)");
+ timespan = 0;
}
- return std::make_tuple(year, month, day);
}
+Date::Date(year_t year, month_t month, day_t day) : timespan{ _dateToTimespan(year, month, day) } {}
-Date::Date(Timespan const& timespan) : ts(timespan) { updateDate(ts); }
+Date::year_t Date::getYear() const {
+ return static_cast<Timespan::day_t>(timespan) / DAYS_IN_YEAR;
+}
-Date::Date(year_t year, month_t month, date_t day) {
- ts = fromYearZero(year, month, day);
- updateDate(ts);
+Date::month_t Date::getMonth() const {
+ return ((static_cast<Timespan::day_t>(timespan) % DAYS_IN_YEAR) / 32) + 1;
}
-void Date::updateDate(Timespan const& timespan) {
- gregorianDate = toGregorianDate(timespan);
+Date::day_t Date::getDay() const {
+ const Timespan::day_t days_in_year = static_cast<Timespan::day_t>(timespan) % DAYS_IN_YEAR;
+ return days_in_year - DAYS_UP_TO_MONTH[days_in_year / 32] + 1;
}
-size_t Date::getDay() const { return std::get<2>(gregorianDate); }
-size_t Date::getMonth() const { return std::get<1>(gregorianDate); }
-size_t Date::getYear() const { return std::get<0>(gregorianDate); }
-bool Date::operator< (Date const& other) const { return ts < other.ts; }
-bool Date::operator> (Date const& other) const { return ts > other.ts; }
-bool Date::operator<= (Date const& other) const { return ts <= other.ts; }
-bool Date::operator>= (Date const& other) const { return ts >= other.ts; }
-bool Date::operator== (Date const& other) const { return ts == other.ts; }
-bool Date::operator!= (Date const& other) const { return ts != other.ts; }
+bool Date::operator<(Date other) const { return timespan < other.timespan; };
+bool Date::operator>(Date other) const { return timespan > other.timespan; };
+bool Date::operator<=(Date other) const { return timespan <= other.timespan; };
+bool Date::operator>=(Date other) const { return timespan >= other.timespan; };
+bool Date::operator==(Date other) const { return timespan == other.timespan; };
+bool Date::operator!=(Date other) const { return timespan != other.timespan; };
+
+Date Date::operator+(Timespan other) const { return timespan + other; }
+
+Timespan Date::operator-(Date other) const { return timespan - other.timespan; }
-Date Date::operator+ (Timespan timespan) const { return Date(ts + timespan); }
-Timespan Date::operator- (Date const& other) const { return ts - other.ts; }
+Date& Date::operator+=(Timespan other) {
+ timespan += other;
+ return *this;
+}
-Date& Date::operator+= (Timespan const& timespan) {
- ts += timespan;
- updateDate(ts);
+Date& Date::operator-=(Timespan other) {
+ timespan -= other;
return *this;
}
-Date& Date::operator-= (Timespan const& timespan) {
- ts -= timespan;
- updateDate(ts);
+
+Date& Date::operator++() {
+ timespan++;
return *this;
}
-Date Date::operator++ (int) {
- Date oldCopy = *this;
- (*this) += 1;
- return oldCopy;
+
+Date Date::operator++(int) {
+ Date old = *this;
+ ++(*this);
+ return old;
}
Date::operator std::string() const {
std::stringstream ss;
- ss << getYear() << '.' << getMonth() << '.' << getDay();
+ ss << *this;
return ss.str();
}
-std::ostream &operator<<(std::ostream &out, Date const& date) {
- return out << static_cast<std::string>(date);
+
+std::ostream& OpenVic2::operator<<(std::ostream& out, Date date) {
+ return out << (int) date.getYear() << '.' << (int) date.getMonth() << '.' << (int) date.getDay();
}
+
+// Parsed from string of the form YYYY.MM.DD
+Date Date::from_string(std::string const& date) {
+ year_t year = 0;
+ month_t month = 1;
+ day_t day = 1;
+
+ size_t first_pos = 0;
+ while (first_pos < date.length() && std::isdigit(date[first_pos++]));
+ year = atoi(date.substr(0, first_pos).c_str());
+ if (first_pos < date.length()) {
+ if (date[first_pos] == '.') {
+ size_t second_pos = first_pos + 1;
+ while (second_pos < date.length() && std::isdigit(date[second_pos++]));
+ month = atoi(date.substr(first_pos, second_pos - first_pos).c_str());
+ if (second_pos < date.length()) {
+ if (date[second_pos] == '.') {
+ size_t third_pos = second_pos + 1;
+ while (third_pos < date.length() && std::isdigit(date[third_pos++]));
+ day = atoi(date.substr(second_pos, third_pos - second_pos).c_str());
+ if (third_pos < date.length())
+ Logger::error("Unexpected string \"", date.substr(third_pos), "\" at the end of date ", date);
+ } else Logger::error("Unexpected character \"", date[second_pos], "\" in date ", date);
+ }
+ } else Logger::error("Unexpected character \"", date[first_pos], "\" in date ", date);
+ }
+ return _dateToTimespan(year, month, day);
+};