-
-
Notifications
You must be signed in to change notification settings - Fork 221
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add
core.tempus
module for date management
- Loading branch information
Showing
2 changed files
with
310 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,5 +46,6 @@ return neorg.modules.create_meta( | |
"core.storage", | ||
"core.syntax", | ||
"core.tangle", | ||
"core.tempus", | ||
"core.upgrade" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,309 @@ | ||
local module = neorg.modules.create("core.tempus") | ||
|
||
-- NOTE: Maybe encapsulate whole date parser in a single PEG grammar? | ||
local time_regex = vim.re.compile([[{%d%d?} ":" {%d%d} ("." {%d%d?})?]]) | ||
|
||
local timezone_list = { | ||
"ACDT", | ||
"ACST", | ||
"ACT", | ||
"ACWST", | ||
"ADT", | ||
"AEDT", | ||
"AEST", | ||
"AET", | ||
"AFT", | ||
"AKDT", | ||
"AKST", | ||
"ALMT", | ||
"AMST", | ||
"AMT", | ||
"ANAT", | ||
"AQTT", | ||
"ART", | ||
"AST", | ||
"AWST", | ||
"AZOST", | ||
"AZOT", | ||
"AZT", | ||
"BNT", | ||
"BIOT", | ||
"BIT", | ||
"BOT", | ||
"BRST", | ||
"BRT", | ||
"BST", | ||
"BTT", | ||
"CAT", | ||
"CCT", | ||
"CDT", | ||
"CEST", | ||
"CET", | ||
"CHADT", | ||
"CHAST", | ||
"CHOT", | ||
"CHOST", | ||
"CHST", | ||
"CHUT", | ||
"CIST", | ||
"CKT", | ||
"CLST", | ||
"CLT", | ||
"COST", | ||
"COT", | ||
"CST", | ||
"CT", | ||
"CVT", | ||
"CWST", | ||
"CXT", | ||
"DAVT", | ||
"DDUT", | ||
"DFT", | ||
"EASST", | ||
"EAST", | ||
"EAT", | ||
"ECT", | ||
"EDT", | ||
"EEST", | ||
"EET", | ||
"EGST", | ||
"EGT", | ||
"EST", | ||
"ET", | ||
"FET", | ||
"FJT", | ||
"FKST", | ||
"FKT", | ||
"FNT", | ||
"GALT", | ||
"GAMT", | ||
"GET", | ||
"GFT", | ||
"GILT", | ||
"GIT", | ||
"GMT", | ||
"GST", | ||
"GYT", | ||
"HDT", | ||
"HAEC", | ||
"HST", | ||
"HKT", | ||
"HMT", | ||
"HOVST", | ||
"HOVT", | ||
"ICT", | ||
"IDLW", | ||
"IDT", | ||
"IOT", | ||
"IRDT", | ||
"IRKT", | ||
"IRST", | ||
"IST", | ||
"JST", | ||
"KALT", | ||
"KGT", | ||
"KOST", | ||
"KRAT", | ||
"KST", | ||
"LHST", | ||
"LINT", | ||
"MAGT", | ||
"MART", | ||
"MAWT", | ||
"MDT", | ||
"MET", | ||
"MEST", | ||
"MHT", | ||
"MIST", | ||
"MIT", | ||
"MMT", | ||
"MSK", | ||
"MST", | ||
"MUT", | ||
"MVT", | ||
"MYT", | ||
"NCT", | ||
"NDT", | ||
"NFT", | ||
"NOVT", | ||
"NPT", | ||
"NST", | ||
"NT", | ||
"NUT", | ||
"NZDT", | ||
"NZST", | ||
"OMST", | ||
"ORAT", | ||
"PDT", | ||
"PET", | ||
"PETT", | ||
"PGT", | ||
"PHOT", | ||
"PHT", | ||
"PHST", | ||
"PKT", | ||
"PMDT", | ||
"PMST", | ||
"PONT", | ||
"PST", | ||
"PWT", | ||
"PYST", | ||
"PYT", | ||
"RET", | ||
"ROTT", | ||
"SAKT", | ||
"SAMT", | ||
"SAST", | ||
"SBT", | ||
"SCT", | ||
"SDT", | ||
"SGT", | ||
"SLST", | ||
"SRET", | ||
"SRT", | ||
"SST", | ||
"SYOT", | ||
"TAHT", | ||
"THA", | ||
"TFT", | ||
"TJT", | ||
"TKT", | ||
"TLT", | ||
"TMT", | ||
"TRT", | ||
"TOT", | ||
"TVT", | ||
"ULAST", | ||
"ULAT", | ||
"UTC", | ||
"UYST", | ||
"UYT", | ||
"UZT", | ||
"VET", | ||
"VLAT", | ||
"VOLT", | ||
"VOST", | ||
"VUT", | ||
"WAKT", | ||
"WAST", | ||
"WAT", | ||
"WEST", | ||
"WET", | ||
"WIB", | ||
"WIT", | ||
"WITA", | ||
"WGST", | ||
"WGT", | ||
"WST", | ||
"YAKT", | ||
"YEKT", | ||
} | ||
|
||
module.public = { | ||
--- Parses a date and returns a table representing the date | ||
---@param input string #The input which should follow the date specification found in the Norg spec. | ||
---@return {weekday: {name: string, number: number}?, day: number?, month: {name: string, number: number}?, year: number?, timezone: string?, time: {hour: number, minute: number, second: number?}?}|string #The data extracted from the input | ||
parse_date = function(input) | ||
local weekdays = {} | ||
for i = 1, 7 do | ||
table.insert(weekdays, os.date("%A", os.time({ year = 2000, month = 5, day = i })):lower()) | ||
end | ||
|
||
local months = {} | ||
for i = 1, 12 do | ||
table.insert(months, os.date("%B", os.time({ year = 2000, month = i, day = 1 })):lower()) | ||
end | ||
|
||
local output = {} | ||
|
||
for word in vim.gsplit(input, "%s+") do | ||
if word:len() == 0 then | ||
goto continue | ||
end | ||
|
||
if word:match("^-?%d%d%d%d+$") then | ||
output.year = tonumber(word) | ||
elseif word:match("^%d+,?$") then | ||
output.day = tonumber(word:match("%d+")) | ||
elseif vim.list_contains(timezone_list, word:upper()) then | ||
output.timezone = word:upper() | ||
else | ||
do | ||
local hour, minute, second = vim.re.match(word, time_regex) | ||
|
||
if hour and minute then | ||
output.time = { | ||
hour = tonumber(hour), | ||
minute = tonumber(minute), | ||
second = second and tonumber(second) or nil, | ||
} | ||
|
||
goto continue | ||
end | ||
end | ||
|
||
do | ||
local valid_months = {} | ||
|
||
-- Check for month abbreviation | ||
for i, month in ipairs(months) do | ||
if vim.startswith(month, word:lower()) then | ||
valid_months[month] = i | ||
end | ||
end | ||
|
||
local count = vim.tbl_count(valid_months) | ||
if count > 1 then | ||
return "Ambiguous month name! Possible interpretations: " | ||
.. table.concat(vim.tbl_keys(valid_months), ",") | ||
elseif count == 1 then | ||
local valid_month_name, valid_month_number = next(valid_months) | ||
|
||
output.month = { | ||
name = valid_month_name, | ||
number = valid_month_number, | ||
} | ||
|
||
goto continue | ||
end | ||
end | ||
|
||
do | ||
local valid_weekdays = {} | ||
|
||
-- Check for weekday abbreviation | ||
for i, weekday in ipairs(weekdays) do | ||
if vim.startswith(weekday, word:lower()) then | ||
valid_weekdays[weekday] = i | ||
end | ||
end | ||
|
||
local count = vim.tbl_count(valid_weekdays) | ||
if count > 1 then | ||
return "Ambiguous weekday name! Possible interpretations: " | ||
.. table.concat(vim.tbl_keys(valid_weekdays), ",") | ||
elseif count == 1 then | ||
local valid_weekday_name, valid_weekday_number = next(valid_weekdays) | ||
|
||
output.weekday = { | ||
name = valid_weekday_name, | ||
number = valid_weekday_number, | ||
} | ||
|
||
goto continue | ||
end | ||
end | ||
|
||
return "Unidentified string: `" | ||
.. word | ||
.. "` - make sure your locale and language are set correctly if you are using a language other than English!" | ||
end | ||
|
||
::continue:: | ||
end | ||
|
||
return output | ||
end, | ||
} | ||
|
||
return module |