Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions src/eckit/types/Date.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

begin is a verb, not a noun.

You want 'startOfMonth', (and equivalently for other places you have used 'begin' in this file).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I fully agree; I am usually really bad in choosing names

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_);
Expand Down
24 changes: 24 additions & 0 deletions src/eckit/types/Date.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Comment on lines +114 to +124
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Date gains non-trivial calendar logic (leap-year, days-in-month, month/year shifting with day clamping, begin/end of month/year). There doesn’t seem to be direct unit test coverage for Date behavior in the test suite; please add tests for edge cases like shifting from Jan 31 to Feb, leap years (Feb 29), and negative month shifts.

Copilot uses AI. Check for mistakes.

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&);

Expand Down Expand Up @@ -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_); }
Expand Down
180 changes: 180 additions & 0 deletions src/eckit/types/DateTime.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading
Loading