commit bad6a75a6e68b5938bea74c5ceb9fa6d1b8cd3fc
parent d175a565cee80690e09ee41d4a3e0b2beabfae94
Author: Byron Torres <b@torresjrjr.com>
Date: Sun, 19 Dec 2021 15:48:25 +0000
merge date & time, improve tz
Signed-off-by: Byron Torres <b@torresjrjr.com>
Diffstat:
7 files changed, 247 insertions(+), 392 deletions(-)
diff --git a/datetime/calendar.ha b/datetime/calendar.ha
@@ -19,27 +19,27 @@ export def EPOCH_COMMONERA: i64 = -719164;
//
// Evaluates a [[datetime]]'s number of days since the calendar epoch 0000-01-01
-export fn epochal(dt: *datetime) int = {
- match (dt.date.epochal) {
+export fn epochal(dt: *datetime) chrono::epochal = {
+ match (dt.date) {
case void =>
// How to resolve?
// Use calc_epochal_from_*? How to avoid recursion?
// When to rely on input validation?
abort("TODO");
- case let e: int =>
+ case let e: chrono::epochal =>
return e;
};
};
// Evaluates a [[datetime]]'s era
export fn era(dt: *datetime) int = {
- match (dt.date.era) {
+ match (dt.era) {
case void =>
- if (dt.date.year is void) {
- dt.date.year = year(dt);
+ if (dt.year is void) {
+ dt.year = year(dt);
};
- dt.date.era = calc_era(dt.date.year: int);
- return dt.date.era: int;
+ dt.era = calc_era(dt.year: int);
+ return dt.era: int;
case let a: int =>
return a;
};
@@ -47,16 +47,16 @@ export fn era(dt: *datetime) int = {
// Evaluates a [[datetime]]'s year
export fn year(dt: *datetime) int = {
- match (dt.date.year) {
+ match (dt.year) {
case void =>
- if (dt.date.epochal is void) {
+ if (dt.date is void) {
epochal(dt);
};
- const ymd = calc_ymd(dt.date.epochal: int);
- dt.date.year = ymd.0;
- dt.date.month = ymd.1;
- dt.date.day = ymd.2;
- return dt.date.year: int;
+ const ymd = calc_ymd(dt.date: chrono::epochal);
+ dt.year = ymd.0;
+ dt.month = ymd.1;
+ dt.day = ymd.2;
+ return dt.year: int;
case let y: int =>
return y;
};
@@ -64,16 +64,16 @@ export fn year(dt: *datetime) int = {
// Evaluates a [[datetime]]'s month of the year
export fn month(dt: *datetime) int = {
- match (dt.date.month) {
+ match (dt.month) {
case void =>
- if (dt.date.epochal is void) {
+ if (dt.date is void) {
epochal(dt);
};
- const ymd = calc_ymd(dt.date.epochal: int);
- dt.date.year = ymd.0;
- dt.date.month = ymd.1;
- dt.date.day = ymd.2;
- return dt.date.month: int;
+ const ymd = calc_ymd(dt.date: chrono::epochal);
+ dt.year = ymd.0;
+ dt.month = ymd.1;
+ dt.day = ymd.2;
+ return dt.month: int;
case let y: int =>
return y;
};
@@ -81,16 +81,16 @@ export fn month(dt: *datetime) int = {
// Evaluates a [[datetime]]'s day of the month
export fn day(dt: *datetime) int = {
- match (dt.date.day) {
+ match (dt.day) {
case void =>
- if (dt.date.epochal is void) {
+ if (dt.date is void) {
epochal(dt);
};
- const ymd = calc_ymd(dt.date.epochal: int);
- dt.date.year = ymd.0;
- dt.date.month = ymd.1;
- dt.date.day = ymd.2;
- return dt.date.day: int;
+ const ymd = calc_ymd(dt.date: chrono::epochal);
+ dt.year = ymd.0;
+ dt.month = ymd.1;
+ dt.day = ymd.2;
+ return dt.day: int;
case let y: int =>
return y;
};
@@ -98,13 +98,13 @@ export fn day(dt: *datetime) int = {
// Evaluates a [[datetime]]'s day of the week
export fn weekday(dt: *datetime) int = {
- match (dt.date.weekday) {
+ match (dt.weekday) {
case void =>
- if (dt.date.epochal is void) {
+ if (dt.date is void) {
epochal(dt);
};
- dt.date.weekday = calc_weekday(dt.date.epochal: int);
- return dt.date.weekday: int;
+ dt.weekday = calc_weekday(dt.date: chrono::epochal);
+ return dt.weekday: int;
case let y: int =>
return y;
};
@@ -112,23 +112,23 @@ export fn weekday(dt: *datetime) int = {
// Evaluates a [[datetime]]'s ordinal day of the year
export fn yearday(dt: *datetime) int = {
- match (dt.date.yearday) {
+ match (dt.yearday) {
case void =>
- if (dt.date.year is void) {
+ if (dt.year is void) {
year(dt);
};
- if (dt.date.month is void) {
+ if (dt.month is void) {
month(dt);
};
- if (dt.date.day is void) {
+ if (dt.day is void) {
day(dt);
};
- dt.date.yearday = calc_yearday(
- dt.date.year: int,
- dt.date.month: int,
- dt.date.day: int,
+ dt.yearday = calc_yearday(
+ dt.year: int,
+ dt.month: int,
+ dt.day: int,
);
- return dt.date.yearday: int;
+ return dt.yearday: int;
case let yd: int =>
return yd;
};
@@ -136,27 +136,27 @@ export fn yearday(dt: *datetime) int = {
// Evaluates a [[datetime]]'s ISO week-numbering year
export fn isoweekyear(dt: *datetime) int = {
- match (dt.date.isoweekyear) {
+ match (dt.isoweekyear) {
case void =>
- if (dt.date.year is void) {
+ if (dt.year is void) {
year(dt);
};
- if (dt.date.month is void) {
+ if (dt.month is void) {
month(dt);
};
- if (dt.date.day is void) {
+ if (dt.day is void) {
day(dt);
};
- if (dt.date.weekday is void) {
+ if (dt.weekday is void) {
weekday(dt);
};
- dt.date.isoweekyear = calc_isoweekyear(
- dt.date.year: int,
- dt.date.month: int,
- dt.date.day: int,
- dt.date.weekday: int,
+ dt.isoweekyear = calc_isoweekyear(
+ dt.year: int,
+ dt.month: int,
+ dt.day: int,
+ dt.weekday: int,
);
- return dt.date.isoweekyear: int;
+ return dt.isoweekyear: int;
case let iwy: int =>
return iwy;
};
@@ -164,19 +164,19 @@ export fn isoweekyear(dt: *datetime) int = {
// Evaluates a [[datetime]]'s Gregorian week
export fn week(dt: *datetime) int = {
- match (dt.date.week) {
+ match (dt.week) {
case void =>
- if (dt.date.yearday is void) {
+ if (dt.yearday is void) {
yearday(dt);
};
- if (dt.date.weekday is void) {
+ if (dt.weekday is void) {
weekday(dt);
};
- dt.date.week = calc_week(
- dt.date.yearday: int,
- dt.date.weekday: int,
+ dt.week = calc_week(
+ dt.yearday: int,
+ dt.weekday: int,
);
- return dt.date.week: int;
+ return dt.week: int;
case let w: int =>
return w;
};
@@ -184,27 +184,27 @@ export fn week(dt: *datetime) int = {
// Evaluates a [[datetime]]'s ISO week
export fn isoweek(dt: *datetime) int = {
- match (dt.date.isoweek) {
+ match (dt.isoweek) {
case void =>
- if (dt.date.year is void) {
+ if (dt.year is void) {
year(dt);
};
- if (dt.date.week is void) {
+ if (dt.week is void) {
week(dt);
};
- if (dt.date.weekday is void) {
+ if (dt.weekday is void) {
weekday(dt);
};
- if (dt.date.yearday is void) {
+ if (dt.yearday is void) {
yearday(dt);
};
- dt.date.isoweek = calc_isoweek(
- dt.date.year: int,
- dt.date.week: int,
- dt.date.weekday: int,
- dt.date.yearday: int,
+ dt.isoweek = calc_isoweek(
+ dt.year: int,
+ dt.week: int,
+ dt.weekday: int,
+ dt.yearday: int,
);
- return dt.date.isoweek: int;
+ return dt.isoweek: int;
case let iw: int =>
return iw;
};
@@ -217,7 +217,7 @@ export fn isoweek(dt: *datetime) int = {
// Evaluates a [[datetime]]'s hour of the day
export fn hour(dt: *datetime) int = {
- match (dt.time.hour) {
+ match (dt.hour) {
case void =>
abort("TODO");
case let h: int =>
@@ -227,7 +227,7 @@ export fn hour(dt: *datetime) int = {
// Evaluates a [[datetime]]'s minute of the hour
export fn min(dt: *datetime) int = {
- match (dt.time.min) {
+ match (dt.min) {
case void =>
abort("TODO");
case let m: int =>
@@ -237,7 +237,7 @@ export fn min(dt: *datetime) int = {
// Evaluates a [[datetime]]'s second of the minute
export fn sec(dt: *datetime) int = {
- match (dt.time.sec) {
+ match (dt.sec) {
case void =>
abort("TODO");
case let s: int =>
@@ -247,40 +247,10 @@ export fn sec(dt: *datetime) int = {
// Evaluates a [[datetime]]'s nanosecond of the second
export fn nsec(dt: *datetime) int = {
- match (dt.time.nsec) {
+ match (dt.nsec) {
case void =>
abort("TODO");
case let n: int =>
return n;
};
};
-
-// // Converts a [[datetime]] to a [[chrono::moment]].
-// // Fails if there is insufficient information in the [[datetime]].
-// export fn conv_datetime_moment(dt: datetime) (chrono::moment | errors::invalid) = {
-// const d = conv_localdate_epochal(dt.date)?;
-// const t = conv_localtime_time(dt.time)?;
-// const m = chrono::moment {
-// date = d,
-// time = t,
-// loc = chrono::local, // TODO
-// };
-// return m;
-// };
-
-// // Converts a [[chrono::moment]] to a [[datetime]]
-// export fn conv_moment_datetime(m: chrono::moment, dt: *datetime) void = {
-// conv_epochal_localdate(m.date, &(dt.date), &localdate {
-// // TODO: reconcile, add more fields when ready
-// year = 0,
-// month = 0,
-// day = 0,
-// ...
-// });
-//
-// const lt = conv_time_localtime(m.time);
-// dt.time = lt;
-//
-// dt.loc = chrono::local; // TODO
-// return dt;
-// };
diff --git a/datetime/date.ha b/datetime/date.ha
@@ -1,32 +1,6 @@
use errors;
use time::chrono;
-export type localdate = struct {
- epochal: (void | int),
- era: (void | int),
- year: (void | int),
- month: (void | int),
- day: (void | int),
- yearday: (void | int),
- isoweekyear: (void | int),
- isoweek: (void | int),
- week: (void | int),
- weekday: (void | int),
-};
-
-fn init_date() localdate = localdate {
- epochal = void,
- era = void,
- year = void,
- month = void,
- day = void,
- yearday = void,
- isoweekyear = void,
- isoweek = void,
- week = void,
- weekday = void,
-};
-
// Calculates whether a given year is a leap year.
export fn is_leap_year(y: int) bool = {
return if (y % 4 != 0) false
@@ -45,7 +19,7 @@ fn calc_era(y: int) int = {
};
// Calculates the (year, month, day), given an epochal day
-fn calc_ymd(e: int) (int, int, int) = {
+fn calc_ymd(e: chrono::epochal) (int, int, int) = {
// Algorithm adapted from:
// https://en.wikipedia.org/wiki/Julian_day#Julian_or_Gregorian_calendar_from_Julian_day_number
//
@@ -201,73 +175,3 @@ fn calc_epochal_from_yd(y: int, yd: int) (chrono::epochal | errors::invalid) = {
// TODO
return 0;
};
-
-// // Converts a [[chrono::epochal]] to a [[localdate]]. The fields in "date" are
-// // populated acording to which fields in "want" are non-void.
-// //
-// // let date = localdate { ... };
-// // let want = localdate { year=0, month=0, day=0, ... };
-// // conv_epochal_localdate(10724, &date, &want);
-// // assert(date == localdate { year=1999, month=5, day=13, ... });
-// //
-// export fn conv_epochal_localdate(
-// e: chrono::epochal,
-// date: *localdate,
-// want: *localdate,
-// ) void = {
-// if (want.year is int || want.month is int || want.day is int) {
-// const ymd = calc_ymd(e: int);
-// date.year = ymd.0;
-// date.month = ymd.1;
-// date.day = ymd.2;
-// };
-//
-// if (want.yearday is int) {
-// if (date.year is void || date.month is void || date.day is void) {
-// const ymd = calc_ymd(e: int);
-// date.year = ymd.0;
-// date.month = ymd.1;
-// date.day = ymd.2;
-// };
-// calc_yearday(date.year: int, date.month: int, date.day: int);
-// };
-//
-// if (want.week is int) {
-// // TODO
-// //calc_isoweek(e);
-// void;
-// };
-//
-// if (want.weekday is int) {
-// date.weekday = calc_weekday(e);
-// };
-// };
-
-// // Converts a [[localdate]] to a [[chrono::epochal]].
-// // Fails if there is insufficient information in the given [[localdate]].
-// export fn conv_localdate_epochal(ld: localdate) (chrono::epochal | errors::invalid) = {
-// if (
-// ld.year is int
-// && ld.month is int
-// && ld.day is int
-// ) {
-// return calc_epochal_from_ymd(
-// ld.year: int,
-// ld.month: int,
-// ld.day: int,
-// );
-// } else if (
-// ld.year is int
-// && ld.week is int
-// && ld.weekday is int
-// ) {
-// return 0; // TODO
-// } else if (
-// ld.year is int
-// && ld.yearday is int
-// ) {
-// return 0; // TODO
-// };
-//
-// return errors::invalid;
-// };
diff --git a/datetime/datetime.ha b/datetime/datetime.ha
@@ -5,15 +5,47 @@ use time::chrono;
// Represents a datetime; a single, reasonably unique moment in time, specified
// by a calendar date and a wallclock time, contextualised within a locality.
export type datetime = struct {
- date: localdate,
- time: localtime,
- loc: locality,
+ date: (void | chrono::epochal),
+ time: (void | time::duration),
+ loc: chrono::locality,
+
+ era: (void | int),
+ year: (void | int),
+ month: (void | int),
+ day: (void | int),
+ yearday: (void | int),
+ isoweekyear: (void | int),
+ isoweek: (void | int),
+ week: (void | int),
+ weekday: (void | int),
+
+ hour: (void | int),
+ min: (void | int),
+ sec: (void | int),
+ nsec: (void | int),
};
-fn init_datetime() datetime = datetime {
- date = init_date(),
- time = init_time(),
- loc = chrono::local,
+
+
+fn init() datetime = datetime {
+ date = void,
+ time = void,
+ loc = chrono::locality{ timezone = chrono::local, ... },
+
+ era = void,
+ year = void,
+ month = void,
+ day = void,
+ yearday = void,
+ isoweekyear = void,
+ isoweek = void,
+ week = void,
+ weekday = void,
+
+ hour = void,
+ min = void,
+ sec = void,
+ nsec = void,
};
// Creates a new datetime
@@ -29,32 +61,27 @@ export fn new(
min: int,
sec: int,
nsec: int,
- loc: locality,
+ loc: chrono::locality,
) (datetime | errors::invalid) = {
const dt = datetime {
- date = localdate {
- epochal = void,
- era = void,
- year = year,
- month = month,
- day = day,
- isoweekyear = void,
- isoweek = void,
- week = void,
- weekday = void,
- yearday = void,
- },
- time = localtime {
- lapsed = void,
- hour = hour,
- min = min,
- sec = sec,
- nsec = nsec,
- },
- loc = loc,
- };
- if (!validate(dt)) {
- return errors::invalid;
+ date = calc_epochal_from_ymd(year, month, day)?,
+ time = calc_time_from_hmsn(hour, min, sec, nsec)?,
+ loc = loc,
+
+ era = void,
+ year = year,
+ month = month,
+ day = day,
+ isoweekyear = void,
+ isoweek = void,
+ week = void,
+ weekday = void,
+ yearday = void,
+
+ hour = hour,
+ min = min,
+ sec = sec,
+ nsec = nsec,
};
return dt;
};
@@ -62,67 +89,38 @@ export fn new(
// Returns the current datetime
export fn now() datetime = {
const i = time::now(time::clock::REALTIME);
- const u = time::unix(i);
- const d = (u / 86400);
- const ld = init_date();
- ld.epochal = d: int;
+ const unix = time::unix(i);
+ const daynum = (unix / 86400);
+ const date = calc_ymd(daynum);
const dt = datetime {
- date = ld,
- time = localtime {
- lapsed = ((i.sec / 86400) * time::NANOSECOND + i.nsec): int,
- hour = (i.sec / 3600): int % 24,
- min = (i.sec / 60): int % 60,
- sec = i.sec: int % 60,
- nsec = i.nsec: int,
- },
+ date = daynum,
+ time = ((i.sec / 86400) * time::NANOSECOND + i.nsec),
// TODO: What to do here? How to get the timezone from
// /etc/localtime or $TZ? How to determine the system's
// timescale? Assuming UTC may be sufficient.
- loc = chrono::local,
+ loc = chrono::locality{ timezone = chrono::local, ... },
+
+ era = void,
+ year = date.0,
+ month = date.1,
+ day = date.2,
+ isoweekyear = void,
+ isoweek = void,
+ week = void,
+ weekday = void,
+ yearday = void,
+
+ hour = (i.sec / 3600): int % 24,
+ min = (i.sec / 60): int % 60,
+ sec = i.sec: int % 60,
+ nsec = i.nsec: int,
};
return dt;
};
// Validates a datetime's internal date & time values
-export fn validate(dt: (datetime | localdate | localtime)) bool = {
+export fn validate(dt: datetime) bool = {
// TODO
return true;
};
-
-// // Creates a new moment
-// //
-// // // 1995 July 18th 09:16:00.000
-// // datetime::new_moment(1995, 07, 18, 9, 16, 0, 0, chrono::local)
-// //
-// // For alternative forms, assemble a datetime manually using the desired types.
-// export fn new_moment(
-// year: int,
-// month: int,
-// day: int,
-// hour: int,
-// min: int,
-// sec: int,
-// nsec: int,
-// loc: locality,
-// ) (chrono::moment | errors::invalid) = {
-// const dt = new(year, month, day, hour, min, sec, nsec, loc)?;
-// const m = conv_datetime_moment(dt)?;
-// return m;
-// };
-
-// // Returns the current moment
-// export fn now_moment() chrono::moment = {
-// const i = time::now(time::clock::REALTIME);
-// const u = time::unix(i);
-// const d = (u / 86400);
-// const t = (
-// (i.sec * time::SECOND) + (i.nsec * time::NANOSECOND)
-// ) % (24 * time::HOUR);
-// const m = chrono::moment {
-// date = d,
-// time = t,
-// loc = chrono::local,
-// };
-// return m;
-// };
diff --git a/datetime/format.ha b/datetime/format.ha
@@ -85,35 +85,35 @@ export fn strptime(fmt: str, s: str, dt: *datetime) (void | errors::invalid) = {
// Basic specifiers
case 'a' =>
// TODO: Localization
- dt.date.weekday = get_default_locale_string_index(
+ dt.weekday = get_default_locale_string_index(
&s_iter, WEEKDAYS_SHORT[..])?;
case 'A' =>
// TODO: Localization
- dt.date.weekday = get_default_locale_string_index(
+ dt.weekday = get_default_locale_string_index(
&s_iter, WEEKDAYS[..])?;
case 'b', 'h' =>
// TODO: Localization
- dt.date.month = get_default_locale_string_index(
+ dt.month = get_default_locale_string_index(
&s_iter, MONTHS_SHORT[..])?;
case 'B' =>
// TODO: Localization
- dt.date.month = get_default_locale_string_index(
+ dt.month = get_default_locale_string_index(
&s_iter, MONTHS[..])?;
case 'd', 'e' =>
let max_n_digits = 2u;
if (format_r == 'e') {
max_n_digits -= eat_one_rune(&s_iter, ' ')?;
};
- dt.date.day = clamp_int(
+ dt.day = clamp_int(
get_max_n_digits(&s_iter, max_n_digits)?, 1, 31);
case 'G' =>
- dt.date.isoweekyear = get_max_n_digits(&s_iter, 4)?;
+ dt.isoweekyear = get_max_n_digits(&s_iter, 4)?;
case 'H', 'k' =>
let max_n_digits = 2u;
if (format_r == 'k') {
max_n_digits -= eat_one_rune(&s_iter, ' ')?;
};
- dt.time.hour = clamp_int(
+ dt.hour = clamp_int(
get_max_n_digits(&s_iter, max_n_digits)?, 0, 23);
case 'I', 'l' =>
let max_n_digits = 2u;
@@ -121,7 +121,7 @@ export fn strptime(fmt: str, s: str, dt: *datetime) (void | errors::invalid) = {
max_n_digits -= eat_one_rune(&s_iter, ' ')?;
};
const hour = get_max_n_digits(&s_iter, max_n_digits);
- dt.time.hour = match (hour) {
+ dt.hour = match (hour) {
case let hour: int =>
yield if (hour > 12) {
yield clamp_int(hour - 12, 1, 12);
@@ -132,22 +132,22 @@ export fn strptime(fmt: str, s: str, dt: *datetime) (void | errors::invalid) = {
return errors::invalid;
};
case 'j' =>
- dt.date.yearday = clamp_int(
+ dt.yearday = clamp_int(
get_max_n_digits(&s_iter, 3)?, 1, 366);
case 'm' =>
- dt.date.month = clamp_int(
+ dt.month = clamp_int(
get_max_n_digits(&s_iter, 2)?, 1, 12);
case 'M' =>
- dt.time.min = clamp_int(
+ dt.min = clamp_int(
get_max_n_digits(&s_iter, 2)?, 0, 59);
case 'n' =>
eat_one_rune(&s_iter, '\n')?;
case 'N' =>
- dt.time.nsec = clamp_int(
+ dt.nsec = clamp_int(
get_max_n_digits(&s_iter, 3)?, 0, 999);
case 'p', 'P' =>
// TODO: Localization
- if (dt.time.hour is void) {
+ if (dt.hour is void) {
// We can't change the hour's am/pm because we
// have no hour.
return errors::invalid;
@@ -164,19 +164,19 @@ export fn strptime(fmt: str, s: str, dt: *datetime) (void | errors::invalid) = {
yield "pm";
};
if (strings::hasprefix(rest, prefix_am)) {
- if (dt.time.hour as int > 12) {
+ if (dt.hour as int > 12) {
// 13 AM?
return errors::invalid;
- } else if (dt.time.hour as int == 12) {
- dt.time.hour = 0;
+ } else if (dt.hour as int == 12) {
+ dt.hour = 0;
};
} else if (strings::hasprefix(rest, prefix_pm)) {
- if (dt.time.hour as int > 12) {
+ if (dt.hour as int > 12) {
// 13 PM?
return errors::invalid;
- } else if (dt.time.hour as int < 12) {
- dt.time.hour =
- (dt.time.hour as int) + 12;
+ } else if (dt.hour as int < 12) {
+ dt.hour =
+ (dt.hour as int) + 12;
};
} else {
return errors::invalid;
@@ -184,12 +184,12 @@ export fn strptime(fmt: str, s: str, dt: *datetime) (void | errors::invalid) = {
strings::next(&s_iter);
strings::next(&s_iter);
case 'S' =>
- dt.time.sec = clamp_int(
+ dt.sec = clamp_int(
get_max_n_digits(&s_iter, 2)?, 0, 61);
case 't' =>
eat_one_rune(&s_iter, '\t')?;
case 'u', 'w' =>
- dt.date.weekday = match (get_max_n_digits(&s_iter, 1)) {
+ dt.weekday = match (get_max_n_digits(&s_iter, 1)) {
case let i: int =>
yield if (format_r == 'w') {
yield if (i == 0) {
@@ -204,13 +204,13 @@ export fn strptime(fmt: str, s: str, dt: *datetime) (void | errors::invalid) = {
return errors::invalid;
};
case 'U', 'W' =>
- dt.date.week = clamp_int(
+ dt.week = clamp_int(
get_max_n_digits(&s_iter, 2)?, 0, 53);
case 'V' =>
- dt.date.isoweek = clamp_int(
+ dt.isoweek = clamp_int(
get_max_n_digits(&s_iter, 2)?, 0, 53);
case 'Y' =>
- dt.date.year = get_max_n_digits(&s_iter, 4)?;
+ dt.year = get_max_n_digits(&s_iter, 4)?;
case 'z' =>
// TODO
continue;
@@ -220,73 +220,73 @@ export fn strptime(fmt: str, s: str, dt: *datetime) (void | errors::invalid) = {
// Expansion specifiers
case 'c' =>
// TODO: Localization
- dt.date.weekday = get_default_locale_string_index(
+ dt.weekday = get_default_locale_string_index(
&s_iter, WEEKDAYS_SHORT[..])?;
if (eat_one_rune(&s_iter, ' ')? != 1) {
fmtlib::printfln("no space after weekday")!;
return errors::invalid;
};
- dt.date.month = get_default_locale_string_index(
+ dt.month = get_default_locale_string_index(
&s_iter, MONTHS_SHORT[..])?;
if (eat_one_rune(&s_iter, ' ')? != 1) {
fmtlib::printfln("no space after month")!;
return errors::invalid;
};
const max_n_digits = 2 - eat_one_rune(&s_iter, ' ')?;
- dt.date.day = clamp_int(
+ dt.day = clamp_int(
get_max_n_digits(&s_iter, max_n_digits)?, 1, 31);
if (eat_one_rune(&s_iter, ' ')? != 1) {
fmtlib::printfln("no space after day")!;
return errors::invalid;
};
- dt.time.hour = clamp_int(
+ dt.hour = clamp_int(
get_max_n_digits(&s_iter, 2)?, 0, 23);
if (eat_one_rune(&s_iter, ':')? != 1) {
fmtlib::printfln("no : after hour")!;
return errors::invalid;
};
- dt.time.min = clamp_int(
+ dt.min = clamp_int(
get_max_n_digits(&s_iter, 2)?, 0, 59);
if (eat_one_rune(&s_iter, ':')? != 1) {
fmtlib::printfln("no : after minute")!;
return errors::invalid;
};
- dt.time.sec = clamp_int(
+ dt.sec = clamp_int(
get_max_n_digits(&s_iter, 2)?, 0, 61);
if (eat_one_rune(&s_iter, ' ')? != 1) {
fmtlib::printfln("no space after sec")!;
return errors::invalid;
};
- dt.date.year = get_max_n_digits(&s_iter, 4)?;
+ dt.year = get_max_n_digits(&s_iter, 4)?;
case 'D', 'x' =>
// TODO: Localization for %x
- dt.date.month = clamp_int(
+ dt.month = clamp_int(
get_max_n_digits(&s_iter, 2)?, 1, 12);
if (eat_one_rune(&s_iter, '/')? != 1) {
return errors::invalid;
};
- dt.date.day = clamp_int(
+ dt.day = clamp_int(
get_max_n_digits(&s_iter, 2)?, 1, 31);
if (eat_one_rune(&s_iter, '/')? != 1) {
return errors::invalid;
};
- dt.date.year = get_max_n_digits(&s_iter, 4)?;
+ dt.year = get_max_n_digits(&s_iter, 4)?;
case 'F' =>
- dt.date.year = get_max_n_digits(&s_iter, 4)?;
+ dt.year = get_max_n_digits(&s_iter, 4)?;
if (eat_one_rune(&s_iter, '-')? != 1) {
return errors::invalid;
};
- dt.date.month = clamp_int(
+ dt.month = clamp_int(
get_max_n_digits(&s_iter, 2)?, 1, 12);
if (eat_one_rune(&s_iter, '-')? != 1) {
return errors::invalid;
};
- dt.date.day = clamp_int(
+ dt.day = clamp_int(
get_max_n_digits(&s_iter, 2)?, 1, 31);
case 'r' =>
// TODO: Localization
// Time
- dt.time.hour = match (get_max_n_digits(&s_iter, 2)) {
+ dt.hour = match (get_max_n_digits(&s_iter, 2)) {
case let hour: int =>
yield if (hour > 12) {
yield clamp_int(hour - 12, 1, 12);
@@ -299,12 +299,12 @@ export fn strptime(fmt: str, s: str, dt: *datetime) (void | errors::invalid) = {
if (eat_one_rune(&s_iter, ':')? != 1) {
return errors::invalid;
};
- dt.time.min = clamp_int(
+ dt.min = clamp_int(
get_max_n_digits(&s_iter, 2)?, 0, 59);
if (eat_one_rune(&s_iter, ':')? != 1) {
return errors::invalid;
};
- dt.time.sec = clamp_int(
+ dt.sec = clamp_int(
get_max_n_digits(&s_iter, 2)?, 0, 61);
if (eat_one_rune(&s_iter, ' ')? != 1) {
return errors::invalid;
@@ -312,19 +312,19 @@ export fn strptime(fmt: str, s: str, dt: *datetime) (void | errors::invalid) = {
let rest = strings::iter_str(&s_iter);
// AM/PM
if (strings::hasprefix(rest, "AM")) {
- if (dt.time.hour as int > 12) {
+ if (dt.hour as int > 12) {
// 13 AM?
return errors::invalid;
- } else if (dt.time.hour as int == 12) {
- dt.time.hour = 0;
+ } else if (dt.hour as int == 12) {
+ dt.hour = 0;
};
} else if (strings::hasprefix(rest, "PM")) {
- if (dt.time.hour as int > 12) {
+ if (dt.hour as int > 12) {
// 13 PM?
return errors::invalid;
- } else if (dt.time.hour as int < 12) {
- dt.time.hour =
- (dt.time.hour as int) + 12;
+ } else if (dt.hour as int < 12) {
+ dt.hour =
+ (dt.hour as int) + 12;
};
} else {
return errors::invalid;
@@ -332,26 +332,26 @@ export fn strptime(fmt: str, s: str, dt: *datetime) (void | errors::invalid) = {
strings::next(&s_iter);
strings::next(&s_iter);
case 'R' =>
- dt.time.hour = clamp_int(
+ dt.hour = clamp_int(
get_max_n_digits(&s_iter, 2)?, 0, 23);
if (eat_one_rune(&s_iter, ':')? != 1) {
return errors::invalid;
};
- dt.time.min = clamp_int(
+ dt.min = clamp_int(
get_max_n_digits(&s_iter, 2)?, 0, 59);
case 'T', 'X' =>
// TODO: Localization for %X
- dt.time.hour = clamp_int(
+ dt.hour = clamp_int(
get_max_n_digits(&s_iter, 2)?, 0, 23);
if (eat_one_rune(&s_iter, ':')? != 1) {
return errors::invalid;
};
- dt.time.min = clamp_int(
+ dt.min = clamp_int(
get_max_n_digits(&s_iter, 2)?, 0, 59);
if (eat_one_rune(&s_iter, ':')? != 1) {
return errors::invalid;
};
- dt.time.sec = clamp_int(
+ dt.sec = clamp_int(
get_max_n_digits(&s_iter, 2)?, 0, 61);
case =>
diff --git a/datetime/time.ha b/datetime/time.ha
@@ -1,49 +1,27 @@
use errors;
use time;
-export type localtime = struct {
- lapsed: (void | int),
- hour: (void | int),
- min: (void | int),
- sec: (void | int),
- nsec: (void | int),
-};
-
-fn init_time() localtime = localtime {
- lapsed = void,
- hour = void,
- min = void,
- sec = void,
- nsec = void,
-};
-
// TODO: rework the following functions and their signatures
-fn conv_time_localtime(t: time::duration) localtime = {
- const lt = localtime {
- lapsed = t: int,
- hour = (t / time::HOUR): int,
- min = ((t / time::MINUTE) % 60): int,
- sec = ((t / time::SECOND) % 60): int,
- nsec = (t % time::SECOND): int,
- };
- return lt;
+fn calc_hmsn(t: time::duration) (int, int, int, int) = {
+ const hour = (t / time::HOUR): int;
+ const min = ((t / time::MINUTE) % 60): int;
+ const sec = ((t / time::SECOND) % 60): int;
+ const nsec = (t % time::SECOND): int;
+ return (hour, min, sec, nsec);
};
-fn conv_localtime_time(lt: localtime) (time::duration | errors::invalid) = {
- if (
- lt.hour is void
- || lt.min is void
- || lt.sec is void
- || lt.nsec is void
- ) {
- return errors::invalid;
- };
+fn calc_time_from_hmsn(
+ hour: int,
+ min: int,
+ sec: int,
+ nsec: int,
+) (time::duration | errors::invalid) = {
const t = (
- (lt.hour: int * time::HOUR) +
- (lt.min: int * time::MINUTE) +
- (lt.sec: int * time::SECOND) +
- (lt.nsec: int * time::NANOSECOND)
+ (hour * time::HOUR) +
+ (min * time::MINUTE) +
+ (sec * time::SECOND) +
+ (nsec * time::NANOSECOND)
);
return t;
};
diff --git a/datetime/timezone.ha b/datetime/timezone.ha
@@ -1,17 +1,6 @@
use time;
use time::chrono;
-// Represents the locality of a [[datetime]]
-//
-// Notes: how to expand?
-export type locality = (chrono::local | tzrepr);
-
-export type tzrepr = struct {
- name: str,
- abbrev: str,
- zoffset: localtime,
-};
-
// Retrieves a IANA timezone object by name
export fn tzdb(name: str) chrono::timezone = {
// TODO
diff --git a/time/chrono/timezone.ha b/time/chrono/timezone.ha
@@ -1,15 +1,31 @@
use time;
-// Represents the locality of a datetime
-export type locality = (local | zoffset | *timezone | *tzalias);
+// The locality of a datetime
+export type locality = struct {
+ zrepr: str, // %Z
+ zoffset: zoffset, // %z
+ timezone: (*timezone | local),
+};
+
+// A destructured dual std/dst POSIX timezone. See tzset(3).
+type tzname = struct {
+ std_name: str,
+ std_offset: zoffset,
+ dst_name: str,
+ dst_offset: zoffset,
+ dst_start: str,
+ dst_starttime: str,
+ dst_end: str,
+ dst_endtime: str,
+};
// Represents its associated datetime as local
export type local = void;
-// Represents a simple, constant zone offset
+// A simple, constant zone offset
export type zoffset = time::duration;
-// Represents a timezone; a political region with a ruleset regarding offsets
+// A timezone; a political region with a ruleset regarding offsets
export type timezone = struct {
name: str, // "Europe/Amsterdam"
scale: *timescale,
@@ -17,7 +33,7 @@ export type timezone = struct {
trans: []zonetran,
};
-// Represents a conditional offset, dependant on the time of year
+// A conditional offset, dependant on the time of year
export type zone = struct {
zoffset: zoffset, // 2 * time::HOUR
name: str, // "Central European Summer Time"
@@ -25,7 +41,7 @@ export type zone = struct {
dst: bool, // true
};
-// Represents a timezone transition
+// A timezone transition
export type zonetran = struct {
when: time::instant,
zoneindex: int,