Home / Cardano Foundation / cf-cardano-conversions-java
Jun 05, 4-5 AM (0)
Jun 05, 5-6 AM (0)
Jun 05, 6-7 AM (0)
Jun 05, 7-8 AM (0)
Jun 05, 8-9 AM (0)
Jun 05, 9-10 AM (0)
Jun 05, 10-11 AM (0)
Jun 05, 11-12 PM (0)
Jun 05, 12-1 PM (0)
Jun 05, 1-2 PM (0)
Jun 05, 2-3 PM (0)
Jun 05, 3-4 PM (0)
Jun 05, 4-5 PM (0)
Jun 05, 5-6 PM (0)
Jun 05, 6-7 PM (0)
Jun 05, 7-8 PM (0)
Jun 05, 8-9 PM (0)
Jun 05, 9-10 PM (0)
Jun 05, 10-11 PM (0)
Jun 05, 11-12 AM (0)
Jun 06, 12-1 AM (0)
Jun 06, 1-2 AM (0)
Jun 06, 2-3 AM (0)
Jun 06, 3-4 AM (0)
Jun 06, 4-5 AM (0)
Jun 06, 5-6 AM (0)
Jun 06, 6-7 AM (0)
Jun 06, 7-8 AM (0)
Jun 06, 8-9 AM (0)
Jun 06, 9-10 AM (0)
Jun 06, 10-11 AM (0)
Jun 06, 11-12 PM (0)
Jun 06, 12-1 PM (0)
Jun 06, 1-2 PM (0)
Jun 06, 2-3 PM (0)
Jun 06, 3-4 PM (0)
Jun 06, 4-5 PM (0)
Jun 06, 5-6 PM (0)
Jun 06, 6-7 PM (0)
Jun 06, 7-8 PM (0)
Jun 06, 8-9 PM (0)
Jun 06, 9-10 PM (0)
Jun 06, 10-11 PM (0)
Jun 06, 11-12 AM (0)
Jun 07, 12-1 AM (0)
Jun 07, 1-2 AM (0)
Jun 07, 2-3 AM (0)
Jun 07, 3-4 AM (0)
Jun 07, 4-5 AM (0)
Jun 07, 5-6 AM (0)
Jun 07, 6-7 AM (0)
Jun 07, 7-8 AM (0)
Jun 07, 8-9 AM (0)
Jun 07, 9-10 AM (0)
Jun 07, 10-11 AM (0)
Jun 07, 11-12 PM (0)
Jun 07, 12-1 PM (0)
Jun 07, 1-2 PM (0)
Jun 07, 2-3 PM (0)
Jun 07, 3-4 PM (0)
Jun 07, 4-5 PM (0)
Jun 07, 5-6 PM (0)
Jun 07, 6-7 PM (0)
Jun 07, 7-8 PM (0)
Jun 07, 8-9 PM (0)
Jun 07, 9-10 PM (0)
Jun 07, 10-11 PM (0)
Jun 07, 11-12 AM (0)
Jun 08, 12-1 AM (0)
Jun 08, 1-2 AM (0)
Jun 08, 2-3 AM (0)
Jun 08, 3-4 AM (0)
Jun 08, 4-5 AM (0)
Jun 08, 5-6 AM (0)
Jun 08, 6-7 AM (0)
Jun 08, 7-8 AM (0)
Jun 08, 8-9 AM (0)
Jun 08, 9-10 AM (0)
Jun 08, 10-11 AM (0)
Jun 08, 11-12 PM (0)
Jun 08, 12-1 PM (0)
Jun 08, 1-2 PM (0)
Jun 08, 2-3 PM (0)
Jun 08, 3-4 PM (0)
Jun 08, 4-5 PM (0)
Jun 08, 5-6 PM (0)
Jun 08, 6-7 PM (0)
Jun 08, 7-8 PM (0)
Jun 08, 8-9 PM (0)
Jun 08, 9-10 PM (0)
Jun 08, 10-11 PM (0)
Jun 08, 11-12 AM (0)
Jun 09, 12-1 AM (0)
Jun 09, 1-2 AM (0)
Jun 09, 2-3 AM (0)
Jun 09, 3-4 AM (0)
Jun 09, 4-5 AM (0)
Jun 09, 5-6 AM (0)
Jun 09, 6-7 AM (0)
Jun 09, 7-8 AM (0)
Jun 09, 8-9 AM (0)
Jun 09, 9-10 AM (0)
Jun 09, 10-11 AM (0)
Jun 09, 11-12 PM (0)
Jun 09, 12-1 PM (0)
Jun 09, 1-2 PM (0)
Jun 09, 2-3 PM (0)
Jun 09, 3-4 PM (0)
Jun 09, 4-5 PM (0)
Jun 09, 5-6 PM (0)
Jun 09, 6-7 PM (0)
Jun 09, 7-8 PM (0)
Jun 09, 8-9 PM (0)
Jun 09, 9-10 PM (0)
Jun 09, 10-11 PM (0)
Jun 09, 11-12 AM (0)
Jun 10, 12-1 AM (0)
Jun 10, 1-2 AM (0)
Jun 10, 2-3 AM (0)
Jun 10, 3-4 AM (0)
Jun 10, 4-5 AM (0)
Jun 10, 5-6 AM (0)
Jun 10, 6-7 AM (0)
Jun 10, 7-8 AM (0)
Jun 10, 8-9 AM (0)
Jun 10, 9-10 AM (0)
Jun 10, 10-11 AM (0)
Jun 10, 11-12 PM (0)
Jun 10, 12-1 PM (0)
Jun 10, 1-2 PM (0)
Jun 10, 2-3 PM (0)
Jun 10, 3-4 PM (0)
Jun 10, 4-5 PM (0)
Jun 10, 5-6 PM (0)
Jun 10, 6-7 PM (0)
Jun 10, 7-8 PM (0)
Jun 10, 8-9 PM (0)
Jun 10, 9-10 PM (0)
Jun 10, 10-11 PM (0)
Jun 10, 11-12 AM (0)
Jun 11, 12-1 AM (0)
Jun 11, 1-2 AM (0)
Jun 11, 2-3 AM (0)
Jun 11, 3-4 AM (0)
Jun 11, 4-5 AM (0)
Jun 11, 5-6 AM (0)
Jun 11, 6-7 AM (0)
Jun 11, 7-8 AM (0)
Jun 11, 8-9 AM (0)
Jun 11, 9-10 AM (0)
Jun 11, 10-11 AM (0)
Jun 11, 11-12 PM (0)
Jun 11, 12-1 PM (0)
Jun 11, 1-2 PM (3)
Jun 11, 2-3 PM (0)
Jun 11, 3-4 PM (0)
Jun 11, 4-5 PM (0)
Jun 11, 5-6 PM (0)
Jun 11, 6-7 PM (0)
Jun 11, 7-8 PM (0)
Jun 11, 8-9 PM (0)
Jun 11, 9-10 PM (0)
Jun 11, 10-11 PM (0)
Jun 11, 11-12 AM (0)
Jun 12, 12-1 AM (0)
Jun 12, 1-2 AM (0)
Jun 12, 2-3 AM (0)
Jun 12, 3-4 AM (0)
Jun 12, 4-5 AM (0)
3 commits this week Jun 05, 2026 - Jun 12, 2026
feat!: return primitive types from slotToEpoch and toSlot
Epoch numbers are int everywhere else in the API (utcTimeToEpochNo,
epochToAbsoluteSlot, era history) while slotToEpoch returned a boxed
Long, and toSlot returned a boxed Long where slots are long elsewhere.

slotToEpoch now returns int and toSlot returns long.

BREAKING CHANGE: SlotConversions.slotToEpoch returns int (was Long)
and TimeConversions.toSlot returns long (was Long). Call sites using
the values arithmetically are source compatible; call sites storing
the boxed Long need a recompile/adjustment.

Co-Authored-By: Claude Fable 5 <[email protected]>
fix: verify era history real slots against chain data, correct preview era model
Real first/last block slots per era are not in any genesis file - they
are on-chain data (the first/last block actually minted in an era).
All values across the three tables were verified against chain data
via Koios; placeholders filled and one wrong value corrected:

- mainnet: filled Byron(0-175) last real slot 3801599, Alonzo(290-297)
  last real slot 43372792, Babbage(365-393) last real slot 84844799;
  all pre-existing values confirmed correct
- preprod: filled first real slots for Shelley (86400), Allegra
  (518400), Mary (950410), Alonzo (1382422) and Babbage (3974409),
  filled Babbage last real slot (68774372), and corrected Alonzo's
  last real slot from 3542390 (not the last Alonzo block) to 3931295
- preview: the single "Shelley 0-645" row was wrong - preview never
  ran Byron/Shelley; it launched directly in Alonzo (ledger protocol
  v6, epochs 0-2), hard-forked to Babbage at epoch 3 and to Conway at
  epoch 646 (verified via on-chain epoch_params). The table now models
  Alonzo/Babbage/Conway with real block slots.

GenesisConfig.firstShelleyEpochNo() now resolves the first non-Byron
era history row, since networks without a literal Shelley era (preview)
start the 1s-slot phase in a later era.

The EraHistoryConsistencyTest no longer tolerates -1 placeholders.

Co-Authored-By: Claude Fable 5 <[email protected]>
fix: epoch off-by-one at every epoch boundary in utcTimeToEpochNo
utcTimeToEpochNo computed the Shelley-era epoch with Math.ceil over
double division, which returns the previous epoch for the entire first
second of every epoch, on every network. It is now routed through the
already-correct toSlot + slotToEpoch pair (exact long arithmetic, no
doubles, no ceil), making time->epoch, time->slot and slot->epoch
mutually consistent by construction.

Also fixes uncovered by new oracle-based audit tests:

- era history data: mainnet Mary lastTheoreticalSlotNo overlapped
  Alonzo's first slot; mainnet Babbage rows had a missing last slot and
  one pointing at the end of epoch 448 instead of 506; preprod Babbage
  used Conway's first block slot instead of the epoch boundary
- EraConversions answered last*Slot/last*EraTime questions from the
  first era history row, returning empty/wrong values for eras spanning
  multiple rows (Byron, Alonzo, Babbage); added EraHistory.findLastByEra
- epoch lengths are now derived from the genesis files (Shelley
  epochLength, Byron 10 * k) instead of being hardcoded in NetworkType,
  and GenesisConfig cross-validates the two genesis files at
  construction time

Simplifications: EpochConversions now computes first/last slots with a
direct two-segment formula; TimeConversions has a single code path.
Public API unchanged. utcTimeToEpochNo now rejects pre-genesis times
and epochToAbsoluteSlot rejects negative epochs.

New regression suites: MainNetBoundaryAuditTest, TestnetBoundaryAuditTest
(second-by-second ground-truth scans around epoch boundaries, including
recent epochs) and EraHistoryConsistencyTest (era table contiguity and
agreement with epoch arithmetic).

Fixes #30

Co-Authored-By: Claude Fable 5 <[email protected]>