commit 11f0c0813c4398cb4efcf337a02e2db9b0b50b51
parent 6569a9970de4b4dbbc8eaaa6e6de00699eb8c90b
Author: Byron Torres <b@torresjrjr.com>
Date: Sat, 13 Nov 2021 01:20:30 +0000
organise date calc, modify types
Signed-off-by: Byron Torres <b@torresjrjr.com>
Diffstat:
5 files changed, 197 insertions(+), 56 deletions(-)
diff --git a/datetime/calendar.ha b/datetime/calendar.ha
@@ -1,5 +1,6 @@
-use time;
+use errors;
use time::chrono;
+use time;
// The epoch of the Julian Day Number
@@ -9,25 +10,32 @@ export def EPOCH_JULIAN: i64 = -2440588;
export def EPOCH_COMMONERA: i64 = -719164;
-export fn conv_datetime_moment(dt: datetime) chrono::moment = {
- const d = conv_localdate_epochal(dt.date);
- const t = conv_localtime_time(dt.time);
+// 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 = dt.loc,
+ loc = chrono::local, // TODO
};
return m;
};
-export fn conv_moment_datetime(m: chrono::moment) datetime = {
- const ld = conv_epochal_localdate(m.date);
+// 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);
- const dt = datetime {
- date = ld,
- time = lt,
- loc = m.loc,
- };
+ dt.time = lt;
+
+ dt.loc = chrono::local; // TODO
return dt;
};
@@ -52,38 +60,44 @@ export fn era(m: chrono::moment) int = {
// Calculates a moment's year
export fn year(m: chrono::moment) int = {
- const ld = conv_epochal_localdate(m.date);
+ const ld = localdate { ... };
+ calc_ymd(m.date, &ld);
return ld.year as int;
};
// Calculates a moment's month
export fn month(m: chrono::moment) int = {
- const ld = conv_epochal_localdate(m.date);
+ const ld = localdate { ... };
+ calc_ymd(m.date, &ld);
return ld.month as int;
};
// Calculates a moment's day of the month
export fn day(m: chrono::moment) int = {
- const ld = conv_epochal_localdate(m.date);
+ const ld = localdate { ... };
+ calc_ymd(m.date, &ld);
return ld.day as int;
};
// Calculates a moment's ISO week calendar year
export fn weekyear(m: chrono::moment) int = {
- // TODO
- return 0;
+ const ld = localdate { ... };
+ calc_ywd(m.date, &ld);
+ return ld.weekyear as int;
};
// Calculates a moment's ISO week
export fn week(m: chrono::moment) int = {
- // TODO
- return 0;
+ const ld = localdate { ... };
+ calc_ywd(m.date, &ld);
+ return ld.week as int;
};
// Calculates a moment's ordinal day of the year
export fn yearday(m: chrono::moment) int = {
- // TODO
- return 0;
+ const ld = localdate { ... };
+ calc_yd(m.date, &ld);
+ return ld.yearday as int;
};
//
@@ -171,6 +185,7 @@ export fn add(m: chrono::moment, flag: int, pp: period...) chrono::moment = {
return m;
};
+// Specifies behaviour during calendar arithmetic
export type calculus = enum int {
LOGICAL,
PHYSICAL,
diff --git a/datetime/date.ha b/datetime/date.ha
@@ -1,7 +1,8 @@
use time::chrono;
+use errors;
// Represents an ISO calendar date.
-// Instances created from isocal:: functions are guaranteed to be valid.
+// Instances created from datetime:: functions are guaranteed to be valid.
export type localdate = struct {
era: (void | int),
year: (void | int),
@@ -13,7 +14,12 @@ export type localdate = struct {
yearday: (void | int),
};
-export fn conv_epochal_localdate(epochal: chrono::epochal) localdate = {
+// TODO: The following function can be split up for efficiency.
+// calc_y, calc_m, calc_d, etc.
+
+// Populates the year, month, and day fields of a given [[localdate]],
+// calculated from a [[chrono::epochal]]
+export fn calc_ymd(epochal: chrono::epochal, ld: *localdate) void = {
// Algorithm adapted from:
// https://en.wikipedia.org/wiki/Julian_day#Julian_or_Gregorian_calendar_from_Julian_day_number
//
@@ -41,25 +47,116 @@ export fn conv_epochal_localdate(epochal: chrono::epochal) localdate = {
const M = ((h / s + m) % n) + 1;
const Y = (e / p) - y + (n + m - M) / n;
- const ld = localdate {
- year = Y: int,
- month = M: int,
- day = D: int,
+ ld.year = Y: int;
+ ld.month = M: int;
+ ld.day = D: int;
+};
+
+export fn calc_ywd(e: chrono::epochal, ld: *localdate) void = {
+ // TODO
+ ld.year = 0;
+ ld.week = 0;
+ ld.weekday = 0;
+ return;
+};
+
+export fn calc_yd(e: chrono::epochal, ld: *localdate) void = {
+ // TODO
+ ld.year = 0;
+ ld.yearday = 0;
+ return;
+};
+
+// Converts a [[chrono::epocal]] 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 (
+ // TODO: split up calc_ymd for finer grained
+ // calculating and populating
+ want.year is int
+ || want.month is int
+ || want.day is int
+ ) {
+ calc_ymd(e, date);
+ } else if (
+ want.year is int
+ || want.week is int
+ || want.weekday is int
+ ) {
+ calc_ywd(e, date);
+ } else if (
+ want.year is int
+ || want.yearday is int
+ ) {
+ calc_yd(e, date);
};
- return ld;
};
-export fn conv_localdate_epochal(ld: localdate) chrono::epochal = {
- const Y = ld.year as int;
- const M = ld.month as int;
- const D = ld.day as int;
+// Converts a year-month-day date into an [[chrono::epocal]]
+export fn epocal_from_ymd(y: int, m: int, d: int) (chrono::epochal | errors::invalid) = {
+ // Algorithm adapted from:
+ // https://en.wikipedia.org/wiki/Julian_day
+ //
+ // Alternate methods of date calculation should be explored.
const jdn = (
- (1461 * (Y + 4800 + (M - 14) / 12)) / 4
- + (367 * (M - 2 - 12 * ((M - 14) / 12))) / 12
- - (3 * ((Y + 4900 + (M - 14) / 12) / 100)) / 4
- + D
+ (1461 * (y + 4800 + (m - 14) / 12)) / 4
+ + (367 * (m - 2 - 12 * ((m - 14) / 12))) / 12
+ - (3 * ((y + 4900 + (m - 14) / 12) / 100)) / 4
+ + d
- 32075
);
const epochal = jdn + EPOCH_JULIAN;
return epochal;
+
+};
+
+// Converts a year-week-weekday date into an [[chrono::epocal]]
+export fn epocal_from_ywd() (chrono::epochal | errors::invalid) = {
+ // TODO
+ return 0;
+};
+
+// Converts a year-yearday date into an [[chrono::epocal]]
+export fn epocal_from_yd() (chrono::epochal | errors::invalid) = {
+ // TODO
+ return 0;
+};
+
+// Converts a [[localdate]] to a [[chrono::epocal]].
+// 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 epocal_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
@@ -2,6 +2,7 @@ use time;
use time::chrono;
use errors;
+
// Represents a ISO datetime
//
// Notes:
@@ -17,7 +18,7 @@ use errors;
export type datetime = struct {
date: localdate,
time: localtime,
- loc: chrono::locality,
+ loc: locality,
};
// Creates a new moment
@@ -34,8 +35,8 @@ export fn new_moment(
min: int,
sec: int,
nsec: int,
- loc: chrono::locality,
-) chrono::moment = {
+ loc: locality,
+) (chrono::moment | errors::invalid) = {
const dt = datetime {
date = localdate {
year = year,
@@ -50,7 +51,7 @@ export fn new_moment(
},
loc = loc,
};
- const m = conv_datetime_moment(dt);
+ const m = conv_datetime_moment(dt)?;
return m;
};
@@ -68,7 +69,7 @@ export fn new_datetime(
min: int,
sec: int,
nsec: int,
- loc: chrono::locality,
+ loc: locality,
) (datetime | errors::invalid) = {
const dt = datetime {
date = localdate {
@@ -111,7 +112,13 @@ export fn now_datetime() datetime = {
const i = time::now(time::clock::REALTIME);
const u = time::unix(i);
const d = (u / 86400);
- const ld = conv_epochal_localdate(d);
+ const ld = localdate { ... };
+ conv_epochal_localdate(d, &ld, &localdate {
+ // TODO: reconcile, add new fields when ready
+ year = 0,
+ month = 0,
+ day = 0,
+ });
const dt = datetime {
date = ld,
time = localtime {
@@ -129,7 +136,7 @@ export fn now_datetime() datetime = {
return dt;
};
-export fn validate(dt: datetime) bool = {
+export fn validate(dt: (datetime | localdate | localtime)) bool = {
// TODO
return true;
};
diff --git a/datetime/time.ha b/datetime/time.ha
@@ -1,13 +1,15 @@
+use errors;
use time;
-// Represents a ISO time of day
+// Represents a time of day as represented on a wall clock
export type localtime = struct {
- hour: int,
- min: int,
- sec: int,
- nsec: int,
+ hour: (void | int),
+ min: (void | int),
+ sec: (void | int),
+ nsec: (void | int),
};
+// Converts a [[time::duration]] to a [[localtime]]
export fn conv_time_localtime(t: time::duration) localtime = {
const lt = localtime {
hour = (t / time::HOUR): int,
@@ -18,14 +20,22 @@ export fn conv_time_localtime(t: time::duration) localtime = {
return lt;
};
-export fn conv_localtime_time(lt: localtime) time::duration = {
+// 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) = {
+ if (
+ lt.hour is void
+ || lt.min is void
+ || lt.sec is void
+ || lt.nsec is void
+ ) {
+ return errors::invalid;
+ };
const t = (
- (lt.hour * time::HOUR) +
- (lt.min * time::MINUTE) +
- (lt.sec * time::SECOND) +
- (lt.nsec * time::NANOSECOND)
+ (lt.hour: int * time::HOUR) +
+ (lt.min: int * time::MINUTE) +
+ (lt.sec: int * time::SECOND) +
+ (lt.nsec: int * time::NANOSECOND)
);
return t;
};
-
-
diff --git a/datetime/timezone.ha b/datetime/timezone.ha
@@ -1,6 +1,17 @@
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
@@ -38,7 +49,8 @@ export const TZ_CET: chrono::timezone = chrono::timezone {
};
fn zone_cet(m: chrono::moment) uint = {
- const dt = conv_moment_datetime(m);
+ const dt = datetime { ... };
+ conv_moment_datetime(m, &dt);
const dst = (
dt.date.month: int == 3 &&
dt.date.day: int == 28 &&