Class TxnId
This class encodes a transaction timestamp (UTC, second precision), a node
identifier, and a per-node transaction counter suffix into a single
long. It supports:
- A canonical numeric form (
id()). - A stable human-readable form (
toString()) suitable for logs and debugging. - A compact base-36 form (
toRrn()) suitable for ISO-8583 field 37 (RRN). - A filesystem-friendly relative path (
toFile()) that partitions by date/time.
RRN length constraint and long-term viability.
ISO-8583 DE-037 limits the Retrieval Reference Number to 12 characters. When
rendered in base 36, this implementation therefore enforces the numeric ceiling
"zzzzzzzzzzzz" (base 36), exposed as MAX_VALUE, so that
toRrn() always fits within 12 characters.
This ceiling is purely a numeric bound required for DE-037 compliance;
it is not derived from the YYY-DDD-SSSSS-NNN-TTTTT field layout.
Nevertheless, when TxnIds are created through create(ZonedDateTime, int, long),
the encoded timestamp remains comfortably below this bound for several centuries.
In practice, the maximum semantically valid timestamp that can be encoded while still satisfying the DE-037 12-character constraint is 2473-12-31 23:59:59 UTC. This places the effective limit more than four centuries in the future, making the scheme safe for long-term production use.
Uniqueness model. The identifier is composed of:
YYY: years since 2000 (000..999).DDD: day of year (001..366).SSSSS: second of day (00000..86399).NNN: node id (000..999).TTTTT: last 5 digits of a per-node transaction counter (00000..99999).
Collisions are prevented as long as, for a given (UTC second, node),
the TTTTT suffix is not reused.
Time semantics. All time components are encoded in UTC to avoid daylight-saving and timezone ambiguity. The timestamp component has second precision.
Query-range semantics. Because the numeric encoding is ordered by UTC time,
callers can build inclusive numeric bounds for index range scans. For “between local
dates” queries, this class provides DST-safe helpers that define a local day as the
half-open interval [startOfDay(d), startOfDay(d+1)) in the requested zone and
then converts that to an inclusive UTC-second range.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final recordInclusive numeric id range suitable for DB index range scans. -
Method Summary
Modifier and TypeMethodDescriptionstatic TxnIdCreates a newTxnIdfrom anInstant(assumed UTC), node, and transaction suffix.static TxnIdcreate(ZonedDateTime zonedDateTime, int node, long transactionId) Creates a newTxnIdfrom a timestamp, node, and transaction suffix.booleanstatic TxnIdParses aTxnIdfrom an ISO-8583 DE-037 Retrieval Reference Number (RRN) in base 36.inthashCode()longid()Returns the canonical numeric representation of this transaction id.static TxnId.TxnIdRangeComputes an inclusive numeric id range for the given UTC instant range.static TxnId.TxnIdRangeComputes an inclusive numeric id range for transactions between the given local dates, inclusive on both ends, in the provided time zone.static TxnId.TxnIdRangeidRange(LocalDateTime fromLocalDateTime, LocalDateTime toLocalDateTime, ZoneId zone) Inclusive range for local date-times inzone.static TxnId.TxnIdRangeidRange(ZonedDateTime from, ZonedDateTime to) Inclusive range for zoned date-times.static longlowerBoundId(Instant instantUtc) Computes the lowest possible TxnId numeric value for the given UTC second, suitable for an inclusive range lower bound.static longlowerBoundId(LocalDate localDate, ZoneId zone) Inclusive lower bound id for the start of the given local day inzone.static TxnIdparse(long id) Parses aTxnIdfrom its canonical numeric value.static TxnIdParses aTxnIdfrom its human-readable formYYY-DDD-SSSSS-NNN-TTTTT.toFile()Returns a relative file path suitable to store contents of this transaction.toRrn()Returns a compact base-36 rendering ofid()suitable for ISO-8583 DE-037 (RRN).toString()Returns the human-readable form:YYY-DDD-SSSSS-NNN-TTTTT.static longupperBoundId(Instant instantUtc) Computes the highest possible TxnId numeric value for the given UTC second, suitable for an inclusive range upper bound.static longupperBoundId(LocalDate localDate, ZoneId zone) Inclusive upper bound id for the end of the given local day inzone.
-
Method Details
-
id
Returns the canonical numeric representation of this transaction id.Note: not all numeric values are necessarily a valid structured TxnId; use
parse(String)when validation of the human-readable components is required.- Returns:
- the packed long value.
-
toFile
Returns a relative file path suitable to store contents of this transaction.Path format:
yyyy/mm/dd/hh-mm-ss-NNN-TTTTTwhere:yyyy/mm/ddis the UTC date derived from the encoded timestamp.hh-mm-ssis the UTC time (second precision).NNNis the node id (000..999).TTTTTis the transaction suffix (00000..99999).
- Returns:
- a
Filewith the above relative path.
-
toString
Returns the human-readable form:YYY-DDD-SSSSS-NNN-TTTTT.Where:
YYY: years since 2000 (000..999).DDD: day of year (001..366).SSSSS: second of day (00000..86399).NNN: node id (000..999).TTTTT: transaction suffix (00000..99999).
-
toRrn
-
equals
-
hashCode
-
create
Creates a newTxnIdfrom a timestamp, node, and transaction suffix.The timestamp is converted to UTC using
ZonedDateTime.withZoneSameInstant(ZoneId)and then encoded at second precision.- Parameters:
zonedDateTime- transaction timestamp.node- node id (0..999). Values outside this range are wrapped using modulo 1000.transactionId- per-node transaction suffix (0..99999). Values outside this range are wrapped using modulo 100000.- Returns:
- newly created TxnId.
-
create
Creates a newTxnIdfrom anInstant(assumed UTC), node, and transaction suffix.- Parameters:
instant- transaction timestamp in UTC.node- node id (0..999).transactionId- per-node transaction suffix (0..99999).- Returns:
- newly created TxnId.
-
parse
Parses aTxnIdfrom its human-readable formYYY-DDD-SSSSS-NNN-TTTTT.- Parameters:
idString- TxnId inYYY-DDD-SSSSS-NNN-TTTTTformat (as produced bytoString()).- Returns:
- newly created TxnId.
- Throws:
IllegalArgumentException- ifidStringis invalid or out of range.
-
parse
Parses aTxnIdfrom its canonical numeric value.This validates only the numeric bound required for DE-037 usage (see
MAX_VALUE). It does not validate that each encoded component is within expected ranges.- Parameters:
id- numeric value.- Returns:
- newly created TxnId.
- Throws:
IllegalArgumentException- if the value is negative or exceedsMAX_VALUE.
-
fromRrn
Parses aTxnIdfrom an ISO-8583 DE-037 Retrieval Reference Number (RRN) in base 36.- Parameters:
rrn- base-36 value (must decode to a non-negative number not exceedingMAX_VALUE).- Returns:
- newly created TxnId.
- Throws:
IllegalArgumentException- ifrrnis invalid or out of range.
-
lowerBoundId
Computes the lowest possible TxnId numeric value for the given UTC second, suitable for an inclusive range lower bound.This uses
node=000andsuffix=00000.- Parameters:
instantUtc- a timestamp whoseInstant.getEpochSecond()is used.- Returns:
- inclusive lower bound id.
-
upperBoundId
Computes the highest possible TxnId numeric value for the given UTC second, suitable for an inclusive range upper bound.This uses
node=999andsuffix=99999.- Parameters:
instantUtc- a timestamp whoseInstant.getEpochSecond()is used.- Returns:
- inclusive upper bound id.
-
idRange
Computes an inclusive numeric id range for the given UTC instant range.Both ends are treated as inclusive at second precision. Any sub-second component is ignored.
- Parameters:
fromUtc- inclusive lower endpoint (UTC).toUtc- inclusive upper endpoint (UTC).- Returns:
- inclusive numeric id range; may be empty.
-
idRange
Computes an inclusive numeric id range for transactions between the given local dates, inclusive on both ends, in the provided time zone.DST-safe strategy: define each local day as the half-open interval
[startOfDay(d), startOfDay(d+1))inzone. This avoids constructing local “end of day” timestamps (which can be ambiguous on overlap days). The resulting UTC range is then made inclusive at second precision by subtracting one second from the exclusive end.- Parameters:
fromLocalDate- inclusive start date inzone.toLocalDate- inclusive end date inzone.zone- time zone for interpreting local dates.- Returns:
- inclusive numeric id range; may be empty.
-
lowerBoundId
Inclusive lower bound id for the start of the given local day inzone.- Parameters:
localDate- local date.zone- zone in which the local day is defined.- Returns:
- inclusive lower bound id.
-
upperBoundId
Inclusive upper bound id for the end of the given local day inzone.DST-safe: computed as one second before
startOfDay(localDate+1)inzone.- Parameters:
localDate- local date.zone- zone in which the local day is defined.- Returns:
- inclusive upper bound id.
-
idRange
public static TxnId.TxnIdRange idRange(LocalDateTime fromLocalDateTime, LocalDateTime toLocalDateTime, ZoneId zone) Inclusive range for local date-times inzone.Note: this method interprets
fromLocalDateTimeandtoLocalDateTimeas local wall-clock times inzone. For DST gaps/overlaps,ZonedDateTime.of(LocalDateTime, ZoneId)applies the zone rules. If you need explicit overlap resolution (earlier vs later offset), passZonedDateTimevalues instead and useidRange(Instant, Instant)oridRange(ZonedDateTime, ZonedDateTime).- Parameters:
fromLocalDateTime- inclusive start time inzone.toLocalDateTime- inclusive end time inzone.zone- zone for interpreting local date-times.- Returns:
- inclusive numeric id range; may be empty.
-
idRange
Inclusive range for zoned date-times.- Parameters:
from- inclusive start time.to- inclusive end time.- Returns:
- inclusive numeric id range; may be empty.
-