Skip to content

fix: keep exact milliseconds in from_datetime and from_timestamp - #71

Open
taltal-beep wants to merge 1 commit into
mdomke:mainfrom
taltal-beep:fix/timestamp-float-truncation
Open

taltal-beep wants to merge 1 commit into
mdomke:mainfrom
taltal-beep:fix/timestamp-float-truncation

Conversation

@taltal-beep

@taltal-beep taltal-beep commented Oct 30, 2026 •

Copy link
Copy Markdown

Requested by Taltal

ULID.from_datetime() and ULID.from_timestamp() can return a ULID one millisecond early for a value that sits exactly on a millisecond:

>>> ULID.from_timestamp(1097375394.952).milliseconds
1097375394951

_normalize_timestamp does int(seconds * 1000). For some values the product is just below the integer as a float, and int() drops the whole fraction. In a random sample of 200,000 datetimes on exact milliseconds, about 0.6% came out one millisecond low. The same applies to a value read back from ULID.timestamp.

The fix rounds to three decimals before truncating. That removes the float error and still drops real sub-millisecond digits, so from_timestamp(1000.9999) stays at 1000999. After the fix the same sample has no mismatches.

The new test fails on main for both methods and passes with the fix. pytest, ruff check, ruff format --check and doc8 pass. pyrefly check reports one error (override import) that is also on main.

Converting seconds to milliseconds with int(value * 1000) truncates float
error along with the sub-millisecond part. 1078625331.860 * 1000 is just
below 1078625331860, so the ULID lands one millisecond early. This hit
about 0.6% of random timestamps on an exact millisecond.

Round to three decimals before truncating. That removes the float error
and still drops real sub-millisecond digits.
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant