lune/tests/datetime/toIsoDate.luau

72 lines
2.7 KiB
Lua

local DateTime = require("@lune/datetime")
local now = DateTime.now()
local nowIso = now:toIsoDate()
-- Make sure we have separator characters, T to separate date & time, + or Z to separate timezone
local dateTimeSplitIdx = string.find(nowIso, "T")
local timezoneSplitIdx = string.find(nowIso, "+")
local timezoneZeroedIdx = string.find(nowIso, "Z")
assert(dateTimeSplitIdx ~= nil, "Missing date & time separator 'T' in iso 8601 string")
assert(
timezoneSplitIdx ~= nil or timezoneZeroedIdx ~= nil,
"Missing timezone separator '+' or 'Z' in iso date string"
)
-- Split date (before T) by dashes, split time (after T, before + or Z)
-- by colons, we should then get 3 substrings for each of date & time
local dateParts = string.split(string.sub(nowIso, 1, dateTimeSplitIdx - 1), "-")
local timeParts = string.split(
string.sub(
nowIso,
dateTimeSplitIdx + 1,
((timezoneSplitIdx or timezoneZeroedIdx) :: number) - 1
),
":"
)
assert(#dateParts == 3, "Date partial of iso 8601 should consist of 3 substrings, separated by '-'")
assert(#timeParts == 3, "Time partial of iso 8601 should consist of 3 substrings, separated by ':'")
-- date should be in format YYYY:MM::DD
-- time should be in format HH:MM:SS with optional fraction for seconds
assert(string.match(dateParts[1], "^%d%d%d%d$"), "Date partial should have 4 digits for year")
assert(string.match(dateParts[2], "^%d%d$"), "Date partial should have 2 digits for month")
assert(string.match(dateParts[3], "^%d%d$"), "Date partial should have 2 digits for day")
assert(string.match(timeParts[1], "^%d%d$"), "Time partial should have 2 digits for hour")
assert(string.match(timeParts[2], "^%d%d$"), "Time partial should have 2 digits for minute")
assert(
string.match(timeParts[3], "^%d%d%.?%d*$") and tonumber(timeParts[3]) ~= nil,
"Time partial should have minimum 2 digits with optional fraction for seconds"
)
-- Timezone specifier is either 'Z' for zeroed out timezone (no offset),
-- in which case we don't need to check anything other than it being the
-- last character, or it can be a timezone offset in the format HH::MM
if timezoneZeroedIdx ~= nil then
-- No timezone offset
assert(
timezoneZeroedIdx == #nowIso,
"Timezone specifier 'Z' must be at the last character in iso 8601 string"
)
elseif timezoneSplitIdx ~= nil then
-- Timezone offset
local timezoneParts = string.split(string.sub(nowIso, timezoneSplitIdx + 1), ":")
assert(#timezoneParts == 2, "Timezone partial should consist of 2 substings, separated by ':'")
assert(
string.match(timezoneParts[1], "^%d%d$"),
"Timezone partial should have 2 digits for hour"
)
assert(
string.match(timezoneParts[2], "^%d%d$"),
"Timezone partial should have 2 digits for minute"
)
else
error("unreachable")
end