Liking cljdoc? Tell your friends :D

datahike.pg.datetime.zone

DetermineTimeZoneOffset (datetime.c:1575-1733): a local date and time plus a zone to an OFFSET.

This is a separate step from parsing because an offset is a function of the INSTANT, and the instant is only known once the date has been decoded and validated.

THE AMBIGUITY RULE IS THE OPPOSITE OF java.time's, in both directions, and this is the whole reason the namespace exists rather than a call to ZonedDateTime/of:

spring forward (a GAP, the local time never happened) PostgreSQL takes the BEFORE offset and keeps the local fields java.time shifts the time forward and takes the AFTER offset

fall back (an OVERLAP, the local time happened twice) PostgreSQL takes the AFTER offset java.time takes the earlier, BEFORE offset

datetime.c:1697-1706 states the rule and why it is not phrased as "prefer standard time": that older rule could not resolve zones where both readings report as standard time -- Europe/Moscow in October 2014 -- and in zones like Europe/Dublin there is widespread disagreement about which offset is "standard" at all.

An hour wrong, twice a year, with no error, is exactly the failure this port is meant to remove, so it is implemented from the C's branches rather than from the convenience method.

SIGN: everything here returns and accepts SECONDS WEST, as PostgreSQL stores internally.

`DetermineTimeZoneOffset` (datetime.c:1575-1733): a local date and
time plus a zone to an OFFSET.

This is a separate step from parsing because an offset is a function
of the INSTANT, and the instant is only known once the date has been
decoded and validated.

THE AMBIGUITY RULE IS THE OPPOSITE OF `java.time`'s, in both
directions, and this is the whole reason the namespace exists rather
than a call to `ZonedDateTime/of`:

  spring forward (a GAP, the local time never happened)
    PostgreSQL  takes the BEFORE offset and keeps the local fields
    java.time   shifts the time forward and takes the AFTER offset

  fall back (an OVERLAP, the local time happened twice)
    PostgreSQL  takes the AFTER offset
    java.time   takes the earlier, BEFORE offset

datetime.c:1697-1706 states the rule and why it is not phrased as
"prefer standard time": that older rule could not resolve zones
where both readings report as standard time -- Europe/Moscow in
October 2014 -- and in zones like Europe/Dublin there is widespread
disagreement about which offset is "standard" at all.

An hour wrong, twice a year, with no error, is exactly the failure
this port is meant to remove, so it is implemented from the C's
branches rather than from the convenience method.

SIGN: everything here returns and accepts SECONDS WEST, as
PostgreSQL stores internally.
raw docstring

determine-abbrev-offsetclj

(determine-abbrev-offset tm zone-name)

DetermineTimeZoneAbbrevOffset (datetime.c:1748-1779) for a DYNTZ abbreviation -- one that names a zone instead of carrying an offset.

PARTIAL, and deliberately so. The C first asks the zone's own transition data whether the abbreviation as WRITTEN matches at that instant, and uses that offset if it does; only on a miss does it fall back to the zone's offset. Java exposes no abbreviation strings from tzdb, so only the fallback is implementable here without shipping the tzdb text ourselves.

What that costs: writing an abbreviation that disagrees with the zone's state at the instant -- '2000-01-01 12:00 ARST', summer time in Buenos Aires named on a winter date -- gets the zone's offset for that date rather than the abbreviation's own. The abbreviation still selects the right ZONE, so it is wrong only when the two disagree, and only for the 50 DYNTZ entries of 195. Recorded in doc/review-backlog.md rather than papered over.

`DetermineTimeZoneAbbrevOffset` (datetime.c:1748-1779) for a DYNTZ
abbreviation -- one that names a zone instead of carrying an offset.

PARTIAL, and deliberately so. The C first asks the zone's own
transition data whether the abbreviation as WRITTEN matches at that
instant, and uses that offset if it does; only on a miss does it
fall back to the zone's offset. Java exposes no abbreviation strings
from tzdb, so only the fallback is implementable here without
shipping the tzdb text ourselves.

What that costs: writing an abbreviation that disagrees with the
zone's state at the instant -- `'2000-01-01 12:00 ARST'`, summer
time in Buenos Aires named on a winter date -- gets the zone's
offset for that date rather than the abbreviation's own. The
abbreviation still selects the right ZONE, so it is wrong only when
the two disagree, and only for the 50 DYNTZ entries of 195. Recorded
in doc/review-backlog.md rather than papered over.
sourceraw docstring

determine-offsetclj

(determine-offset {:keys [year mon mday hour min sec]} z)

DetermineTimeZoneOffsetInternal. The local fields and a zone to SECONDS WEST.

Three cases, and the last two are where this differs from ZonedDateTime/of:

one valid offset use it none (a gap) the BEFORE offset, local fields unchanged two (an overlap) the AFTER offset

An out-of-range date is not an error: the C falls through to overflow and assumes UTC (datetime.c:1726-1730).

`DetermineTimeZoneOffsetInternal`. The local fields and a zone to
SECONDS WEST.

Three cases, and the last two are where this differs from
`ZonedDateTime/of`:

  one valid offset   use it
  none (a gap)       the BEFORE offset, local fields unchanged
  two (an overlap)   the AFTER offset

An out-of-range date is not an error: the C falls through to
`overflow` and assumes UTC (datetime.c:1726-1730).
sourceraw docstring

fixed-offsetclj

(fixed-offset z)

pg_get_timezone_offset: the zone's offset if it has exactly one for all time, else nil. DecodeTimeOnly needs this -- a time with no date can take a zone only when the answer does not depend on the date, so '12:00 UTC'::timetz works and '12:00 America/New_York'::timetz does not.

`pg_get_timezone_offset`: the zone's offset if it has exactly one for
all time, else nil. `DecodeTimeOnly` needs this -- a time with no
date can take a zone only when the answer does not depend on the
date, so `'12:00 UTC'::timetz` works and
`'12:00 America/New_York'::timetz` does not.
sourceraw docstring

posix-offsetclj

(posix-offset name)

GMT+8 and friends, as SECONDS WEST -- or nil if name is not one.

THE SIGN IS INVERTED relative to everything else, and this is not a quirk of ours: in a POSIX TZ string the offset is "the value added to local time to arrive at UTC", so GMT+8 is eight hours BEHIND UTC. The oracle agrees -- '2000-01-01 12:00:00 GMT+8'::timestamptz is 20:00:00+00.

Java reads it the other way. ZoneId/of("GMT+8") is +08:00, so routing these through ZoneId gives an answer sixteen hours out with no error. That is why this is checked BEFORE the tzdb lookup rather than after.

It does not shadow real zone names: PST8PDT and EST5EDT have a second alpha run and do not match, and Etc/GMT+5 has a /. Those go to tzdb, which applies the same inversion itself.

`GMT+8` and friends, as SECONDS WEST -- or nil if `name` is not one.

THE SIGN IS INVERTED relative to everything else, and this is not a
quirk of ours: in a POSIX TZ string the offset is "the value added
to local time to arrive at UTC", so `GMT+8` is eight hours BEHIND
UTC. The oracle agrees -- `'2000-01-01 12:00:00 GMT+8'::timestamptz`
is `20:00:00+00`.

Java reads it the other way. `ZoneId/of("GMT+8")` is +08:00, so
routing these through `ZoneId` gives an answer sixteen hours out
with no error. That is why this is checked BEFORE the tzdb lookup
rather than after.

It does not shadow real zone names: `PST8PDT` and `EST5EDT` have a
second alpha run and do not match, and `Etc/GMT+5` has a `/`. Those
go to tzdb, which applies the same inversion itself.
sourceraw docstring

resolve-zone-nameclj

(resolve-zone-name name)

Cached zone-id. Zone lookup walks every available id on a miss and a literal can carry any string, so the misses are cached too.

Cached `zone-id`. Zone lookup walks every available id on a miss and
a literal can carry any string, so the misses are cached too.
sourceraw docstring

utcclj

The session zone until SET TimeZone is honoured (expr.clj:1613 reports UTC unconditionally).

The session zone until `SET TimeZone` is honoured (expr.clj:1613
reports UTC unconditionally).
sourceraw docstring

zone-idclj

(zone-id name)

pg_tzset: a zone NAME to a zone, or nil if there is no such zone.

Case-insensitive, because pg_tzset is and because the lexer has already lowercased the field. Java's own ids are mixed case, so the lookup is against a folded index.

ZoneId/of with SHORT_IDS is deliberately NOT used: it maps PST to America/Los_Angeles, which observes DST, while PostgreSQL's PST is a fixed -08:00 from the abbreviation table. Abbreviations never reach this function -- they are resolved earlier, against tokens/zone-abbrevs -- and routing them here would be the bug.

`pg_tzset`: a zone NAME to a zone, or nil if there is no such zone.

Case-insensitive, because `pg_tzset` is and because the lexer has
already lowercased the field. Java's own ids are mixed case, so the
lookup is against a folded index.

`ZoneId/of` with `SHORT_IDS` is deliberately NOT used: it maps `PST`
to America/Los_Angeles, which observes DST, while PostgreSQL's `PST`
is a fixed -08:00 from the abbreviation table. Abbreviations never
reach this function -- they are resolved earlier, against
`tokens/zone-abbrevs` -- and routing them here would be the bug.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close