hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mdatetime/calendar.ha | 57++++++++++++++++++++++++++++++++++++---------------------
Mdatetime/date.ha | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Mdatetime/datetime.ha | 21++++++++++++++-------
Mdatetime/time.ha | 34++++++++++++++++++++++------------
Mdatetime/timezone.ha | 14+++++++++++++-
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 &&