% datemultical-format.def % % datemultical: Named dates with multi-calendar formatting for LaTeX. % % Copyright (C) 2026 Amer Amikhteh % % This file is part of the datemultical package. % % This work is free software: you may redistribute it and/or modify % it under the terms of the LaTeX Project Public License as published % by the LaTeX Project, either version 1.3c of the License, or % (at your option) any later version. % % This work is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty % of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. % % The full license text is available at: % https://www.latex-project.org/lppl/ % % This work is "maintained" by Amer Amikhteh. % % The current maintainer of this work is Amer Amikhteh. \NeedsTeXFormat{LaTeX2e} \ProvidesFile{datemultical-format.def} [2026/10/18 v0.2.0 Multi-calendar date formatting] \ExplSyntaxOn \makeatletter % ================================================= % Temporary variables % ================================================= \tl_new:N \l_dmc_format_tl \tl_new:N \l_dmc_style_tl \tl_new:N \l_dmc_calendar_tl \cs_new_protected:Npn \dmc_style_store:nnn #1 #2 #3 { \tl_set:Nx \l_dmc_calendar_tl { \tl_to_str:n {#1} } \cs_gset:cpn { g_dmc_style_ \l_dmc_calendar_tl _ \tl_to_str:n {#2} _tl } {#3} } \cs_new_protected:Npn \dmc_style_fetch:nnN #1 #2 #3 { \tl_set:Nx \l_dmc_calendar_tl { \tl_to_str:n {#1} } \cs_if_exist:cTF { g_dmc_style_ \l_dmc_calendar_tl _ \tl_to_str:n {#2} _tl } { \tl_set:Nx #3 { \use:c { g_dmc_style_ \l_dmc_calendar_tl _ \tl_to_str:n {#2} _tl } } } { \tl_clear:N #3 } } % ================================================= % Calendar-dependent month captions % ================================================= \cs_new:Npn \dmc_format_month_name:nn #1 #2 { \str_case:nnF {#1} { {gr} { \dmc_month_name_gr:n {#2} } {sh} { \dmc_month_name_sh:n {#2} } {lh} { \dmc_month_name_lh:n {#2} } } {} } \cs_new:Npn \dmc_format_month_persian:nn #1 #2 { \str_case:nnF {#1} { {gr} { \dmc_month_name_gr_persian:n {#2} } {sh} { \dmc_month_name_sh_persian:n {#2} } {lh} { \dmc_month_name_lh_persian:n {#2} } } {} } \cs_new:Npn \dmc_format_month_abbrev:nn #1 #2 { \str_case:nnF {#1} { {gr} { \dmc_month_abbrev_gr:n {#2} } {sh} { \dmc_month_abbrev_sh:n {#2} } {lh} { \dmc_month_abbrev_lh:n {#2} } } {} } % ================================================= % Multi-digit formatting % ================================================= \cs_new:Npn \dmc_format_two_digits:n #1 { \int_compare:nNnTF {#1} < {10} { 0#1 } { #1 } } \cs_new:Npn \dmc_format_four_digits:n #1 { \int_compare:nNnTF {#1} < {10} { 000#1 } { \int_compare:nNnTF {#1} < {100} { 00#1 } { \int_compare:nNnTF {#1} < {1000} { 0#1 } { #1 } } } } % ================================================= % Bool to intiger % ================================================= \cs_new:Npn \dmc_format_bool_to_int:n #1 { \exp_args:Nx \str_case:nnF {#1} { {true} {1} {false} {0} } {#1} } % ================================================= % Japanese era formatting % ================================================= \cs_new:Npn \dmc_format_japanese_era:n #1 { \exp_args:Nx \str_case:nnF {#1} { {meiji} {1} {taisho} {2} {showa} {3} {heisei} {4} {reiwa} {5} } {#1} } % ================================================= % Internal formatting command % ================================================= \cs_new_protected:Npn \dmc_format_replace_one:nnnnn #1 #2 #3 #4 #5 { \tl_replace_all:Nnn \l_dmc_format_tl {#3} { \tl_if_blank:nTF {#5} { \dmcget [#1] {#2} {#4} } { #5 { \dmcget [#1] {#2} {#4} } } } } \cs_new_protected:Npn \dmc_format_replace_two:nnnnn #1 #2 #3 #4 #5 { \tl_replace_all:Nnn \l_dmc_format_tl {#3} { \tl_if_blank:nTF {#5} { \dmcget [#1] {#2} {#4} } { #5 {#1} { \dmcget [#1] {#2} {#4} } } } } \cs_new_protected:Npn \dmc_format:nnn #1 #2 #3 { \group_begin: \tl_set:Nn \l_dmc_format_tl { #3 } % ================================================= % Four-digit and two-digit year % ================================================= \dmc_format_replace_one:nnnnn {#1} {#2} {yyyy} {year} {\dmc_format_four_digits:n} \dmc_format_replace_one:nnnnn {#1} {#2} {yy} {year} {\dmc_format_two_digits:n} % ================================================= % Longest leap and era tokens % ================================================= \dmc_format_replace_one:nnnnn {#1} {#2} {lmi} {leap_month} {\dmc_format_bool_to_int:n} \dmc_format_replace_one:nnnnn {#1} {#2} {ldi} {leap_day} {\dmc_format_bool_to_int:n} \dmc_format_replace_one:nnnnn {#1} {#2} {lui} {luang} {\dmc_format_bool_to_int:n} \dmc_format_replace_one:nnnnn {#1} {#2} {Gi} {era} {\dmc_format_japanese_era:n} % ================================================= % Two-character leap tokens % ================================================= \dmc_format_replace_one:nnnnn {#1} {#2} {li} {leap} {\dmc_format_bool_to_int:n} \dmc_format_replace_one:nnnnn {#1} {#2} {lm} {leap_month} {} \dmc_format_replace_one:nnnnn {#1} {#2} {ld} {leap_day} {} % ================================================= % Maya Long Count % % lui must precede ui. % ================================================= \dmc_format_replace_one:nnnnn {#1} {#2} {bt} {baktun} {} \dmc_format_replace_one:nnnnn {#1} {#2} {ka} {katun} {} \dmc_format_replace_one:nnnnn {#1} {#2} {tn} {tun} {} \dmc_format_replace_one:nnnnn {#1} {#2} {ui} {uinal} {} \dmc_format_replace_one:nnnnn {#1} {#2} {ki} {kin} {} % ================================================= % Balinese cycles % % lui has already been replaced above. % ================================================= \dmc_format_replace_one:nnnnn {#1} {#2} {lu} {luang} {} \dmc_format_replace_one:nnnnn {#1} {#2} {di} {dwiwara} {} \dmc_format_replace_one:nnnnn {#1} {#2} {tr} {triwara} {} \dmc_format_replace_one:nnnnn {#1} {#2} {cw} {caturwara} {} \dmc_format_replace_one:nnnnn {#1} {#2} {pw} {pancawara} {} \dmc_format_replace_one:nnnnn {#1} {#2} {sw} {sadwara} {} \dmc_format_replace_one:nnnnn {#1} {#2} {sp} {saptawara} {} \dmc_format_replace_one:nnnnn {#1} {#2} {aw} {asatawara} {} \dmc_format_replace_one:nnnnn {#1} {#2} {sg} {sangawara} {} \dmc_format_replace_one:nnnnn {#1} {#2} {da} {dasawara} {} % ================================================= % Month names and numeric month % ================================================= \ifdmc@persian \dmc_format_replace_two:nnnnn {#1} {#2} {MMMMP} {month} {\dmc_format_month_persian:nn} \fi \dmc_format_replace_two:nnnnn {#1} {#2} {MMMM} {month} {\dmc_format_month_name:nn} \dmc_format_replace_two:nnnnn {#1} {#2} {MMM} {month} {\dmc_format_month_abbrev:nn} \dmc_format_replace_one:nnnnn {#1} {#2} {MM} {month} {\dmc_format_two_digits:n} % ================================================= % Day % ================================================= \dmc_format_replace_one:nnnnn {#1} {#2} {dd} {day} {\dmc_format_two_digits:n} % ================================================= % Week % ================================================= \dmc_format_replace_one:nnnnn {#1} {#2} {ww} {week} {\dmc_format_two_digits:n} % ================================================= % Weekday names % ================================================= \ifdmc@persian \dmc_format_replace_one:nnnnn {#1} {#2} {EEEEP} {weekday} {\dmc_weekday_persian:n} \fi \dmc_format_replace_one:nnnnn {#1} {#2} {EEEE} {weekday} {\dmc_weekday_name:n} \dmc_format_replace_one:nnnnn {#1} {#2} {EEE} {weekday} {\dmc_weekday_abbrev:n} % ================================================= % Major and cycle % ================================================= \dmc_format_replace_one:nnnnn {#1} {#2} {R} {major} {} \dmc_format_replace_one:nnnnn {#1} {#2} {U} {cycle} {} % ================================================= % Remaining one-character tokens % ================================================= \dmc_format_replace_one:nnnnn {#1} {#2} {y} {year} {} \dmc_format_replace_one:nnnnn {#1} {#2} {l} {leap} {} \dmc_format_replace_one:nnnnn {#1} {#2} {M} {month} {} \dmc_format_replace_one:nnnnn {#1} {#2} {d} {day} {} \dmc_format_replace_one:nnnnn {#1} {#2} {w} {week} {} \dmc_format_replace_one:nnnnn {#1} {#2} {u} {weekday} {} \dmc_format_replace_one:nnnnn {#1} {#2} {N} {name} {} \dmc_format_replace_one:nnnnn {#1} {#2} {S} {season} {} \dmc_format_replace_one:nnnnn {#1} {#2} {G} {era} {} \dmc_format_replace_one:nnnnn {#1} {#2} {E} {event} {} \dmc_format_replace_one:nnnnn {#1} {#2} {C} {count} {} \dmc_format_replace_one:nnnnn {#1} {#2} {p} {prefix} {} \dmc_format_replace_one:nnnnn {#1} {#2} {s} {stem} {} \dmc_format_replace_one:nnnnn {#1} {#2} {n} {number} {} % ================================================= % Output % ================================================= \tl_use:N \l_dmc_format_tl \group_end: } % ================================================= % Public formatting command % ================================================= \NewDocumentCommand \dmcformat { O{gr} m m } { \dmc_format:nnn {#1} {#2} {#3} } % ================================================= % Internal style setter % ================================================= \cs_new_protected:Npn \dmc_style_set:nnn #1 #2 #3 { \clist_map_inline:nn {#1} { \dmc_style_store:nnn {##1} {#2} {#3} } } \NewDocumentCommand \dmcstyle { O{gr} m m } { \dmc_style_set:nnn {#1} {#2} {#3} } % ================================================= % Resolve for style % ================================================= \cs_new_protected:Npn \dmc_style_resolve:nnN #1 #2 #3 { \dmc_style_fetch:nnN {#1} {#2} #3 \tl_if_blank:VTF #3 { \dmc_style_fetch:nnN {gr} {#2} #3 } { } } % ================================================= % Public styled-date command % ================================================= \NewDocumentCommand \dmc { O{gr} m m } { \dmc_style_resolve:nnN {#1} {#3} \l_dmc_style_tl \tl_if_blank:VTF \l_dmc_style_tl { \PackageError{datemultical} {Unknown date style '#3' for calendar '#1'} {The requested date style has not been defined for this calendar, and no Gregorian fallback style exists.} } { \exp_args:NnnV \dmc_format:nnn {#1} {#2} \l_dmc_style_tl } } % ================================================= % Standard date styles % ================================================= \dmcstyle{full}{EEEE,~MMMM~d,~y} \dmcstyle{long}{MMMM~d,~y} \dmcstyle{medium}{MMM~d,~y} \dmcstyle{short}{yy/MM/dd} \dmcstyle{short-use}{M/d/yy} \dmcstyle{ISO}{yyMMdd} \dmcstyle{ISOext}{yy-MM-dd} \dmcstyle{american}{MMMM~dd,~yy} \dmcstyle{shamerican}{MM/dd/yy} \dmcstyle{british}{dd~MMMM~yy} \dmcstyle{shbritish}{dd/MM/yy} \dmcstyle{shbritishdots}{dd.MM.yy} % ================================================= % Standard date styles for nonstandard calendars % ================================================= \dmcstyle[akan]{short}{p/s} \dmcstyle[aztec-tonalpohualli,mayan-tzolkin]{short}{n/N} \dmcstyle[aztec-xihuitl,mayan-haab]{short}{MM/dd} \dmcstyle[babylonian,old-hindu-lunar]{short}{yy/MM/li/dd} \dmcstyle[bahai,bahai-astronomical]{short}{R/U/yy/MM/dd} \dmcstyle[balinese]{short}{lui/di/tr/cw/pw/sw/sp/aw/sg/da} \dmcstyle[chinese,japanese,vietnamese]{short}{U/yy/MM/li/dd} \dmcstyle[hindu-lunar,hindu-lunar-astronomical,tibetan]{short}{yy/MM/lmi/dd/ldi} \dmcstyle[icelandic]{short}{yy/S/ww/u} \dmcstyle[iso]{short}{yy/ww/dd} \dmcstyle[japanese-era]{short}{Gi/yy/MM/dd} \dmcstyle[korean]{short}{yy/MM/li/dd} \dmcstyle[mayan-long-count]{short}{bt/ka/tn/ui/ki} \dmcstyle[olympiad]{short}{U/yy/MM/dd} \dmcstyle[roman]{short}{yy/MM/E/C/li} % ================================================= % Persian convenience commands % ================================================= \NewDocumentCommand \ShortShamsi { m } {\rl{\dmcformat[sh]{#1}{yy/MM/dd}}} \NewDocumentCommand \ShortGhamari { m } {\rl{\dmcformat[lh]{#1}{yy/MM/dd}}} \NewDocumentCommand \ShortMiladi { m } {\lr{\dmcformat[gr]{#1}{yy/MM/dd}}} \NewDocumentCommand \Shamsi { m } {\rl{\dmcformat[sh]{#1}{d~MMMMP~y}}} \NewDocumentCommand \Ghamari { m } {\rl{\dmcformat[lh]{#1}{d~MMMMP~y}}} \NewDocumentCommand \Miladi { m } {\lr{\dmcformat[gr]{#1}{MMMM~d,~y}}} \NewDocumentCommand \FaMiladi { m } {\rl{\dmcformat[gr]{#1}{d~MMMMP~y}}} \NewDocumentCommand \Persianweekday { m } {\rl{\dmcformat{#1}{EEEEP}}} \makeatother \ExplSyntaxOff \endinput