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:
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' =>