hare

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

commit aadc7c3701073aa15489f6a6a27a8e7bc441b1fa
parent febd5fe36cb010c7382287c6729be0e4831aa423
Author: Curtis Arthaud <uku82@gmx.fr>
Date:   Thu, 11 Jul 2024 20:47:24 +0200

time::date: realize: support ISO week dates

Signed-off-by: Curtis Arthaud <uku82@gmx.fr>
Co-authored-by: Byron Torres <b@torresjrjr.com>

Diffstat:
Mtime/date/daydate.ha | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtime/date/virtual.ha | 22+++++++++++++---------
2 files changed, 72 insertions(+), 9 deletions(-)

diff --git a/time/date/daydate.ha b/time/date/daydate.ha @@ -42,6 +42,15 @@ fn is_valid_yd(y: int, yd: int) bool = { return yd >= 1 && yd <= calc_days_in_year(y); }; +// Calculates whether a given ISO week-numbering year, and day-of-year, +// is a valid date. +fn is_valid_isoywd(iy: int, iw: int, wd: int) bool = { + return ( + iw > 0 && iw <= (if (islongisoyear(iy)) 53 else 52) + && wd >= MONDAY && wd <= SUNDAY + ); +}; + // Calculates the number of days in the given month of the given year. fn calc_days_in_month(y: int, m: int) int = { const days_per_month: [_]int = [ @@ -258,6 +267,17 @@ fn calc_daydate__yd(y: int, yd: int) (i64 | invalid) = { return calc_daydate__ymd(y, 1, 1)? + yd - 1; }; +// Calculates the daydate, +// given an ISO week-numbering year, ISO week, and day-of-week. +fn calc_daydate__isoywd(iy: int, iw: int, wd: int) (i64 | invalid) = { + if (!is_valid_isoywd(iy, iw, wd)) { + return invalid; + }; + const jan4 = calc_daydate__ymd(iy, 1, 4)?; + const isoyearstart = jan4 - calc_weekday(jan4); + return isoyearstart + (iw - 1) * 7 + wd; +}; + @test fn calc_daydate__ymd() void = { const cases = [ (( -768, 2, 5), -999999, false), @@ -382,6 +402,45 @@ fn calc_daydate__yd(y: int, yd: int) (i64 | invalid) = { "calc_daydate__yd() did not reject invalid yearday"); }; +@test fn calc_daydate__isoywd() void = { + const testcases = [ + (( 1965, 12, 1), -1745, false), + (( 1970, 1, 2), -1, false), + (( 1970, 1, 3), 0, false), + (( 1970, 1, 4), 1, false), + (( 1999, 52, 4), 10956, false), + (( 1999, 52, 5), 10957, false), + (( 1999, 52, 6), 10958, false), + (( 2038, 3, 0), 24854, false), + (( 2038, 3, 1), 24855, false), + (( 2038, 3, 2), 24856, false), + (( 2243, 42, 1), 100000, false), + (( 4707, 48, 3), 999999, false), + (( 4707, 48, 4), 1000000, false), + ((29349, 4, 5), 9999999, false), + + (( 1970,-99,-99), 0, true), + (( 1970, -9, -9), 0, true), + (( 1970, -1, -1), 0, true), + (( 1970, 0, 0), 0, true), + (( 1970, 0, 1), 0, true), + (( 1970, 1, 99), 0, true), + (( 1970, 99, 99), 0, true), + ]; + for (let (params, expect, should_error) .. testcases) { + const actual = calc_daydate__isoywd( + params.0, params.1, params.2, + ); + + if (should_error) { + assert(actual is invalid, "invalid date accepted"); + } else { + assert(actual is i64, "valid date not accepted"); + assert(actual as i64 == expect, "date miscalculation"); + }; + }; +}; + @test fn calc_ymd() void = { const cases = [ (-999999, ( -768, 2, 5)), diff --git a/time/date/virtual.ha b/time/date/virtual.ha @@ -364,9 +364,6 @@ fn realize_datetimezoff( return invalid; }; yield cc * 100 + yy; - } else { - lacking |= lack::DAYDATE; - yield :daydate; }; if ( @@ -374,7 +371,7 @@ fn realize_datetimezoff( v.day is int ) { v.daydate = calc_daydate__ymd( - year, + year as int, v.month as int, v.day as int, )?; @@ -382,7 +379,7 @@ fn realize_datetimezoff( v.yearday is int ) { v.daydate = calc_daydate__yd( - year, + year as int, v.yearday as int, )?; } else if ( @@ -390,13 +387,20 @@ fn realize_datetimezoff( v.weekday is int ) { v.daydate = calc_daydate__ywd( - year, + year as int, v.week as int, v.weekday as int, )?; - } else if (false) { - // TODO: calendar.ha: calc_daydate__isoywd() - void; + } else if ( + v.isoweekyear is int && + v.isoweek is int && + v.weekday is int + ) { + v.daydate = calc_daydate__isoywd( + v.isoweekyear as int, + v.isoweek as int, + v.weekday as int, + )?; } else { // cannot deduce daydate lacking |= insufficient::DAYDATE;