hare

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

commit b25b0cfc68280e58558d2cca37b92595652bbb27
parent 5fc0a4ff6b7700edd35692f605056afa28aecbdf
Author: Byron Torres <b@torresjrjr.com>
Date:   Fri, 12 Nov 2021 22:16:23 +0000

add moment{} stuct and conversion functions

Signed-off-by: Byron Torres <b@torresjrjr.com>

Diffstat:
Dchrono/calendar.ha | 16----------------
Mchrono/chronology.ha | 45+++++++++++++++++++++++++++++++++------------
Achrono/isocal/calendar.ha | 21+++++++++++++++++++++
Achrono/isocal/date.ha | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mchrono/isocal/datetime.ha | 62+++++++++++++++++++++++++++++++++-----------------------------
Achrono/isocal/time.ha | 31+++++++++++++++++++++++++++++++
Mchrono/isocal/types.ha | 75+++++++++++++++------------------------------------------------------------
Mchrono/timescales.ha | 6++++--
Mscripts/gen-stdlib | 8+++++---
Mstdlib.mk | 16++++++++++------
10 files changed, 207 insertions(+), 128 deletions(-)

diff --git a/chrono/calendar.ha b/chrono/calendar.ha @@ -1,16 +0,0 @@ -use time; - -// Represents a system for ordering days as dates and eras. -// Allows conversion between [[date]] types. -export type calendar = struct { - // TODO - TODO: bool, -}; - -export type localdate = struct { - nday: i64, -}; - -export type localtime = struct { - ntime: time::duration, -}; diff --git a/chrono/chronology.ha b/chrono/chronology.ha @@ -1,17 +1,38 @@ use time; -// Represents a [[timescale]]-[[calendar]] system for ordering events. -// Allows conversion between [[datetime]] and [[time::instant]] types. -// -// Notes: -// Needs rethinking. Initially, the idea was to have the possibility of multiple -// plug-and-plug calendars, but since hare doesn't have objects, we need to -// deisgn this another way. Probably, datetime:: will be solely ISO 8601 -// Proleptic Gregorian, with TAI, UTC, and UNIX, and then we'll have something -// like datetime::chrono::* for alternative chronologies. 3rd party libraries -// would be similar. +// Represents a chronological system for ordering days as dates and eras export type chronology = struct { - timescale: timescale, - calendar: calendar, + // MJD = Modified Julian Date + to_mjd: nullable *fn(day: moment) moment, + to_moment: nullable *fn(day: moment) moment, +}; + +// Represents a calendar system for ordering datea and eras +export type calendar = struct { + // MJDN = Modified Julian Day Number + // RD = Rata Die + to_mjdn: nullable *fn(dn: daynum) daynum, + to_rd: nullable *fn(dn: daynum) daynum, +}; + +// Represents a moment in time on a calendar; essentially a datetime +export type moment = struct { + day: daynum, + time: time::duration, }; +// Represents a Rata Die, an ordinal day since a calendar epoch +// +// Notes: +// aka: +// - epochalday +// - epochal +// - nday +export type daynum = i64; + +// Represents the Modified Julian Day Number calendar. +// Not to be confused with the Julian calendar. +export const MJDN: calendar = calendar { ... }; + +// Represents the Modified Julian Date chronology. +export const MJD: chronology = chronology { ... }; diff --git a/chrono/isocal/calendar.ha b/chrono/isocal/calendar.ha @@ -0,0 +1,21 @@ + +// // Represents a calendar system which supports datetimes +// export type calendar = struct { +// // chrono::calendar, +// to_localdate: *conv_daynum_localdate, +// to_daynum: *conv_localdate_daynum, +// }; +// +// export type conv_daynum_localdate = fn(dn: daynum) localdate; +// +// export type conv_localdate_daynum = fn(ld: localdate) daynum; +// +// export type chronology = struct { +// // chrono::chronology, +// to_datetime: *conv_moment_datetime, +// to_moment: *conv_datetime_moment, +// }; +// +// export type conv_moment_datetime = fn(m: moment) datetime; +// +// export type conv_datetime_moment = fn(dt: datetime) moment; diff --git a/chrono/isocal/date.ha b/chrono/isocal/date.ha @@ -0,0 +1,55 @@ +use chrono; + +// Represents a ISO calendar date +export type localdate = struct { + year: i64, + month: int, + day: int, +}; + +export fn conv_daynum_localdate(dn: chrono::daynum) localdate = { + const J = dn; + const j = 1401; + const y = 4716; + const B = 274277; + const C = -38; + const r = 4; + const v = 3; + const p = 1461; + const u = 5; + const w = 2; + const s = 153; + const n = 12; + const m = 2; + + const f = J + j + (((4 * J + B) / 146097) * 3) / 4 + C; + const e = r * f + v; + const g = (e % p) / r; + const h = u * g + w; + + const D = (h % s) / u + 1; + const M = ((h / s + m) % n) + 1; + const Y = (e / p) - y + (n + m - M) / n; + + const ld = localdate { + year = Y, + month = M: int, + day = D: int, + }; + return ld; +}; + +export fn conv_localdate_daynum(ld: localdate) chrono::daynum = { + const Y = ld.year; + const M = ld.month; + const D = ld.day; + const jdn = ( + (1461 * (Y + 4000 + (M - 14) / 12)) / 4 + + (367 * (M - 2 - 12 * ((M - 14) / 12))) / 12 + - (3 * ((Y + 4900 + (M - 14) / 12) / 100)) / 4 + + D + - 32075 + ); + const dn = jdn; + return dn; +}; diff --git a/chrono/isocal/datetime.ha b/chrono/isocal/datetime.ha @@ -1,20 +1,37 @@ use time; -// Creates a new datetime, using a [[calendardate]]. +// 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. +export type datetime = struct { + date: localdate, + time: localtime, + loc: locality, +}; + +// Creates a new datetime // // // 1995 July 18th 09:16:00.000 -// datetime::new(1995, 07, 18, 9, 16, 0, 0, datetime::local) -// chrono::iso::new(1995, 07, 18, 9, 16, 0, 0, chrono::iso::local) +// isocal::new(1995, 07, 18, 9, 16, 0, 0, isocal::local) // // For alternative forms, assemble a datetime manually using the desired types. export fn new( year: i64, - month: u8, - day: u8, - hour: u8, - min: u8, - sec: u8, - nsec: u64, + month: int, + day: int, + hour: int, + min: int, + sec: int, + nsec: int, loc: locality, ) datetime = datetime { date = localdate { @@ -40,34 +57,21 @@ export fn now() datetime = { // TODO: figure out calendar arithmetics first year = 1970, month = 1, - day = (i.sec / 86400): u8, + day = (i.sec / 86400): int, }, time = localtime { - hour = (i.sec / 3600): u8 % 24, - min = (i.sec / 60): u8 % 60, - sec = i.sec: u8 % 60, - nsec = i.nsec: u64, + hour = (i.sec / 3600): int % 24, + min = (i.sec / 60): int % 60, + sec = i.sec: int % 60, + nsec = i.nsec: int, }, // TODO: What to do here? How to get the timezone from - // /etc/localtime? How to determine the system's timescale? - // Assuming UTC may be sufficient. + // /etc/localtime or $TZ? How to determine the system's + // timescale? Assuming UTC may be sufficient. loc = local, }; return dt; }; -// Normalizes all fields a datetime -export fn normalize(dt: datetime) datetime = { - validate(dt)!; - // TODO - return dt; -}; - -// Validates a datetime -export fn validate(dt: datetime) (datetime | error) = { - // TODO - return dt; -}; - export type error = !void; diff --git a/chrono/isocal/time.ha b/chrono/isocal/time.ha @@ -0,0 +1,31 @@ +use time; + +// Represents a ISO time of day +export type localtime = struct { + hour: int, + min: int, + sec: int, + nsec: int, +}; + +export fn conv_time_localtime(t: time::duration) localtime = { + const lt = localtime { + hour = (t / time::HOUR): int, + min = (t / time::MINUTE): int % 60, + sec = (t / time::SECOND): int % 60, + nsec = (t % time::SECOND): int, + }; + return lt; +}; + +export fn conv_localtime_time(lt: localtime) time::duration = { + const t = ( + (lt.hour * time::HOUR) + + (lt.min * time::MINUTE) + + (lt.sec * time::SECOND) + + (lt.nsec * time::NANOSECOND) + ); + return t; +}; + + diff --git a/chrono/isocal/types.ha b/chrono/isocal/types.ha @@ -1,58 +1,19 @@ use time; use chrono; -// 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. -export type datetime = struct { - date: localdate, - time: localtime, - loc: locality, -}; - -// Represents a ISO date -export type localdate = struct { - // days since calendar epoch - epochday: i64, - - // ISO calendar date - year: i64, - month: u8, - day: u8, - - // ISO week date - weekyear: i64, - week: u8, - weekday: u8, - - // ISO ordinal date - yearday: uint, -}; - -// Represents a ISO time of day -export type localtime = struct { - hour: u8, - min: u8, - sec: u8, - nsec: u64, -}; +// // Represents a timezone +// // Allows conversion between datetimes and instances according to a timescale +// export type timezone = struct { +// chrono::timezone, +// to_tz_utc: nullable *converter, +// from_tz_utc: nullable *converter, +// to_tz_tai: nullable *converter, +// from_tz_tai: nullable *converter, +// }; + +export type converter = fn(dt: datetime) datetime; // Represents the locality of a datetime -// -// Notes: -// `timescale` may not meaningfully belong here. It's here because sometimes ISO -// datetimes like "1999-05-13T12:30:45.125 UTC" exist as a human-readible form -// of a UTC instant, using the ISO calendar, and where localtime.sec ranges only -// from 0-59. export type locality = (local | zoneoffset | timezone); // Represents its associated datetime as local @@ -66,14 +27,8 @@ export type local = void; export type zoneoffset = time::duration; // Represents a timezone; a political region with a ruleset regarding offsets -// -// Notes: -// timezone types design needs a lot of thought. Enum is probably not a good -// idea. Initially this was a `type enum str {}`, which may have been a worse -// idea. Maybe we need a `fn tzdb(tz: str)` like other langs' libs. -export type timezone = enum { - UTC, - EUROPE_LONDON, - // ... +export type timezone = struct { + timescale: chrono::timescale, + // TODO + // func...: *fn... }; - diff --git a/chrono/timescales.ha b/chrono/timescales.ha @@ -2,10 +2,12 @@ use time; // Represents a linear scale of time, with an epoch. export type timescale = struct { - to_tai: *fn(i: time::instant) []time::instant, - from_tai: *fn(i: time::instant) []time::instant, + to_tai: *converter, + from_tai: *converter, }; +export type converter = fn(i: time::instant) []time::instant; + // International Atomic Time // diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -184,15 +184,17 @@ bytes() { chrono() { gen_srcs chrono \ chronology.ha \ - timescales.ha \ - calendar.ha + timescales.ha gen_ssa chrono time } chrono_isocal() { gen_srcs chrono::isocal \ + types.ha \ + calendar.ha \ datetime.ha \ - types.ha + date.ha \ + time.ha gen_ssa chrono::isocal chrono time } diff --git a/stdlib.mk b/stdlib.mk @@ -722,8 +722,7 @@ $(HARECACHE)/bytes/bytes-any.ssa: $(stdlib_bytes_any_srcs) $(stdlib_rt) $(stdlib # chrono (+any) stdlib_chrono_any_srcs= \ $(STDLIB)/chrono/chronology.ha \ - $(STDLIB)/chrono/timescales.ha \ - $(STDLIB)/chrono/calendar.ha + $(STDLIB)/chrono/timescales.ha $(HARECACHE)/chrono/chrono-any.ssa: $(stdlib_chrono_any_srcs) $(stdlib_rt) $(stdlib_time_$(PLATFORM)) @printf 'HAREC \t$@\n' @@ -733,8 +732,11 @@ $(HARECACHE)/chrono/chrono-any.ssa: $(stdlib_chrono_any_srcs) $(stdlib_rt) $(std # chrono::isocal (+any) stdlib_chrono_isocal_any_srcs= \ + $(STDLIB)/chrono/isocal/types.ha \ + $(STDLIB)/chrono/isocal/calendar.ha \ $(STDLIB)/chrono/isocal/datetime.ha \ - $(STDLIB)/chrono/isocal/types.ha + $(STDLIB)/chrono/isocal/date.ha \ + $(STDLIB)/chrono/isocal/time.ha $(HARECACHE)/chrono/isocal/chrono_isocal-any.ssa: $(stdlib_chrono_isocal_any_srcs) $(stdlib_rt) $(stdlib_chrono_$(PLATFORM)) $(stdlib_time_$(PLATFORM)) @printf 'HAREC \t$@\n' @@ -2664,8 +2666,7 @@ $(TESTCACHE)/bytes/bytes-any.ssa: $(testlib_bytes_any_srcs) $(testlib_rt) $(test # chrono (+any) testlib_chrono_any_srcs= \ $(STDLIB)/chrono/chronology.ha \ - $(STDLIB)/chrono/timescales.ha \ - $(STDLIB)/chrono/calendar.ha + $(STDLIB)/chrono/timescales.ha $(TESTCACHE)/chrono/chrono-any.ssa: $(testlib_chrono_any_srcs) $(testlib_rt) $(testlib_time_$(PLATFORM)) @printf 'HAREC \t$@\n' @@ -2675,8 +2676,11 @@ $(TESTCACHE)/chrono/chrono-any.ssa: $(testlib_chrono_any_srcs) $(testlib_rt) $(t # chrono::isocal (+any) testlib_chrono_isocal_any_srcs= \ + $(STDLIB)/chrono/isocal/types.ha \ + $(STDLIB)/chrono/isocal/calendar.ha \ $(STDLIB)/chrono/isocal/datetime.ha \ - $(STDLIB)/chrono/isocal/types.ha + $(STDLIB)/chrono/isocal/date.ha \ + $(STDLIB)/chrono/isocal/time.ha $(TESTCACHE)/chrono/isocal/chrono_isocal-any.ssa: $(testlib_chrono_isocal_any_srcs) $(testlib_rt) $(testlib_chrono_$(PLATFORM)) $(testlib_time_$(PLATFORM)) @printf 'HAREC \t$@\n'