commit 5bf82661b4989dd93db5cbe07655196f7c78f2b9
parent a6448dbd209d83e01c673cbca5c505418ebf91b4
Author: Byron Torres <b@torresjrjr.com>
Date: Sat, 20 Nov 2021 01:01:16 +0000
tidy code and comments, add arithmetic.ha
TODO datetime:
- Write some use cases and more tests.
- Tidy, validate, and accredit magic "calc ymd" code and formulae.
- Write and incorporate validation near datetime creation.
- Write add(), hop() and maybe reckon(), a combo of the two.
- Reconcile separation of concerns of datetime, localdate, localtime
- Make some basic timezones.
- Make now() use time::clock and/or chrono::timescale.
TODO time::chrono:
- Complete to_tai and from_tai functions.
- Add difftai to the timescale interface.
- Complete timezone type system.
- Reconcile chrono::moment's relation with datetime::datetime.
Signed-off-by: Byron Torres <b@torresjrjr.com>
Diffstat:
11 files changed, 301 insertions(+), 297 deletions(-)
diff --git a/datetime/arithmetic.ha b/datetime/arithmetic.ha
@@ -0,0 +1,75 @@
+use time::chrono;
+
+// Represents a span of time in the proleptic Gregorian calendar,
+// using relative units of time. Used for calendar arithmetic.
+export type period = struct {
+ eras: int,
+ years: int,
+
+ // Can be 28, 29, 30, or 31 days long
+ months: int,
+
+ // Weeks start on Monday
+ weeks: int,
+
+ days: int,
+ hours: int,
+ minutes: int,
+ seconds: int,
+ nanoseconds: int,
+};
+
+// Specifies behaviour during calendar arithmetic
+export type calculus = enum int {
+ LOGICAL,
+ PHYSICAL,
+};
+
+// Hops, starting from a datetime, to static inter-period points along the
+// calendar, according to the given periods, and returns a new datetime.
+// Inter-period points are the starts of years, months, days, etc.
+//
+// hop() consults each period's fields in order of largest to smallest
+// calendrically (from years to nanoseconds).
+//
+// If a field's value N is zero, nothing happens. Otherwise, hop() will reckon
+// to the Nth inter-period point from where last reckoned. This repeats until
+// all the given period's fields are exhausted.
+//
+// let dt = ... // 1999-05-13 12:30:45
+// datetime::hop(dt, datetime::period {
+// years = 22, // produces 2021-01-01 00:00:00
+// months = -1, // produces 2020-11-01 00:00:00
+// days = -4, // produces 2020-10-27 00:00:00
+// });
+//
+export fn hop(dt: datetime, pp: period...) datetime = {
+ // TODO
+ for (let i = 0z; i < len(pp); i += 1) {
+ const p = pp[i];
+ };
+ return dt;
+};
+
+// Adds a calindrical period of time to a datetime, largest units first.
+// Tries to conserve relative distance from cyclical points on the calendar.
+//
+// let dt = ... // 1999-05-13 12:30:45
+// datetime::hop(dt, datetime::calculus::LOGICAL, datetime::period {
+// years = 22, // 2021-05-13 00:00:00
+// months = -1, // 2021-04-13 00:00:00
+// days = -4, // 2020-04-09 00:00:00
+// });
+//
+// When units overflow, such as when adding a month to Jan 31st would
+// erroneously result in Feb 31th, the flag is consulted on how to handle this.
+//
+// TODO:
+// How to handle overflows and predictability with cal-arithm in general?
+export fn add(m: datetime, flag: int, pp: period...) datetime = {
+ // TODO
+ for (let i = 0z; i < len(pp); i += 1) {
+ const p = pp[i];
+ };
+ return dt;
+};
diff --git a/datetime/calendar.ha b/datetime/calendar.ha
@@ -1,61 +1,37 @@
use errors;
-use time::chrono;
use time;
+use time::chrono;
+// TODO: reconcile what epochs to use for time::chrono and datetime::
+//
+// 1970-01-01 "Hare epoch"
+// 0000-01-01 Gregorian epoch
-// The epoch of the Julian Day Number
+// The Hare epoch of the Julian Day Number
export def EPOCH_JULIAN: i64 = -2440588;
-// The epoch of the Common Era
+// The Hare epoch of the Common Era
export def EPOCH_COMMONERA: i64 = -719164;
-// 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;
-};
-
-
//
// date-like
//
-// Evaluates a datetime's number of days since the calendar epoch 0001-01-01
+// Evaluates a [[datetime]]'s number of days since the calendar epoch 0000-01-01
export fn epochal(dt: *datetime) int = {
match (dt.date.epochal) {
case void =>
- abort("TODO"); // How to resolve? Use calc_epochal_from_*?
+ // How to resolve?
+ // Use calc_epochal_from_*? How to avoid recursion?
+ // When to rely on input validation?
+ abort("TODO");
case e: int =>
return e;
};
};
-// Evaluates a datetime's era
+// Evaluates a [[datetime]]'s era
export fn era(dt: *datetime) int = {
match (dt.date.era) {
case void =>
@@ -69,7 +45,7 @@ export fn era(dt: *datetime) int = {
};
};
-// Evaluates a datetime's year
+// Evaluates a [[datetime]]'s year
export fn year(dt: *datetime) int = {
match (dt.date.year) {
case void =>
@@ -86,7 +62,7 @@ export fn year(dt: *datetime) int = {
};
};
-// Evaluates a datetime's month
+// Evaluates a [[datetime]]'s month of the year
export fn month(dt: *datetime) int = {
match (dt.date.month) {
case void =>
@@ -103,7 +79,7 @@ export fn month(dt: *datetime) int = {
};
};
-// Evaluates a datetime's day of the month
+// Evaluates a [[datetime]]'s day of the month
export fn day(dt: *datetime) int = {
match (dt.date.day) {
case void =>
@@ -120,8 +96,7 @@ export fn day(dt: *datetime) int = {
};
};
-
-// Evaluates a datetime's day of the week
+// Evaluates a [[datetime]]'s day of the week
export fn weekday(dt: *datetime) int = {
match (dt.date.weekday) {
case void =>
@@ -135,7 +110,7 @@ export fn weekday(dt: *datetime) int = {
};
};
-// Evaluates a datetime's ordinal day of the year
+// Evaluates a [[datetime]]'s ordinal day of the year
export fn yearday(dt: *datetime) int = {
match (dt.date.yearday) {
case void =>
@@ -158,7 +133,8 @@ export fn yearday(dt: *datetime) int = {
return yd;
};
};
-// Evaluates a datetime's ISO week calendar year
+
+// Evaluates a [[datetime]]'s ISO week-numbering year
export fn isoweekyear(dt: *datetime) int = {
match (dt.date.isoweekyear) {
case void =>
@@ -186,7 +162,7 @@ export fn isoweekyear(dt: *datetime) int = {
};
};
-// Evaluates a datetime's Gregorian week
+// Evaluates a [[datetime]]'s Gregorian week
export fn week(dt: *datetime) int = {
match (dt.date.week) {
case void =>
@@ -206,7 +182,7 @@ export fn week(dt: *datetime) int = {
};
};
-// Evaluates a datetime's ISO week
+// Evaluates a [[datetime]]'s ISO week
export fn isoweek(dt: *datetime) int = {
match (dt.date.isoweek) {
case void =>
@@ -234,11 +210,12 @@ export fn isoweek(dt: *datetime) int = {
};
};
+
//
// time-like
//
-// Evaluates a datetime's hour of the day
+// Evaluates a [[datetime]]'s hour of the day
export fn hour(dt: *datetime) int = {
match (dt.time.hour) {
case void =>
@@ -248,7 +225,7 @@ export fn hour(dt: *datetime) int = {
};
};
-// Evaluates a datetime's minute of the hour
+// Evaluates a [[datetime]]'s minute of the hour
export fn min(dt: *datetime) int = {
match (dt.time.min) {
case void =>
@@ -258,7 +235,7 @@ export fn min(dt: *datetime) int = {
};
};
-// Evaluates a datetime's second of the minute
+// Evaluates a [[datetime]]'s second of the minute
export fn sec(dt: *datetime) int = {
match (dt.time.sec) {
case void =>
@@ -268,7 +245,7 @@ export fn sec(dt: *datetime) int = {
};
};
-// Evaluates a datetime's nanosecond of the second
+// Evaluates a [[datetime]]'s nanosecond of the second
export fn nsec(dt: *datetime) int = {
match (dt.time.nsec) {
case void =>
@@ -278,69 +255,32 @@ export fn nsec(dt: *datetime) int = {
};
};
-
-// A contextual span of time in the proleptic Gregorian calendar.
-// Used for calendar arithmetic.
-export type period = struct {
- eras: int,
- years: int,
-
- // Can be 28, 29, 30, or 31 days long
- months: int,
-
- // Weeks start on Monday
- weeks: int,
-
- days: int,
- hours: int,
- minutes: int,
- seconds: int,
- nanoseconds: int,
-};
-
-// Hops along the calendar from a moment, according to the given periods
-// sequencially, consulting period's units from largest to smallest.
-//
-// // m := 1999-05-13 12:30:45
-// datetime::hop(m, datetime::period {
-// years = 22, // 2021-01-01 00:00:00
-// months = -1, // 2020-11-01 00:00:00
-// days = -4, // 2020-10-27 00:00:00
-// });
-//
-export fn hop(m: chrono::moment, pp: period...) chrono::moment = {
- // TODO
- for (let i = 0z; i < len(pp); i += 1) {
- const p = pp[i];
- };
- return m;
-};
-
-// Adds a calindrical period of time to a moment, largest units first.
-// Tries to conserve relative distance from cyclical points on the calendar.
-//
-// // m := 1999-05-13 12:30:45
-// datetime::hop(m, datetime::period {
-// years = 22, // 2021-05-13 00:00:00
-// months = -1, // 2021-04-13 00:00:00
-// days = -4, // 2020-04-09 00:00:00
-// });
-//
-// When units overflow, such as when adding a month to Jan 31st inaccurately
-// results to Feb 31th, the flag is consulted on how to handle this.
-//
-// TODO:
-// How to handle overflows and predictability with cal-arithm in general?
-export fn add(m: chrono::moment, flag: int, pp: period...) chrono::moment = {
- // TODO
- for (let i = 0z; i < len(pp); i += 1) {
- const p = pp[i];
- };
- return m;
-};
-
-// Specifies behaviour during calendar arithmetic
-export type calculus = enum int {
- LOGICAL,
- PHYSICAL,
-};
+// // 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+test.ha b/datetime/date+test.ha
@@ -147,4 +147,3 @@ use time::chrono;
assert(expect == actual, "weekday miscalculation");
};
};
-
diff --git a/datetime/date.ha b/datetime/date.ha
@@ -1,8 +1,6 @@
-use time::chrono;
use errors;
+use time::chrono;
-// Represents an ISO calendar date.
-// Instances created from datetime:: functions are guaranteed to be valid.
export type localdate = struct {
epochal: (void | int),
era: (void | int),
@@ -16,7 +14,7 @@ export type localdate = struct {
weekday: (void | int),
};
-export fn init_date() localdate = localdate {
+fn init_date() localdate = localdate {
epochal = void,
era = void,
year = void,
@@ -29,7 +27,15 @@ export fn init_date() localdate = localdate {
weekday = void,
};
-// Calculates an era, given a year
+// Calculates whether a given year is a leap year.
+export fn is_leap_year(y: int) bool = {
+ return if (y % 4 != 0) false
+ else if (y % 100 != 0) true
+ else if (y % 400 != 0) false
+ else true;
+};
+
+// Calculates the era, given a year
fn calc_era(y: int) int = {
return if (y >= 0) {
yield 1; // CE "Common Era"
@@ -38,7 +44,6 @@ fn calc_era(y: int) int = {
};
};
-
// Calculates the (year, month, day), given an epochal day
fn calc_ymd(e: int) (int, int, int) = {
// Algorithm adapted from:
@@ -73,7 +78,7 @@ fn calc_ymd(e: int) (int, int, int) = {
return (Y: int, M: int, D: int);
};
-// Calculates the day of a year, given a year, month, and day
+// Calculates the day of a year, given a (year, month, day) date
fn calc_yearday(y: int, m: int, d: int) int = {
const months_firsts: [_]int = [
0, 31, 59,
@@ -90,7 +95,7 @@ fn calc_yearday(y: int, m: int, d: int) int = {
};
// Calculates the ISO week-numbering year,
-// given a year, month, day, and weekday
+// given a (year, month, day, weekday) date
fn calc_isoweekyear(y: int, m: int, d: int, wd: int) int = {
if (
// if the date is within a week whose Thurday
@@ -117,7 +122,7 @@ fn calc_isoweekyear(y: int, m: int, d: int, wd: int) int = {
};
};
-// Calculates a ISO week, given a year, week, Gregorian weekday, and yearday
+// Calculates the ISO week, given a (year, week, weekday, yearday) date
fn calc_isoweek(y: int, w: int, wd: int, yd: int) int = {
const jan1wd = (yd - wd + 7) % 7 + 1;
@@ -145,7 +150,6 @@ fn calc_isoweek(y: int, w: int, wd: int, yd: int) int = {
yield w;
};
};
-
return iw;
};
@@ -156,69 +160,20 @@ fn calc_week(yd: int, wd: int) int = {
return (5 + yd - wd) / 7;
};
-// Calculates the weekday, given a epochal day
+// Calculates the weekday, given a epochal day,
// from Monday=1 to Sunday=7
fn calc_weekday(e: chrono::epochal) int = {
const wd = ((e + 3) % 7 + 1): int;
return if (wd > 0) wd else wd + 7;
};
-// Calculates the weekday, given a epochal day
+// Calculates the zeroed weekday, given a weekday,
// from Monday=0 to Sunday=6
fn calc_zeroweekday(wd: int) int = {
return wd - 1;
};
-// Calculates whether a given year is a leap year.
-fn is_leap_year(y: int) bool = {
- return if (y % 4 != 0) false
- else if (y % 100 != 0) true
- else if (y % 400 != 0) false
- else true;
-};
-
-// 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 year-month-day date into an [[chrono::epochal]]
+// Calculates the [[chrono::epochal]], given a (year, month, day) date
fn calc_epochal_from_ymd(y: int, m: int, d: int) (chrono::epochal | errors::invalid) = {
// Algorithm adapted from:
// https://en.wikipedia.org/wiki/Julian_day
@@ -231,48 +186,88 @@ fn calc_epochal_from_ymd(y: int, m: int, d: int) (chrono::epochal | errors::inva
+ d
- 32075
);
- const epochal = jdn + EPOCH_JULIAN;
- return epochal;
-
+ const e = jdn + EPOCH_JULIAN;
+ return e;
};
-// Converts a year-week-weekday date into an [[chrono::epochal]]
-fn calc_epochal_from_ywd() (chrono::epochal | errors::invalid) = {
+// Calculates the [[chrono::epochal]], given a (year, week, weekday) date
+fn calc_epochal_from_ywd(y: int, w: int, wd: int) (chrono::epochal | errors::invalid) = {
// TODO
return 0;
};
-// Converts a year-yearday date into an [[chrono::epochal]]
-fn calc_epochal_from_yd() (chrono::epochal | errors::invalid) = {
+// Calculates the [[chrono::epochal]], given a (year, yearday) date
+fn calc_epochal_from_yd(y: int, yd: int) (chrono::epochal | errors::invalid) = {
// TODO
return 0;
};
-// 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
- };
+// // 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);
+// };
+// };
- return errors::invalid;
-};
+// // 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
@@ -1,60 +1,26 @@
+use errors;
use time;
use time::chrono;
-use errors;
-
-// Represents a ISO datetime
-//
-// Notes:
-// Java has good separation of types: A LocalDatetime, ZonedDatetime,
-// OffsetDatetime. Python instead reasons about datetimes as being
-// timezone-aware/naive. Here's I try to leaverage Hare's type system to combine
-// the two.
-//
-// Putting the date and time related fields into separate typed structs maybe
-// isn't a good idea (see `type localdate` below), but I still put it here
-// because localtime is often used on it's own, and it makes some sense to have
-// a datetime be composed of a date and time.
+// 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,
};
-// Returns a [[datetime]], with all subfields initialised with void
-export fn init_datetime() datetime = datetime {
+fn init_datetime() datetime = datetime {
date = init_date(),
time = init_time(),
loc = chrono::local,
};
-// 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;
-};
-
// Creates a new datetime
//
-// // 1995 July 18th 09:16:00.000
-// datetime::new(1995, 07, 18, 9, 16, 0, 0, chrono::local)
+// // 2038 January 19th 03:14:07.000
+// datetime::new(2038, 01, 19, 03, 14, 07, 0, chrono::local)
//
-// For alternative forms, assemble a datetime manually using the desired types.
export fn new(
year: int,
month: int,
@@ -77,7 +43,6 @@ export fn new(
week = void,
weekday = void,
yearday = void,
-
},
time = localtime {
lapsed = void,
@@ -94,22 +59,6 @@ export fn new(
return dt;
};
-// 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;
-};
-
// Returns the current datetime
export fn now() datetime = {
const i = time::now(time::clock::REALTIME);
@@ -135,7 +84,45 @@ export fn now() datetime = {
return dt;
};
+// Validates a datetime's internal date & time values
export fn validate(dt: (datetime | localdate | localtime)) 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+test.ha b/datetime/format+test.ha
@@ -1,6 +1,6 @@
use errors;
-use time::chrono;
use fmt;
+use time::chrono;
@test fn strptime() void = {
let dt = datetime {...};
diff --git a/datetime/format.ha b/datetime/format.ha
@@ -112,7 +112,11 @@ fn clamp_int(i: int, min: int, max: int) int = {
};
};
-// Parses a string into a [[datetime]]
+// Parses a datetime string into a [[datetime::datetime]].
+//
+// The resulting [[datetime::datetime]] may not contain sufficient information
+// to be valid. Incremental parsing of data is possible, but the caller should
+// validate the [[datetime::datetime]] when appropriate.
export fn strptime(format: str, s: str, dt: *datetime) (void | errors::invalid) = {
const format_iter = strings::iter(format);
const s_iter = strings::iter(s);
@@ -427,7 +431,6 @@ export fn strptime(format: str, s: str, dt: *datetime) (void | errors::invalid)
// Formats a [[datetime]] and writes it into a caller supplied buffer.
// The returned string is borrowed from this buffer.
-// Fails if a particular datetime field is required but void.
export fn bstrftime(buf: []u8, format: str, dt: *datetime) (str | errors::invalid | io::error) = {
let sink = strio::fixed(buf);
defer io::close(sink);
@@ -437,7 +440,6 @@ export fn bstrftime(buf: []u8, format: str, dt: *datetime) (str | errors::invali
// Formats a [[datetime]] and writes it into a heap-allocated string.
// The caller must free the return value.
-// Fails if a particular datetime field is required but void.
export fn strftime(format: str, dt: *datetime) (str | errors::invalid | io::error) = {
let sink = strio::dynamic();
fmttime(sink, format, dt)?;
@@ -445,7 +447,6 @@ export fn strftime(format: str, dt: *datetime) (str | errors::invalid | io::erro
};
// Formats a [[datetime]] and writes it into a [[io::handle]].
-// Fails a particular field is required but void.
export fn fmttime(h: io::handle, format: str, dt: *datetime) (size | errors::invalid | io::error) = {
const iter = strings::iter(format);
let escaped = false;
diff --git a/datetime/time.ha b/datetime/time.ha
@@ -1,7 +1,6 @@
use errors;
use time;
-// Represents a time of day as represented on a wall clock
export type localtime = struct {
lapsed: (void | int),
hour: (void | int),
@@ -10,7 +9,7 @@ export type localtime = struct {
nsec: (void | int),
};
-export fn init_time() localtime = localtime {
+fn init_time() localtime = localtime {
lapsed = void,
hour = void,
min = void,
@@ -18,8 +17,9 @@ export fn init_time() localtime = localtime {
nsec = void,
};
-// Converts a [[time::duration]] to a [[localtime]]
-export fn conv_time_localtime(t: time::duration) localtime = {
+// 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,
@@ -30,9 +30,7 @@ export fn conv_time_localtime(t: time::duration) localtime = {
return lt;
};
-// Converts a [[localtime]] to a [[time::duration]].
-// Fails if any of the [[localtime]] fields are void.
-export fn conv_localtime_time(lt: localtime) (time::duration | errors::invalid) = {
+fn conv_localtime_time(lt: localtime) (time::duration | errors::invalid) = {
if (
lt.hour is void
|| lt.min is void
diff --git a/datetime/timezone.ha b/datetime/timezone.ha
@@ -19,14 +19,18 @@ export fn tzdb(name: str) chrono::timezone = {
};
-// Europe/Amsterdam timezone
+//
+// Some example timezones
+//
+
+// "Europe/Amsterdam" timezone
export const TZ_Europe_Amsterdam: chrono::timezone = chrono::timezone {
aliasof = &TZ_CET,
name = "Europe/Amsterdam",
...
};
-// Central European Time
+// "CET", "Central European Time" timezone
export const TZ_CET: chrono::timezone = chrono::timezone {
aliasof = void,
scale = &chrono::UTC,
@@ -50,7 +54,8 @@ export const TZ_CET: chrono::timezone = chrono::timezone {
fn zone_cet(m: chrono::moment) uint = {
const dt = datetime { ... };
- conv_moment_datetime(m, &dt);
+ // TODO: reconcile chrono::moment // datetime::datetime types
+ //conv_moment_datetime(m, &dt);
const dst = (
dt.date.month: int == 3 &&
dt.date.day: int == 28 &&
@@ -72,4 +77,3 @@ fn zone_cet(m: chrono::moment) uint = {
return 0u;
};
};
-
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -185,21 +185,24 @@ datetime() {
if [ $testing -eq 0 ]
then
gen_srcs datetime \
+ arithmetic.ha \
calendar.ha \
- datetime.ha \
- timezone.ha \
date.ha \
+ datetime.ha \
+ format.ha \
time.ha \
- format.ha
+ timezone.ha
else
gen_srcs datetime \
+ arithmetic.ha \
calendar.ha \
- datetime.ha \
- timezone.ha \
- date.ha \
date+test.ha \
+ date.ha \
+ datetime.ha \
+ format.ha \
+ format+test.ha \
time.ha \
- format.ha
+ timezone.ha
fi
gen_ssa datetime errors fmt strings strio time time::chrono
}
diff --git a/stdlib.mk b/stdlib.mk
@@ -929,12 +929,13 @@ $(HARECACHE)/crypto/curve25519/crypto_curve25519-any.ssa: $(stdlib_crypto_curve2
# datetime (+any)
stdlib_datetime_any_srcs= \
+ $(STDLIB)/datetime/arithmetic.ha \
$(STDLIB)/datetime/calendar.ha \
- $(STDLIB)/datetime/datetime.ha \
- $(STDLIB)/datetime/timezone.ha \
$(STDLIB)/datetime/date.ha \
+ $(STDLIB)/datetime/datetime.ha \
+ $(STDLIB)/datetime/format.ha \
$(STDLIB)/datetime/time.ha \
- $(STDLIB)/datetime/format.ha
+ $(STDLIB)/datetime/timezone.ha
$(HARECACHE)/datetime/datetime-any.ssa: $(stdlib_datetime_any_srcs) $(stdlib_rt) $(stdlib_errors_$(PLATFORM)) $(stdlib_fmt_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_strio_$(PLATFORM)) $(stdlib_time_$(PLATFORM)) $(stdlib_time_chrono_$(PLATFORM))
@printf 'HAREC \t$@\n'
@@ -2892,12 +2893,13 @@ $(TESTCACHE)/crypto/curve25519/crypto_curve25519-any.ssa: $(testlib_crypto_curve
# datetime (+any)
testlib_datetime_any_srcs= \
+ $(STDLIB)/datetime/arithmetic.ha \
$(STDLIB)/datetime/calendar.ha \
$(STDLIB)/datetime/date+test.ha \
$(STDLIB)/datetime/date.ha \
$(STDLIB)/datetime/datetime.ha \
- $(STDLIB)/datetime/format+test.ha \
$(STDLIB)/datetime/format.ha \
+ $(STDLIB)/datetime/format+test.ha \
$(STDLIB)/datetime/time.ha \
$(STDLIB)/datetime/timezone.ha