Skip to content

Commit a3235a5

Browse files
committed
Doc: document POSIX-style time zone specifications in full.
We'd glossed over most of this complexity for years, but it's hard to avoid writing it all down now, so that we can explain what happens when there's no "posixrules" file in the IANA time zone database. That was at best a tiny minority situation till now, but it's likely to become quite common in the future, so we'd better explain it. Nonetheless, we don't really encourage people to use POSIX zone specs; picking a named zone is almost always what you really want, unless perhaps you're stuck with an out-of-date zone database. Therefore, let's shove all this detail into an appendix. Patch by me; thanks to Robert Haas for help with some awkward wording. Discussion: https://postgr.es/m/1390.1562258309@sss.pgh.pa.us
1 parent b48df81 commit a3235a5

File tree

2 files changed

+217
-33
lines changed

2 files changed

+217
-33
lines changed

doc/src/sgml/datatype.sgml

Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2478,7 +2478,7 @@ TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02'
24782478
A time zone abbreviation, for example <literal>PST</literal>. Such a
24792479
specification merely defines a particular offset from UTC, in
24802480
contrast to full time zone names which can imply a set of daylight
2481-
savings transition-date rules as well. The recognized abbreviations
2481+
savings transition rules as well. The recognized abbreviations
24822482
are listed in the <literal>pg_timezone_abbrevs</literal> view (see <xref
24832483
linkend="view-pg-timezone-abbrevs"/>). You cannot set the
24842484
configuration parameters <xref linkend="guc-timezone"/> or
@@ -2492,25 +2492,10 @@ TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02'
24922492
<para>
24932493
In addition to the timezone names and abbreviations,
24942494
<productname>PostgreSQL</productname> will accept POSIX-style time zone
2495-
specifications of the form <replaceable>STD</replaceable><replaceable>offset</replaceable> or
2496-
<replaceable>STD</replaceable><replaceable>offset</replaceable><replaceable>DST</replaceable>, where
2497-
<replaceable>STD</replaceable> is a zone abbreviation, <replaceable>offset</replaceable> is a
2498-
numeric offset in hours west from UTC, and <replaceable>DST</replaceable> is an
2499-
optional daylight-savings zone abbreviation, assumed to stand for one
2500-
hour ahead of the given offset. For example, if <literal>EST5EDT</literal>
2501-
were not already a recognized zone name, it would be accepted and would
2502-
be functionally equivalent to United States East Coast time. In this
2503-
syntax, a zone abbreviation can be a string of letters, or an
2504-
arbitrary string surrounded by angle brackets (<literal>&lt;&gt;</literal>).
2505-
When a daylight-savings zone abbreviation is present,
2506-
it is assumed to be used
2507-
according to the same daylight-savings transition rules used in the
2508-
IANA time zone database's <filename>posixrules</filename> entry.
2509-
In a standard <productname>PostgreSQL</productname> installation,
2510-
<filename>posixrules</filename> is the same as <literal>US/Eastern</literal>, so
2511-
that POSIX-style time zone specifications follow USA daylight-savings
2512-
rules. If needed, you can adjust this behavior by replacing the
2513-
<filename>posixrules</filename> file.
2495+
specifications, as described in
2496+
<xref linkend="datetime-posix-timezone-specs"/>. This option is not
2497+
normally preferable to using a named time zone, but it may be
2498+
necessary if no suitable IANA time zone entry is available.
25142499
</para>
25152500
</listitem>
25162501
</itemizedlist>
@@ -2537,19 +2522,6 @@ TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02'
25372522
above, this is not necessarily the same as local civil time on that date.
25382523
</para>
25392524

2540-
<para>
2541-
One should be wary that the POSIX-style time zone feature can
2542-
lead to silently accepting bogus input, since there is no check on the
2543-
reasonableness of the zone abbreviations. For example, <literal>SET
2544-
TIMEZONE TO FOOBAR0</literal> will work, leaving the system effectively using
2545-
a rather peculiar abbreviation for UTC.
2546-
Another issue to keep in mind is that in POSIX time zone names,
2547-
positive offsets are used for locations <emphasis>west</emphasis> of Greenwich.
2548-
Everywhere else, <productname>PostgreSQL</productname> follows the
2549-
ISO-8601 convention that positive timezone offsets are <emphasis>east</emphasis>
2550-
of Greenwich.
2551-
</para>
2552-
25532525
<para>
25542526
In all cases, timezone names and abbreviations are recognized
25552527
case-insensitively. (This is a change from <productname>PostgreSQL</productname>

doc/src/sgml/datetime.sgml

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,218 @@
555555

556556
</sect1>
557557

558+
<sect1 id="datetime-posix-timezone-specs">
559+
<title><acronym>POSIX</acronym> Time Zone Specifications</title>
560+
561+
<indexterm zone="datetime-posix-timezone-specs">
562+
<primary>time zone</primary>
563+
<secondary><acronym>POSIX</acronym>-style specification</secondary>
564+
</indexterm>
565+
566+
<para>
567+
<acronym>PostgreSQL</acronym> can accept time zone specifications that
568+
are written according to the <acronym>POSIX</acronym> standard's rules
569+
for the <varname>TZ</varname> environment
570+
variable. <acronym>POSIX</acronym> time zone specifications are
571+
inadequate to deal with the complexity of real-world time zone history,
572+
but there are sometimes reasons to use them.
573+
</para>
574+
575+
<para>
576+
A POSIX time zone specification has the form
577+
<synopsis>
578+
<replaceable>STD</replaceable> <replaceable>offset</replaceable> <optional> <replaceable>DST</replaceable> <optional> <replaceable>dstoffset</replaceable> </optional> <optional> , <replaceable>rule</replaceable> </optional> </optional>
579+
</synopsis>
580+
(For readability, we show spaces between the fields, but spaces should
581+
not be used in practice.) The fields are:
582+
<itemizedlist>
583+
<listitem>
584+
<para>
585+
<replaceable>STD</replaceable> is the zone abbreviation to be used
586+
for standard time.
587+
</para>
588+
</listitem>
589+
<listitem>
590+
<para>
591+
<replaceable>offset</replaceable> is the zone's standard-time offset
592+
from UTC.
593+
</para>
594+
</listitem>
595+
<listitem>
596+
<para>
597+
<replaceable>DST</replaceable> is the zone abbreviation to be used
598+
for daylight-savings time. If this field and the following ones are
599+
omitted, the zone uses a fixed UTC offset with no daylight-savings
600+
rule.
601+
</para>
602+
</listitem>
603+
<listitem>
604+
<para>
605+
<replaceable>dstoffset</replaceable> is the daylight-savings offset
606+
from UTC. This field is typically omitted, since it defaults to one
607+
hour less than the standard-time <replaceable>offset</replaceable>,
608+
which is usually the right thing.
609+
</para>
610+
</listitem>
611+
<listitem>
612+
<para>
613+
<replaceable>rule</replaceable> defines the rule for when daylight
614+
savings is in effect, as described below.
615+
</para>
616+
</listitem>
617+
</itemizedlist>
618+
</para>
619+
620+
<para>
621+
In this syntax, a zone abbreviation can be a string of letters, such
622+
as <literal>EST</literal>, or an arbitrary string surrounded by angle
623+
brackets, such as <literal>&lt;UTC-05&gt;</literal>.
624+
Note that the zone abbreviations given here are only used for output,
625+
and even then only in some timestamp output formats. The zone
626+
abbreviations recognized in timestamp input are determined as explained
627+
in <xref linkend="datetime-config-files"/>.
628+
</para>
629+
630+
<para>
631+
The offset fields specify the hours, and optionally minutes and seconds,
632+
difference from UTC. They have the format
633+
<replaceable>hh</replaceable><optional><literal>:</literal><replaceable>mm</replaceable><optional><literal>:</literal><replaceable>ss</replaceable></optional></optional>
634+
optionally with a leading sign (<literal>+</literal>
635+
or <literal>-</literal>). The positive sign is used for
636+
zones <emphasis>west</emphasis> of Greenwich. (Note that this is the
637+
opposite of the ISO-8601 sign convention used elsewhere in
638+
<acronym>PostgreSQL</acronym>.) <replaceable>hh</replaceable> can have
639+
one or two digits; <replaceable>mm</replaceable>
640+
and <replaceable>ss</replaceable> (if used) must have two.
641+
</para>
642+
643+
<para>
644+
The daylight-savings transition <replaceable>rule</replaceable> has the
645+
format
646+
<synopsis>
647+
<replaceable>dstdate</replaceable> <optional> <literal>/</literal> <replaceable>dsttime</replaceable> </optional> <literal>,</literal> <replaceable>stddate</replaceable> <optional> <literal>/</literal> <replaceable>stdtime</replaceable> </optional>
648+
</synopsis>
649+
(As before, spaces should not be included in practice.)
650+
The <replaceable>dstdate</replaceable>
651+
and <replaceable>dsttime</replaceable> fields define when daylight-savings
652+
time starts, while <replaceable>stddate</replaceable>
653+
and <replaceable>stdtime</replaceable> define when standard time
654+
starts. (In some cases, notably in zones south of the equator, the
655+
former might be later in the year than the latter.) The date fields
656+
have one of these formats:
657+
<variablelist>
658+
<varlistentry>
659+
<term><replaceable>n</replaceable></term>
660+
<listitem>
661+
<para>
662+
A plain integer denotes a day of the year, counting from zero to
663+
364, or to 365 in leap years.
664+
</para>
665+
</listitem>
666+
</varlistentry>
667+
<varlistentry>
668+
<term><literal>J</literal><replaceable>n</replaceable></term>
669+
<listitem>
670+
<para>
671+
In this form, <replaceable>n</replaceable> counts from 1 to 365,
672+
and February 29 is not counted even if it is present. (Thus, a
673+
transition occurring on February 29 could not be specified this
674+
way. However, days after February have the same numbers whether
675+
it's a leap year or not, so that this form is usually more useful
676+
than the plain-integer form for transitions on fixed dates.)
677+
</para>
678+
</listitem>
679+
</varlistentry>
680+
<varlistentry>
681+
<term><literal>M</literal><replaceable>m</replaceable><literal>.</literal><replaceable>n</replaceable><literal>.</literal><replaceable>d</replaceable></term>
682+
<listitem>
683+
<para>
684+
This form specifies a transition that always happens during the same
685+
month and on the same day of the week. <replaceable>m</replaceable>
686+
identifies the month, from 1 to 12. <replaceable>n</replaceable>
687+
specifies the <replaceable>n</replaceable>'th occurrence of the
688+
weekday identified by <replaceable>d</replaceable>.
689+
<replaceable>n</replaceable> is a number between 1 and 4, or 5
690+
meaning the last occurrence of that weekday in the month (which
691+
could be the fourth or the fifth). <replaceable>d</replaceable> is
692+
a number between 0 and 6, with 0 indicating Sunday.
693+
For example, <literal>M3.2.0</literal> means <quote>the second
694+
Sunday in March</quote>.
695+
</para>
696+
</listitem>
697+
</varlistentry>
698+
</variablelist>
699+
</para>
700+
701+
<note>
702+
<para>
703+
The <literal>M</literal> format is sufficient to describe many common
704+
daylight-savings transition laws. But note that none of these variants
705+
can deal with daylight-savings law changes, so in practice the
706+
historical data stored for named time zones (in the IANA time zone
707+
database) is necessary to interpret past time stamps correctly.
708+
</para>
709+
</note>
710+
711+
<para>
712+
The time fields in a transition rule have the same format as the offset
713+
fields described previously, except that they cannot contain signs.
714+
They define the current local time at which the change to the other
715+
time occurs. If omitted, they default to <literal>02:00:00</literal>.
716+
</para>
717+
718+
<para>
719+
If a daylight-savings abbreviation is given but the
720+
transition <replaceable>rule</replaceable> field is omitted,
721+
<productname>PostgreSQL</productname> attempts to determine the
722+
transition times by consulting the <filename>posixrules</filename> file
723+
in the IANA time zone database. This file has the same format as a
724+
full time zone entry, but only its transition timing rules are used,
725+
not its UTC offsets. Typically, this file has the same contents as the
726+
<literal>US/Eastern</literal> file, so that POSIX-style time zone
727+
specifications follow USA daylight-savings rules. If needed, you can
728+
adjust this behavior by replacing the <filename>posixrules</filename>
729+
file.
730+
</para>
731+
732+
<note>
733+
<para>
734+
The facility to consult a <filename>posixrules</filename> file has
735+
been deprecated by IANA, and it is likely to go away in the future.
736+
One bug in this feature, which is unlikely to be fixed before it
737+
disappears, is that it fails to apply DST rules to dates after 2038.
738+
</para>
739+
</note>
740+
741+
<para>
742+
If the <filename>posixrules</filename> file is not present,
743+
the fallback behavior is to use the
744+
rule <literal>M3.2.0,M11.1.0</literal>, which corresponds to USA
745+
practice as of 2020 (that is, spring forward on the second Sunday of
746+
March, fall back on the first Sunday of November, both transitions
747+
occurring at 2AM prevailing time).
748+
</para>
749+
750+
<para>
751+
As an example, <literal>CET-1CEST,M3.5.0,M10.5.0/3</literal> describes
752+
current (as of 2020) timekeeping practice in Paris. This specification
753+
says that standard time has the abbreviation <literal>CET</literal> and
754+
is one hour ahead (east) of UTC; daylight savings time has the
755+
abbreviation <literal>CEST</literal> and is implicitly two hours ahead
756+
of UTC; daylight savings time begins on the last Sunday in March at 2AM
757+
CET and ends on the last Sunday in October at 3AM CEST.
758+
</para>
759+
760+
<para>
761+
One should be wary that it is easy to misspell a POSIX-style time zone
762+
specification, since there is no check on the reasonableness of the
763+
zone abbreviation(s). For example, <literal>SET TIMEZONE TO
764+
FOOBAR0</literal> will work, leaving the system effectively using a
765+
rather peculiar abbreviation for UTC.
766+
</para>
767+
768+
</sect1>
769+
558770
<sect1 id="datetime-units-history">
559771
<title>History of Units</title>
560772

0 commit comments

Comments
 (0)