commit 5ed9597e4031c90fbbe95d1058426a0e436ff887
parent d25645eef01a73b83e77bfb2f3d777833676140e
Author: Byron Torres <b@torresjrjr.com>
Date: Mon, 8 Apr 2024 23:58:00 +0100
time::date: implement zflag in new()
Diffstat:
M | time/date/date.ha | | | 100 | +++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- |
1 file changed, 60 insertions(+), 40 deletions(-)
diff --git a/time/date/date.ha b/time/date/date.ha
@@ -88,7 +88,7 @@ fn all(d: *date) *date = {
return d;
};
-// Creates a new [[date]]. Accepts a [[time::chrono::locality]], a zone offset,
+// Creates a new [[date]]. Accepts a [[time::chrono::locality]], a zone-offset,
// and up to seven nominal fields applied in the following order:
//
// - year
@@ -102,52 +102,66 @@ fn all(d: *date) *date = {
// 8 or more fields causes an abort. If omitted, the month and day default to 1,
// and the rest default to 0.
//
-// The locality and zone offset parameters discern the desired observed
-// [[time::chrono::zone]]. See [[time::chrono::fixedzone]] for custom timezones.
+// If the desired zone-offset is known, it can be given as a [[time::duration]].
+// Otherwise, use a zflag. See [[zflag]] on its effects to the result.
//
// An invalid combination of provided date/time/zoff values returns [[invalid]].
//
// Examples:
//
// // 0000-01-01 00:00:00.000000000 +0000 UTC UTC
-// date::new(time::chrono::UTC, 0);
+// date::new(time::chrono::UTC, date::zflag::CONTIG);
//
-// // 2019-12-27 20:07:08.000031415 +0000 UTC UTC
+// // 2000-01-02 15:04:05.600000000 +0000 UTC UTC
// date::new(time::chrono::UTC, 0,
-// 2019, 12, 27, 20, 7, 8, 31415);
+// 2000, 1, 2, 15, 4, 5, 600000000);
//
-// // 2019-12-27 21:00:00.000000000 +0100 CET Europe/Amsterdam
-// date::new(time::chrono::tz("Europe/Amsterdam")!, 1 * time::HOUR,
-// 2019, 12, 27, 21);
+// // 2000-01-02 15:00:00.000000000 +0100 CET Europe/Amsterdam
+// date::new(time::chrono::tz("Europe/Amsterdam")!,
+// 1 * time::HOUR, // standard time in January
+// 2000, 1, 2, 15);
//
-// // 2019-12-27 10:00:00.000000000 -1000 HST Pacific/Honolulu
-// date::new(time::chrono::tz("Pacific/Honolulu")!, -10 * time::HOUR,
-// 2019, 12, 27, 10);
+// // Could return [[zfunresolved]] by encountering a timezone transition.
+// date::new(time::chrono::tz("Europe/Amsterdam")!,
+// date::zflag::CONTIG,
+// fields...);
//
-// // Invalid month, day, hour, and minute
-// date::new(time::chrono::UTC, 0,
-// 2019, 0, 0, 99, -30);
-//
-// // Invalid zone offset
-// date::new(time::chrono::UTC, -7 * time::HOUR, 2019);
-// date::new(time::chrono::tz("Europe/Amsterdam")!, 0, 2019);
+// // Will never return [[zfunresolved]].
+// date::new(time::chrono::tz("Europe/Amsterdam")!,
+// date::zflag::LAP_EARLY | date::zflag::GAP_END,
+// fields...);
//
-// Example: Two dates, 30 physical minutes before and after a DST timezone
-// transition, observing the same date & time, but different zone offsets:
+// // On this day in Amsterdam, the clock jumped +1 hour at 02:00.
+// // 02:30 is never observed. Note the difference in zone-offset.
+// //
+// // 2000-03-26 01:59:59.999999999 +0100 CET Europe/Amsterdam
+// date::new(time::chrono::tz("Europe/Amsterdam")!,
+// date::zflag::GAP_START,
+// 2000, 3, 26, 2, 30);
+// //
+// // 2000-03-26 03:00:00.000000000 +0200 CET Europe/Amsterdam
+// date::new(time::chrono::tz("Europe/Amsterdam")!,
+// date::zflag::GAP_END,
+// 2000, 3, 26, 2, 30);
//
-// // 2019-04-07 02:30:00.000000000 +1100 AUDT Australia/Sydney
-// date::new(time::chrono::tz("Australia/Sydney")!, 11 * time::HOUR,
-// 2019, 4, 7, 2, 30);
-//
-// // 2019-04-07 02:30:00.000000000 +1000 AUST Australia/Sydney
-// date::new(time::chrono::tz("Australia/Sydney")!, 10 * time::HOUR,
-// 2019, 4, 7, 2, 30);
+// // On this day in Amsterdam, the clock jumped -1 hour at 03:00.
+// // 02:30 is observed twice. Note the difference in zone-offset.
+// //
+// // 2000-10-29 02:30:00.000000000 +0200 CET Europe/Amsterdam
+// date::new(time::chrono::tz("Europe/Amsterdam")!,
+// date::zflag::LAP_EARLY,
+// 2000, 10, 29, 2, 30);
+// //
+// // 2000-10-29 02:30:00.000000000 +0100 CET Europe/Amsterdam
+// date::new(time::chrono::tz("Europe/Amsterdam")!,
+// date::zflag::LAP_LATE,
+// 2000, 10, 29, 2, 30);
//
export fn new(
loc: chrono::locality,
- zoff: time::duration,
+ zoff: (time::duration | zflag),
fields: int...
-) (date | invalid) = {
+) (date | invalid | zfunresolved) = {
let _fields: [_]int = [
0, 1, 1, // year month day
0, 0, 0, 0, // hour min sec nsec
@@ -169,20 +183,26 @@ export fn new(
v.second = _fields[5];
v.nanosecond = _fields[6];
- let d = (realize(v, loc) as (date | invalid))?;
+ let d = (realize(v, loc) as (date | invalid | zfunresolved))?;
+ // if zflag::GAP_START or zflag::GAP_END was not specified,
// check if input values are actually observed
if (
- zoff != chrono::ozone(&d).zoff
- || _fields[0] != _year(&d)
- || _fields[1] != _month(&d)
- || _fields[2] != _day(&d)
- || _fields[3] != _hour(&d)
- || _fields[4] != _minute(&d)
- || _fields[5] != _second(&d)
- || _fields[6] != _nanosecond(&d)
+ // TODO: check observe values outside of gap?
+ zoff is zflag
+ && zoff as zflag & (zflag::GAP_START | zflag::GAP_END) == 0
) {
- return invalid;
+ if (
+ _fields[0] != _year(&d)
+ || _fields[1] != _month(&d)
+ || _fields[2] != _day(&d)
+ || _fields[3] != _hour(&d)
+ || _fields[4] != _minute(&d)
+ || _fields[5] != _second(&d)
+ || _fields[6] != _nanosecond(&d)
+ ) {
+ return invalid;
+ };
};
return d;