From 31792a3a432f792f2228f1ec1cd85f8eea3d3c10 Mon Sep 17 00:00:00 2001 From: KitAmbraid <128903658+KitAmbraid@users.noreply.github.com> Date: Sat, 22 Feb 2025 12:00:54 +0100 Subject: [PATCH] space lua: os.date add support for %U, %V and %W (#1250) --- common/space_lua/stdlib/os.ts | 33 +++++++++++++++++++++++++++-- common/space_lua/stdlib/os_test.lua | 6 +++++- website/API/os.md | 3 +++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/common/space_lua/stdlib/os.ts b/common/space_lua/stdlib/os.ts index 947e975f..2dea449c 100644 --- a/common/space_lua/stdlib/os.ts +++ b/common/space_lua/stdlib/os.ts @@ -1,5 +1,31 @@ import { LuaBuiltinFunction, LuaTable } from "$common/space_lua/runtime.ts"; +const ONE_DAY = 1000 * 60 * 60 * 24; + +// weekStartDay: 0 for Sunday, 1 for Monday +// iso: if true, week 01 contains Jan. 4th and prior week is week 52 or 53 of year prior +// if false, week 01 starts on first weekStartDay of the year and prior week is week 00 +function weekNumber(inDate: Date, weekStartDay: number, iso: boolean): number { + const year = inDate.getFullYear(); + const jan1 = new Date(year, 0, 1); + + let jan1Week: number; + if (iso) { + jan1Week = (jan1.getDay() - weekStartDay + 7) % 7 < 3 ? 1 : 0; + } else jan1Week = jan1.getDay() == weekStartDay ? 1 : 0; + + const week = Math.floor( + ((inDate.getTime() - jan1.getTime() + ONE_DAY) / ONE_DAY) / 7, + ) + jan1Week; + + if (iso && week == 0) { + const dec31 = new Date(inDate.getFullYear() - 1, 11, 31); + return weekNumber(dec31, weekStartDay, iso); + } + + return week; +} + export const osApi = new LuaTable({ time: new LuaBuiltinFunction((_sf, tbl?: LuaTable) => { if (tbl) { @@ -69,10 +95,13 @@ export const osApi = new LuaTable({ "%j": () => { const start = new Date(date.getFullYear(), 0, 0); const diff = date.getTime() - start.getTime(); - const oneDay = 1000 * 60 * 60 * 24; - const dayOfYear = Math.floor(diff / oneDay); + const dayOfYear = Math.floor(diff / ONE_DAY); return dayOfYear.toString().padStart(3, "0"); }, + // Week + "%U": () => weekNumber(date, 0, false).toString().padStart(2, "0"), + "%W": () => weekNumber(date, 1, false).toString().padStart(2, "0"), + "%V": () => weekNumber(date, 1, true).toString().padStart(2, "0"), // Time zone "%Z": () => { const match = date.toTimeString().match(/\((.*)\)/); diff --git a/common/space_lua/stdlib/os_test.lua b/common/space_lua/stdlib/os_test.lua index 85c7d35e..bf907a6d 100644 --- a/common/space_lua/stdlib/os_test.lua +++ b/common/space_lua/stdlib/os_test.lua @@ -6,4 +6,8 @@ end -- Basic OS functions assert(os.time() > 0) -assert(os.date("%Y-%m-%d", os.time({ year = 2020, month = 1, day = 1 })) == "2020-01-01") \ No newline at end of file +assert(os.date("%Y-%m-%d", os.time({ year = 2020, month = 1, day = 1 })) == "2020-01-01") + +-- Week calculations +assert(os.date("%U %V %W", os.time({ year = 2051, month = 1, day = 1 })) == "01 52 00") +assert(os.date("%U %V %W", os.time({ year = 2025, month = 2, day = 18})) == "07 08 07") diff --git a/website/API/os.md b/website/API/os.md index 6d59e773..1fe578c2 100644 --- a/website/API/os.md +++ b/website/API/os.md @@ -35,6 +35,9 @@ Format specifiers: - `%A`: Full weekday name (e.g., "Sunday") - `%a`: Abbreviated weekday name (e.g., "Sun") - `%w`: Weekday (0-6, Sunday is 0) +- `%U`: Week of the year, starting with the first Sunday as the first day of week 01 (00-53) +- `%W`: Week of the year, starting with the first Monday as the first day of week 01 (00-53) +- `%V`: ISO 8601 week of the year (01-53) (see [Wikipedia](https://en.wikipedia.org/wiki/ISO_week_date)) - `%j`: Day of year (001-366) - `%Z`: Time zone name - `%z`: Time zone offset from UTC