* fix: add unix_epoch_second() with floor semantics for negative timestamps
jiff::Timestamp::as_second() uses truncation toward zero, so a timestamp
of -1.5s returns -1. GNU date's %s format uses floor (toward negative
infinity), returning -2 for the same value.
Add ParsedDateTime::unix_epoch_second() which corrects for this by
detecting a negative subsec_nanosecond and subtracting 1 from the
truncated second. Also add subsec_nanosecond() that re-normalizes to
the non-negative [0, 1_000_000_000) range matching the GNU timespec
convention.
The uutils date command can use these methods to produce correct %s
output for negative fractional epoch inputs like @-1.5.
Fixes#283
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: cover extended epoch helper paths
* test: cover direct extended epoch accessors
* test: remove panic branch to land full patch coverage
The let-else with panic! left one line reachable only on test failure,
which showed up as uncovered on codecov/patch. Use matches! + assert!
to reach the same invariant with 100% patch coverage.
* fix: support HH:MM am/pm time formats in combined date-time parsing
The combined date-time parser (e.g., "2024-06-15 12:00 PM") used
time::iso which only accepts 24-hour notation. When an am/pm suffix
followed, iso would greedily consume the time portion, leaving the
meridiem orphaned and causing a parse error.
Switch to time::parse which tries am_pm_time first (with fallback to
iso), so inputs like "2024-06-15 12:00 PM", "2024-06-15 11:30am", and
"2024-06-15 3:00 PM" are now accepted. Case insensitivity is already
handled by parse_items lowercasing the input before parsing.
Fixes#282
* perf: keep ISO fast path for combined datetime parsing
* fix(offset): accept "ut" / "UT" as a bare UTC timezone abbreviation
GNU date -d accepts "ut" and "UT" (Universal Time) as synonyms for UTC.
parse_datetime rejected them because the timezone_name_to_offset table
contained "utc" and "gmt" but was missing "ut".
Add "ut" => "+0" to the lookup table. "gmt" was already present and
continues to work unchanged.
Add regression tests:
- offset-level: timezone_name_without_offset now includes "ut"
- lib-level: test_bare_utc_timezone_abbreviations covers all four
forms (ut, UT, gmt, GMT) end-to-end
Fixes#280
* style: run rustfmt on bare UT timezone test
A fixed offset (e.g. the "UTC" keyword) was applied after relative
items, so "1970/01/01 UTC N seconds" added N seconds to a local
wall-clock that could drift across a DST boundary before being
re-anchored at the offset, yielding an instant off by the DST gap.
Anchor the offset first, then apply relative items.
Fixesuutils/coreutils#12555.