Skip to content

ZmanimFormatter.formatInstant: format in the ZoneId passed in - #302

Merged
KosherJava merged 1 commit into
KosherJava:masterfrom
Elyahu41:fix/format-instant-zone
Nov 6, 2026
Merged

KosherJava merged 1 commit into
KosherJava:masterfrom
Elyahu41:fix/format-instant-zone

Conversation

@Elyahu41

@Elyahu41 Elyahu41 commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

The issue

ZmanimFormatter.formatInstant(Instant instant, ZoneId zoneId) ignores its zoneId argument and always formats in the formatter's own zone.

The edge case

Any call where zoneId is different from the zone the ZmanimFormatter was created with. One formatter is often reused to show times for several locations, or created with UTC.

What happens

The constructor stores dateTimeFormatter.withZone(zoneId), so the formatter has an override zone. formatInstant builds instant.atZone(zoneId) and formats it, but a DateTimeFormatter with an override zone converts a ZonedDateTime to the override zone before formatting. So the requested zone is silently replaced:

ZmanimFormatter formatter = new ZmanimFormatter(ZoneId.of("UTC"));
Instant instant = Instant.parse("2020-03-25T21:37:09Z");
formatter.formatInstant(instant, ZoneId.of("America/New_York"));   // "9:37:09"  (expected 5:37:09)
formatter.formatInstant(instant, ZoneId.of("Pacific/Kiritimati")); // "9:37:09"  (expected 11:37:09)

The time shown is off by the difference between the two zones, and nothing indicates an error. With a formatter whose zone differs from the location's, every zman displayed through formatInstant is wrong.

The fix

Format with getDateTimeFormatter().withZone(zoneId), so the requested zone becomes the override zone. A formatter set through setDateTimeFormatter without a zone also works, and a null zoneId still throws as before (from instant.atZone).

Tests

ZmanimFormatterFormatInstantTest:

  • formatsInTheRequestedZone: A UTC formatter formats in UTC, America/New_York and Pacific/Kiritimati. This fails without the fix.
  • worksWithAFormatterSetWithoutAZone: A formatter set with setDateTimeFormatter and no zone.

🤖 Generated with Claude Code

https://claude.ai/code/session_015Er4Sx7LnKzzCbgDEatxkU

The DateTimeFormatter created by the constructor has the formatter's zone as
its override zone, and an override zone converts the ZonedDateTime built from
the zoneId argument back to the formatter's zone, so the argument was
ignored (a UTC formatter returned the UTC time for every zoneId).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Er4Sx7LnKzzCbgDEatxkU
@KosherJava
KosherJava merged commit 87416f9 into KosherJava:master Nov 6, 2026
3 checks passed
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.

2 participants