2023-09-16 05:24:05 +01:00
|
|
|
local DateTime = require("@lune/datetime")
|
2023-09-11 18:52:07 +01:00
|
|
|
|
2023-09-16 05:24:05 +01:00
|
|
|
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")
|
2023-09-11 18:52:07 +01:00
|
|
|
assert(
|
2023-09-16 05:24:05 +01:00
|
|
|
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
|
2023-09-11 18:52:07 +01:00
|
|
|
),
|
2023-09-16 05:24:05 +01:00
|
|
|
":"
|
|
|
|
)
|
|
|
|
|
|
|
|
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"
|
2023-09-11 18:52:07 +01:00
|
|
|
)
|
2023-09-16 05:24:05 +01:00
|
|
|
|
|
|
|
-- 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
|