JustBash.Commands.Date (JustBash v0.4.0)
View SourceThe date command — display the current date and time.
Output is always UTC. Supported directives:
- compound —
%F(%Y-%m-%d),%T(%H:%M:%S),%R(%H:%M),%D(%m/%d/%y),%c,%x,%X,%r - date —
%Y,%y,%C,%m,%d,%e(space-padded),%j,%q,%a,%A,%b,%h,%B,%u,%w,%G,%g,%U,%V,%W - time —
%H,%M,%S,%N,%I,%k,%l,%p,%P,%Z,%s - zone offset —
%z(+0000),%:z,%::z,%:::z - literal —
%%,%n,%t
A directive is %, then field flags, then an optional width, then an optional
locale modifier, then the conversion — %_5Od is all four at once. The flags
are - (no padding), _ (space padding), 0 (zero padding), ^ (upper case)
and # (swap the conversion's default case). The modifiers are E and O,
which select nothing in the C locale but are accepted only for the conversions
GNU accepts them for; the rest pass through verbatim.
None of that composes the way it reads. A flag reaches a numeric field and not
a compound one, so %-T is "09:05:03" and only %-D loses its year padding;
the last padding flag wins outright, so %-0d is "05"; a width replaces a
conversion's own width rather than raising it, so %1d is "5"; and a modifier
drops the padding flag entirely, so %-Od is "05". Every one of those rules is
recorded in test/fixtures/bash_cases/date_matrix.json against real GNU date
rather than reasoned about here — this paragraph describes the recording, it
does not define it.
An unrecognized directive is emitted verbatim (%J → %J), as GNU date does,
so a caller can tell the difference between "not supported" and a real value.
That passthrough is only safe because the supported set is complete enough that
reaching it means the directive really does not exist: a directive that is
real but unimplemented would print itself at exit 0, and a caller cannot tell
that from a legitimate literal. The matrix enumerates the whole conversion
alphabet — crossed with every flag, width and modifier — to keep it so.
Flags: -d / --date, -r SECONDS|FILE / --reference FILE, -I[FMT] /
--iso-8601[=FMT], -R / --rfc-email, -u / --utc / --universal, the
BSD -v adjustments, and the BSD -j / -f pair. A value may be attached or
separate (-d2024-06-15, --date=2024-06-15), no-argument flags may cluster
(-ju), and -- ends option parsing — the getopt conventions real date
inherits.
-r reads both spellings the flag has in the wild, as FreeBSD's date does: a
numeric value is epoch seconds, and anything else names a file whose
modification time to report. GNU's --reference is always a file. The VFS
records mtimes, so the file's time comes from the sandbox rather than the host
clock, and a failure to read it reports the real error kind — descending
through a regular file is ENOTDIR, not "no such file".
-d and -r each name the instant to print, so giving both is an error rather
than a silent choice between two answers.
Everything else is an error. An unimplemented flag must not be dropped: ignoring it would print the current date at exit 0, which a caller cannot tell apart from a real answer.
Errors follow whichever real implementation spells the flag: GNU's wording for
a long option (unrecognized option '--foo'), BSD's for a short one
(illegal option -- X), since BSD names a long option by its second - and
so identifies nothing.
One BSD feature is deliberately partial, and says so rather than guessing:
-v implements only the relative form ([+-]val[ymwdHMS]), not the
set-a-field form (-v1d, -vfri).