TzDateTime enhancements #1473

This commit is contained in:
Alex Ling
2024-09-26 11:41:11 +07:00
committed by Christoffer Lerno
parent bf9ae2f0d3
commit 4cdea865f0
3 changed files with 171 additions and 2 deletions

View File

@@ -20,6 +20,19 @@ fn DateTime from_date(int year, Month month = JANUARY, int day = 1, int hour = 0
return dt;
}
/**
* @require day >= 1 && day < 32
* @require hour >= 0 && hour < 24
* @require min >= 0 && min < 60
* @require sec >= 0 && sec < 60
* @require us >= 0 && us < 999_999
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
**/
fn TzDateTime from_date_tz(int year, Month month = JANUARY, int day = 1, int hour = 0, int min = 0, int sec = 0, int us = 0, int gmt_offset = 0)
{
return from_date(year, month, day, hour, min, sec, us).with_gmt_offset(gmt_offset);
}
fn TzDateTime DateTime.to_local(&self)
{
Tm tm @noinit;
@@ -47,6 +60,57 @@ fn TzDateTime DateTime.to_local(&self)
return dt;
}
/**
* Update timestamp to gmt_offset while keeping the date and time
* values unchanged.
*
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
**/
fn TzDateTime DateTime.with_gmt_offset(self, int gmt_offset)
{
TzDateTime dt = { self, 0 };
return dt.with_gmt_offset(gmt_offset);
}
/**
* Update timestamp to gmt_offset while keeping the date and time
* values unchanged.
*
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
**/
fn TzDateTime TzDateTime.with_gmt_offset(self, int gmt_offset)
{
self.time -= (Time)(gmt_offset - self.gmt_offset) * (Time)time::SEC;
return { self.date_time, gmt_offset };
}
/**
* Update the date and time values to gmt_offset while keeping the
* timestamp unchanged.
*
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
* @ensure self.time == return.time
**/
fn TzDateTime DateTime.to_gmt_offset(self, int gmt_offset)
{
TzDateTime dt = { self, 0 };
return dt.to_gmt_offset(gmt_offset);
}
/**
* Update the date and time values to gmt_offset while keeping the
* timestamp unchanged.
*
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
* @ensure self.time == return.time
**/
fn TzDateTime TzDateTime.to_gmt_offset(self, int gmt_offset) {
Time time = self.time + (Time)(gmt_offset - self.gmt_offset) * (Time)time::SEC;
DateTime dt = from_time(time);
dt.time = self.time;
return { dt, gmt_offset };
}
/**
* @require day >= 1 && day < 32
* @require hour >= 0 && hour < 24
@@ -121,6 +185,16 @@ fn DateTime DateTime.add_months(&self, int months)
return from_date(year, (Month)month, self.day, self.hour, self.min, self.sec, self.usec);
}
fn TzDateTime TzDateTime.add_seconds(&self, int seconds) => self.date_time.add_seconds(seconds).to_gmt_offset(self.gmt_offset);
fn TzDateTime TzDateTime.add_minutes(&self, int minutes) => self.date_time.add_minutes(minutes).to_gmt_offset(self.gmt_offset);
fn TzDateTime TzDateTime.add_hours(&self, int hours) => self.date_time.add_hours(hours).to_gmt_offset(self.gmt_offset);
fn TzDateTime TzDateTime.add_days(&self, int days) => self.date_time.add_days(days).to_gmt_offset(self.gmt_offset);
fn TzDateTime TzDateTime.add_weeks(&self, int weeks) => self.date_time.add_weeks(weeks).to_gmt_offset(self.gmt_offset);
fn TzDateTime TzDateTime.add_years(&self, int years) => self.date_time.add_years(years).with_gmt_offset(self.gmt_offset);
fn TzDateTime TzDateTime.add_months(&self, int months) => self.date_time.add_months(months).with_gmt_offset(self.gmt_offset);
fn DateTime from_time(Time time)
{
DateTime dt @noinit;
@@ -128,6 +202,15 @@ fn DateTime from_time(Time time)
return dt;
}
/**
* @require gmt_offset >= -12 * 3600 && gmt_offset <= 14 * 3600
* @ensure time == return.time
**/
fn TzDateTime from_time_tz(Time time, int gmt_offset)
{
return from_time(time).to_gmt_offset(gmt_offset);
}
fn Time DateTime.to_time(&self) @inline
{
return self.time;
@@ -167,4 +250,4 @@ fn double DateTime.diff_sec(self, DateTime from)
fn Duration DateTime.diff_us(self, DateTime from)
{
return self.time.diff_us(from.time);
}
}

View File

@@ -70,6 +70,7 @@
- Add `io::read_new_fully` for reading to the end of a stream.
- Add `io::wrap_bytes` for reading bytes with `io` functions.
- Add `rnd` and `rand_in_range` default random functions.
- Additional timezone related functions for `datetime`.
## 0.6.2 Change list

View File

@@ -42,4 +42,89 @@ DateTime d = datetime::from_date(1973, APRIL, 27);
x = d.add_months(0);
assert(x.year == 1975);
assert(x.month == MAY);
}
}
fn void test_timezone()
{
int offset_hours = 7;
int offset = offset_hours * 3600;
DateTime d1 = datetime::from_date(2022, OCTOBER, 15);
TzDateTime d2 = datetime::from_date_tz(2022, OCTOBER, 15, gmt_offset: offset);
DateTime dt;
TzDateTime tz;
Time t1 = d1.time;
Time t2 = d2.time;
assert(t1 == 1665792000000000);
assert(t2 == 1665766800000000);
// to_gmt_offset should keep the timesampt value
tz = d1.to_gmt_offset(offset);
assert(tz.time == t1);
assert(tz.year == 2022);
assert(tz.month == OCTOBER);
assert(tz.day == 15);
assert(tz.hour == offset_hours);
assert(tz.min == 0);
assert(tz.gmt_offset == offset);
// with_gmt_offset should keep the date/time values and adjust the timestamp
tz = d1.with_gmt_offset(offset);
assert(tz.time == t2);
assert(tz.year == d1.year);
assert(tz.month == d1.month);
assert(tz.day == d1.day);
assert(tz.hour == d1.hour);
assert(tz.min == d1.min);
assert(tz.gmt_offset == offset);
dt = datetime::from_time(t1);
assert(dt.day == 15);
assert(dt.hour == 0);
dt = datetime::from_time(t2);
assert(dt.day == 14);
assert(dt.hour == 24 - offset_hours);
// from_time_tz should keep the timesampt value
tz = datetime::from_time_tz(t1, offset);
assert(tz.time == t1);
assert(tz.day == 15);
assert(tz.hour == offset_hours);
assert(tz.gmt_offset == offset);
tz = datetime::from_time_tz(t2, offset);
assert(tz.time == t2);
assert(tz.day == 15);
assert(tz.hour == 0);
assert(tz.gmt_offset == offset);
// The add_* methods should adjust the targeted date/time values while
// keeping the others unchanged. The gmt_offset should be kept as well.
dt = d1.add_hours(1);
assert(dt.day == 15);
assert(dt.hour == 1);
tz = d2.add_hours(1);
assert(tz.day == 15);
assert(tz.hour == 1);
assert(tz.gmt_offset == offset);
dt = d1.add_days(1);
assert(dt.day == 16);
assert(dt.hour == 0);
tz = d2.add_days(1);
assert(tz.day == 16);
assert(tz.hour == 0);
assert(tz.gmt_offset == offset);
dt = d1.add_months(1);
assert(dt.month == NOVEMBER);
assert(dt.day == 15);
assert(dt.hour == 0);
tz = d2.add_months(1);
assert(tz.month == NOVEMBER);
assert(tz.day == 15);
assert(tz.hour == 0);
assert(tz.gmt_offset == offset);
}