From 574d4740f88044b3164a9d83656d454d246f225b Mon Sep 17 00:00:00 2001 From: Mirco Valentini Date: Mon, 23 Mar 2026 11:07:33 +0000 Subject: [PATCH] Interface proposal --- src/eckit/types/Date.cc | 118 +++++++++++++++++++++++ src/eckit/types/Date.h | 24 +++++ src/eckit/types/DateTime.cc | 180 ++++++++++++++++++++++++++++++++++++ src/eckit/types/DateTime.h | 47 ++++++++++ src/eckit/types/Time.cc | 99 ++++++++++++++++++++ src/eckit/types/Time.h | 20 ++++ 6 files changed, 488 insertions(+) diff --git a/src/eckit/types/Date.cc b/src/eckit/types/Date.cc index 478b55e64..c02ed5b69 100644 --- a/src/eckit/types/Date.cc +++ b/src/eckit/types/Date.cc @@ -271,6 +271,124 @@ long Date::dateToJulian(long ddate) { return (j1); } +bool Date::isLeapYear(long year) { + return ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0)); +} + +bool Date::isLeap() const { + return isLeapYear(year()); +} + +long Date::numberOfDaysInMonth(long year, long month) { + ASSERT(month >= 1 && month <= 12); + + static const long days[] = { + 31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31 + }; + + if (month == 2 && isLeapYear(year)) { + return 29; + } + + return days[month - 1]; +} + +long Date::numberOfDaysInMonth() const { + return numberOfDaysInMonth(year(), month()); +} + +Date& Date::shiftMonths(long n) { + long y = year(); + long m = month(); + long d = day(); + + long total = (m - 1) + n; + long newYear = y + total / 12; + long newMonth = total % 12; + + if (newMonth < 0) { + newMonth += 12; + --newYear; + } + + newMonth += 1; + + long maxDay = numberOfDaysInMonth(newYear, newMonth); + if (d > maxDay) { + d = maxDay; + } + + julian_ = dateToJulian(newYear * 10000 + newMonth * 100 + d); + return *this; +} + +Date& Date::shiftYears(long n) { + return shiftMonths(12 * n); +} + +Date& Date::beginOfMonth() { + long y = year(); + long m = month(); + julian_ = dateToJulian(y * 10000 + m * 100 + 1); + return *this; +} + +Date& Date::endOfMonth() { + long y = year(); + long m = month(); + long d = numberOfDaysInMonth(y, m); + julian_ = dateToJulian(y * 10000 + m * 100 + d); + return *this; +} + +Date& Date::beginOfYear() { + long y = year(); + julian_ = dateToJulian(y * 10000 + 101); + return *this; +} + +Date& Date::endOfYear() { + long y = year(); + julian_ = dateToJulian(y * 10000 + 1231); + return *this; +} + +Date Date::withShiftMonths(long n) const { + Date out(*this); + out.shiftMonths(n); + return out; +} + +Date Date::withShiftYears(long n) const { + Date out(*this); + out.shiftYears(n); + return out; +} + +Date Date::withBeginOfMonth() const { + Date out(*this); + out.beginOfMonth(); + return out; +} + +Date Date::withEndOfMonth() const { + Date out(*this); + out.endOfMonth(); + return out; +} + +Date Date::withBeginOfYear() const { + Date out(*this); + out.beginOfYear(); + return out; +} + +Date Date::withEndOfYear() const { + Date out(*this); + out.endOfYear(); + return out; +} void Date::print(std::ostream& s) const { long ddate = julianToDate(julian_); diff --git a/src/eckit/types/Date.h b/src/eckit/types/Date.h index 2543ab0e2..99c8d9ee2 100644 --- a/src/eckit/types/Date.h +++ b/src/eckit/types/Date.h @@ -111,6 +111,27 @@ class Date { std::string monthName() const; long dayOfWeek() const { return julian_ % 7; } + bool isLeap() const; + long numberOfDaysInMonth() const; + + Date& shiftMonths(long n = 1); + Date& shiftYears(long n = 1); + + Date& beginOfMonth(); + Date& endOfMonth(); + + Date& beginOfYear(); + Date& endOfYear(); + + Date withShiftMonths(long n = 1) const; + Date withShiftYears(long n = 1) const; + + Date withBeginOfMonth() const; + Date withEndOfMonth() const; + + Date withBeginOfYear() const; + Date withEndOfYear() const; + void dump(DumpLoad&) const; void load(DumpLoad&); @@ -147,6 +168,9 @@ class Date { static long dateToJulian(long); static long today(); + static bool isLeapYear(long year); + static long numberOfDaysInMonth(long year, long month); + // -- Friends friend long operator-(const Date& d1, const Date& d2) { return (d1.julian_ - d2.julian_); } diff --git a/src/eckit/types/DateTime.cc b/src/eckit/types/DateTime.cc index 2a725e584..ce5b2bcd2 100644 --- a/src/eckit/types/DateTime.cc +++ b/src/eckit/types/DateTime.cc @@ -149,6 +149,186 @@ DateTime DateTime::round(const Second& rnd) const { return DateTime(Date(d, true), Time(t)); } +bool DateTime::isLeap() const { + return date_.isLeap(); +} + +long DateTime::numberOfDaysInMonth() const { + return date_.numberOfDaysInMonth(); +} + +DateTime& DateTime::shiftSeconds(long n) { + long dummy; + return shiftSeconds(n, dummy); +} + +DateTime& DateTime::shiftSeconds(long n, long& dayCarry) { + time_.shiftSeconds(n, dayCarry); + date_ += dayCarry; + return *this; +} + +DateTime& DateTime::shiftMinutes(long n) { + long dummy; + return shiftMinutes(n, dummy); +} + +DateTime& DateTime::shiftMinutes(long n, long& dayCarry) { + time_.shiftMinutes(n, dayCarry); + date_ += dayCarry; + return *this; +} + +DateTime& DateTime::shiftHours(long n) { + long dummy; + return shiftHours(n, dummy); +} + +DateTime& DateTime::shiftHours(long n, long& dayCarry) { + time_.shiftHours(n, dayCarry); + date_ += dayCarry; + return *this; +} + +DateTime& DateTime::shiftDays(long n) { + date_ += n; + return *this; +} + +DateTime& DateTime::shiftMonths(long n) { + date_.shiftMonths(n); + return *this; +} + +DateTime& DateTime::shiftYears(long n) { + date_.shiftYears(n); + return *this; +} + +DateTime& DateTime::beginOfDay() { + time_ = Time(0, 0, 0); + return *this; +} + +DateTime& DateTime::endOfDay() { + time_ = Time(23, 59, 59); + return *this; +} + +DateTime& DateTime::beginOfMonth() { + date_.beginOfMonth(); + time_ = Time(0, 0, 0); + return *this; +} + +DateTime& DateTime::endOfMonth() { + date_.endOfMonth(); + time_ = Time(23, 59, 59); + return *this; +} + +DateTime& DateTime::beginOfYear() { + date_.beginOfYear(); + time_ = Time(0, 0, 0); + return *this; +} + +DateTime& DateTime::endOfYear() { + date_.endOfYear(); + time_ = Time(23, 59, 59); + return *this; +} + +DateTime DateTime::withShiftSeconds(long n) const { + DateTime out(*this); + out.shiftSeconds(n); + return out; +} + +DateTime DateTime::withShiftSeconds(long n, long& dayCarry) const { + DateTime out(*this); + out.shiftSeconds(n, dayCarry); + return out; +} + +DateTime DateTime::withShiftMinutes(long n) const { + DateTime out(*this); + out.shiftMinutes(n); + return out; +} + +DateTime DateTime::withShiftMinutes(long n, long& dayCarry) const { + DateTime out(*this); + out.shiftMinutes(n, dayCarry); + return out; +} + +DateTime DateTime::withShiftHours(long n) const { + DateTime out(*this); + out.shiftHours(n); + return out; +} + +DateTime DateTime::withShiftHours(long n, long& dayCarry) const { + DateTime out(*this); + out.shiftHours(n, dayCarry); + return out; +} + +DateTime DateTime::withShiftDays(long n) const { + DateTime out(*this); + out.shiftDays(n); + return out; +} + +DateTime DateTime::withShiftMonths(long n) const { + DateTime out(*this); + out.shiftMonths(n); + return out; +} + +DateTime DateTime::withShiftYears(long n) const { + DateTime out(*this); + out.shiftYears(n); + return out; +} + +DateTime DateTime::withBeginOfDay() const { + DateTime out(*this); + out.beginOfDay(); + return out; +} + +DateTime DateTime::withEndOfDay() const { + DateTime out(*this); + out.endOfDay(); + return out; +} + +DateTime DateTime::withBeginOfMonth() const { + DateTime out(*this); + out.beginOfMonth(); + return out; +} + +DateTime DateTime::withEndOfMonth() const { + DateTime out(*this); + out.endOfMonth(); + return out; +} + +DateTime DateTime::withBeginOfYear() const { + DateTime out(*this); + out.beginOfYear(); + return out; +} + +DateTime DateTime::withEndOfYear() const { + DateTime out(*this); + out.endOfYear(); + return out; +} + void DateTime::dump(DumpLoad& a) const { date_.dump(a); time_.dump(a); diff --git a/src/eckit/types/DateTime.h b/src/eckit/types/DateTime.h index 38c3ab117..216576cbe 100644 --- a/src/eckit/types/DateTime.h +++ b/src/eckit/types/DateTime.h @@ -69,6 +69,53 @@ class DateTime { DateTime round(const Second& seconds) const; + bool isLeap() const; + long numberOfDaysInMonth() const; + + DateTime& shiftSeconds(long n = 1); + DateTime& shiftSeconds(long n, long& dayCarry); + + DateTime& shiftMinutes(long n = 1); + DateTime& shiftMinutes(long n, long& dayCarry); + + DateTime& shiftHours(long n = 1); + DateTime& shiftHours(long n, long& dayCarry); + + DateTime& shiftDays(long n = 1); + DateTime& shiftMonths(long n = 1); + DateTime& shiftYears(long n = 1); + + DateTime& beginOfDay(); + DateTime& endOfDay(); + + DateTime& beginOfMonth(); + DateTime& endOfMonth(); + + DateTime& beginOfYear(); + DateTime& endOfYear(); + + DateTime withShiftSeconds(long n = 1) const; + DateTime withShiftSeconds(long n, long& dayCarry) const; + + DateTime withShiftMinutes(long n = 1) const; + DateTime withShiftMinutes(long n, long& dayCarry) const; + + DateTime withShiftHours(long n = 1) const; + DateTime withShiftHours(long n, long& dayCarry) const; + + DateTime withShiftDays(long n = 1) const; + DateTime withShiftMonths(long n = 1) const; + DateTime withShiftYears(long n = 1) const; + + DateTime withBeginOfDay() const; + DateTime withEndOfDay() const; + + DateTime withBeginOfMonth() const; + DateTime withEndOfMonth() const; + + DateTime withBeginOfYear() const; + DateTime withEndOfYear() const; + void dump(DumpLoad&) const; void load(DumpLoad&); diff --git a/src/eckit/types/Time.cc b/src/eckit/types/Time.cc index ec0fa45ae..3b6591407 100644 --- a/src/eckit/types/Time.cc +++ b/src/eckit/types/Time.cc @@ -305,6 +305,105 @@ Time::Time(long hh, long mm, long ss, bool extended) : seconds_(hh * 3600 + mm * } Time::~Time() {} +namespace { + inline long computeDayCarry(long total, long day) { + long carry = total / day; + long rem = total % day; + + if (rem < 0) { + rem += day; + --carry; + } + return carry; + } + + inline long normalizeSeconds(long total, long day) { + long rem = total % day; + if (rem < 0) rem += day; + return rem; + } +} + +// --- shiftSeconds --- + +Time& Time::shiftSeconds(long n) { + long dummy; + return shiftSeconds(n, dummy); +} + +Time& Time::shiftSeconds(long n, long& dayCarry) { + const long day = static_cast(secondsInDay); + const long total = std::lround(seconds_) + n; + + dayCarry = computeDayCarry(total, day); + seconds_ = normalizeSeconds(total, day); + + return *this; +} + +// --- shiftMinutes --- + +Time& Time::shiftMinutes(long n) { + long dummy; + return shiftMinutes(n, dummy); +} + +Time& Time::shiftMinutes(long n, long& dayCarry) { + return shiftSeconds(static_cast(secondsInMinute) * n, dayCarry); +} + +// --- shiftHours --- + +Time& Time::shiftHours(long n) { + long dummy; + return shiftHours(n, dummy); +} + +Time& Time::shiftHours(long n, long& dayCarry) { + return shiftSeconds(static_cast(secondsInHour) * n, dayCarry); +} + +// --- withShiftSeconds --- + +Time Time::withShiftSeconds(long n) const { + Time out(*this); + out.shiftSeconds(n); + return out; +} + +Time Time::withShiftSeconds(long n, long& dayCarry) const { + Time out(*this); + out.shiftSeconds(n, dayCarry); + return out; +} + +// --- withShiftMinutes --- + +Time Time::withShiftMinutes(long n) const { + Time out(*this); + out.shiftMinutes(n); + return out; +} + +Time Time::withShiftMinutes(long n, long& dayCarry) const { + Time out(*this); + out.shiftMinutes(n, dayCarry); + return out; +} + +// --- withShiftHours --- + +Time Time::withShiftHours(long n) const { + Time out(*this); + out.shiftHours(n); + return out; +} + +Time Time::withShiftHours(long n, long& dayCarry) const { + Time out(*this); + out.shiftHours(n, dayCarry); + return out; +} bool Time::operator==(const Time& other) const { return seconds_ == other.seconds_; diff --git a/src/eckit/types/Time.h b/src/eckit/types/Time.h index cd562214c..d2ba7a075 100644 --- a/src/eckit/types/Time.h +++ b/src/eckit/types/Time.h @@ -92,6 +92,24 @@ class Time { long seconds() const; long hhmmss() const; + Time& shiftSeconds(long n); + Time& shiftSeconds(long n, long& dayCarry); + + Time& shiftMinutes(long n); + Time& shiftMinutes(long n, long& dayCarry); + + Time& shiftHours(long n); + Time& shiftHours(long n, long& dayCarry); + + Time withShiftSeconds(long n) const; + Time withShiftSeconds(long n, long& dayCarry) const; + + Time withShiftMinutes(long n) const; + Time withShiftMinutes(long n, long& dayCarry) const; + + Time withShiftHours(long n) const; + Time withShiftHours(long n, long& dayCarry) const; + void dump(DumpLoad&) const; void load(DumpLoad&); @@ -107,6 +125,8 @@ class Time { Second seconds_; + friend class DateTime; + friend std::ostream& operator<<(std::ostream& s, const Time& t) { t.print(s); return s;