hare

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

commit 0783e33c2fb5f74d1787a23aae227249a91d7e58
parent e8ac6ea44ea58db723977d9603a894aa7baf03aa
Author: Nihal Jere <nihal@nihaljere.xyz>
Date:   Sat,  7 May 2022 11:26:32 -0500

datetime: implement %U format specifier and add a test

This is stolen from musl, adjusted to deal with the way datetime
stores yeardays and weekdays.

Signed-off-by: Nihal Jere <nihal@nihaljere.xyz>

Diffstat:
Mdatetime/chronology.ha | 22++++++++++++++++++++++
Mdatetime/date.ha | 34++++++++++++++++++++++++++++++++++
Mdatetime/datetime.ha | 2++
Mdatetime/format.ha | 3+--
4 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/datetime/chronology.ha b/datetime/chronology.ha @@ -34,6 +34,9 @@ export fn isoweekyear(dt: *datetime) int = _isoweekyear(dt); // Returns a [[datetime]]'s Gregorian week export fn week(dt: *datetime) int = _week(dt); +// Returns a [[datetime]]'s Gregorian week starting Sunday +export fn week_starting_sunday(dt: *datetime) int = _week_starting_sunday(dt); + // Returns a [[datetime]]'s ISO week export fn isoweek(dt: *datetime) int = _isoweek(dt); @@ -190,6 +193,25 @@ fn _week(dt: *datetime) int = { }; }; +fn _week_starting_sunday(dt: *datetime) int = { + match (dt.week) { + case void => + if (dt.yearday is void) { + _yearday(dt); + }; + if (dt.weekday is void) { + _weekday(dt); + }; + dt.weeksunday = calc_week_starting_sunday( + dt.yearday: int, + dt.weekday: int, + ); + return dt.weeksunday: int; + case let w: int => + return w; + }; +}; + fn _isoweek(dt: *datetime) int = { match (dt.isoweek) { case void => diff --git a/datetime/date.ha b/datetime/date.ha @@ -183,6 +183,13 @@ fn calc_week(yd: int, wd: int) int = { return (yd + 7 - wd) / 7; }; +// Calculates the week within a Gregorian year [0..53], +// given a yearday and Gregorian weekday. +// All days in a new year before the year's first Sunday belong to week 0. +fn calc_week_starting_sunday(yd: int, wd: int) int = { + return (yd + 6 - (wd % 7)) / 7; +}; + // Calculates the weekday, given a epochal day, // from Monday=1 to Sunday=7 fn calc_weekday(e: chrono::epochal) int = { @@ -529,6 +536,33 @@ fn calc_epochal_from_yd(y: int, yd: int) (chrono::epochal | invalid) = { }; }; +@test fn calc_week_starting_sunday() void = { + const cases = [ + ((1, 1), 0), + ((1, 2), 0), + ((1, 3), 0), + ((1, 4), 0), + ((1, 5), 0), + ((1, 6), 0), + ((1, 7), 1), + ((21, 2), 3), + ((61, 3), 9), + ((193, 5), 27), + ((229, 1), 33), + ((286, 4), 41), + ((341, 7), 49), + ((365, 6), 52), + ((366, 1), 53), + ]; + + for (let i = 0z; i < len(cases); i += 1) { + const params = cases[i].0; + const expect = cases[i].1; + const actual = calc_week_starting_sunday(params.0, params.1); + assert(expect == actual, "week miscalculation"); + }; +}; + @test fn calc_weekday() void = { const cases = [ (-999999, 4), // -0768-02-05 diff --git a/datetime/datetime.ha b/datetime/datetime.ha @@ -19,6 +19,7 @@ export type datetime = struct { isoweekyear: (void | int), isoweek: (void | int), week: (void | int), + weeksunday: (void | int), weekday: (void | int), hour: (void | int), @@ -41,6 +42,7 @@ fn init() datetime = datetime { isoweekyear = void, isoweek = void, week = void, + weeksunday = void, weekday = void, hour = void, diff --git a/datetime/format.ha b/datetime/format.ha @@ -131,8 +131,7 @@ fn fmtout(out: io::handle, r: rune, dt: *datetime) (size | io::error) = { case 'u' => return fmt::fprint(out, strconv::itos(weekday(dt))); case 'U' => - // return fmt::fprintf(out, "{:02}", week_starting_sunday(dt)); - abort("datetime::format: %U: TODO"); // TODO + return fmt::fprintf(out, "{:02}", week_starting_sunday(dt)); case 'w' => return fmt::fprint(out, strconv::itos(weekday(dt) % 7)); case 'W' =>