@@ -1,53 +1,193 @@
1−------------------------------------------------------------------------------
2−-- |
3−-- Module: Database.PostgreSQL.Simple.Time
4−-- Copyright: (c) 2012 Leon P Smith
5−-- License: BSD3
6−-- Maintainer: Leon P Smith <leon@melding-monads.com>
7−-- Stability: experimental
8−--
9−-- Time types that supports positive and negative infinity. Also includes
10−-- new time parsers and printers with better performance than GHC's time
11−-- package.
12−--
13−-- The parsers only understand the specific variant of ISO 8601 that
14−-- PostgreSQL emits, and the printers attempt to duplicate this syntax.
15−-- Thus the @datestyle@ parameter for the connection must be set to @ISO@.
16−--
17−-- These parsers and printers likely have problems and shortcomings. Some
18−-- that I know of:
19−--
20−-- 1 @TimestampTZ@s before a timezone-dependent point in time cannot be
21−-- parsed, because the parsers can only handle timezone offsets of a
22−-- integer number of minutes. However, PostgreSQL will include seconds
23−-- in the offset, depending on the historical time standards for the city
24−-- identifying the time zone.
25−--
26−-- This boundary point often marks an event of some interest. In the US
27−-- for example, @timestamptz@s before @1883-Nov-18 12:00:00@ local time
28−-- cannot be parsed. This is the moment Standard Railway Time went live.
29−-- Concretely, PostgreSQL will emit @1883-11-18 12:03:57-04:56:02@
30−-- instead of @1883-11-18 11:59:59-05@ when the @timezone@ parameter
31−-- for the connection is set to @America/New_York@.
32−--
33−-- 2. Dates and times surrounding @1582-Feb-24@, the date the Gregorian
34−-- Calendar was introduced, should be investigated for conversion errors.
35−--
36−-- 3. Points in time Before Christ are not also not supported. For example,
37−-- PostgreSQL will emit @0045-01-01 BC@ for a value of a @date@ type.
38−-- This is the year that the Julian Calendar was adopted.
39−--
40−-- However, it should be noted that the old parsers also had issues 1 and 3.
41−-- Also, the new parsers now correctly handle time zones that include minutes
42−-- in their offset. Most notably, this includes all of India and parts of
43−-- Canada and Australia.
44−--
45−-- PostgreSQL uses the zoneinfo database for its time zone information.
46−-- You can read more about PostgreSQL's date and time types at
47−-- <http://www.postgresql.org/docs/9.1/static/datatype-datetime.html>,
48−-- and zoneinfo at <http://en.wikipedia.org/wiki/Tz_database>.
49−--
50−------------------------------------------------------------------------------
1+{- |
2+Module: Database.PostgreSQL.Simple.Time
3+Copyright: (c) 2012-2015 Leon P Smith
4+License: BSD3
5+Maintainer: Leon P Smith <leon@melding-monads.com>
6+Stability: experimental
7+
8+This module provides time types that supports positive and negative
9+infinity, as well as some functions for converting to and from strings.
10+
11+Also, this module also contains commentary regarding postgresql's timestamp
12+types, timekeeping in general, and how it relates to postgresql-simple.
13+You can read more about PostgreSQL's date and time types at
14+<http://www.postgresql.org/docs/9.1/static/datatype-datetime.html>,
15+and the IANA timezone database at <https://en.wikipedia.org/wiki/Tz_database>.
16+
17+Stack Overflow also has some excellent commentary on time, if it is a
18+wiki page or a highly upvoted question and answer. If the answer regarding
19+time has not received hundreds of upvotes, then the answer is almost
20+invariably completely and painfully wrong, even if it's the chosen answer
21+or the most highly upvoted answer to a question.
22+
23+PostgreSQL's @timestamp with time zone@ (hereafter, @timestamptz@) can be
24+converted to Haskell's 'Data.Time.UTCTime' and 'Data.Time.ZonedTime' types,
25+because their values represent an unambiguous point in time. PostgreSQL's
26+@timestamp without time zone@ (hereafter, @timestamp@) can be converted
27+to Haskell's 'Data.Time.LocalTime', because values of these types can only be
28+disambiguated in a larger context.
29+
30+While this behavior may be superficially counterintuitive because the
31+names might suggest otherwise, this behavior is correct. In fact,
32+the \"timezone\" language in both the postgresql and haskell types would
33+be better read as \"offset (from UTC)\", thus we have postgresql's
34+\"timestamp with offset\" corresponding to Haskell's \"time with the
35+offset \'zero\'\" and Haskell's \"time with an offset (that might be
36+nonzero)\". Similarly, postgresql's \"timestamp without an offset\"
37+corresponds to Haskell's \"local time (without an offset)\".
38+
39+It's important to distinguish between an offset, a standard time, and
40+a time zone. An offset is simply a difference of a local time from UTC,
41+such as @+00@, @-05@, or @+05:30@. A standard time specifies an offset
42+(which may vary throughout the year, due to daylight savings) that a
43+region follows, such as Universal Coordinated Time (UTC), Eastern Standard
44+Time\/Eastern Daylight Time (EST\/EDT), or India Standard Time (IST).
45+And a timezone, much like a standard time, is a function from
46+timestamps to offsets.
47+
48+A timezone is different from a standard time because different regions
49+inside a standard time are governed by different civil authorities and
50+have different histories of time. Thus, an IANA timezone is any region
51+of the world that has had the same history of time since
52+@1970-01-01 00:00+00@.
53+
54+For example, as of today, both @America\/New_York@ and
55+@America\/Indiana\/Indianapolis@ are on the EST\/EDT time standard, but
56+Indiana used to be on Central Standard Time until 1942, and did not observe
57+daylight savings time (EST only) until 2006. Thus, the choice between
58+these two timezones still matters if you are dealing with timestamps
59+prior to 2006, and could become relevant again if (most of) Indiana
60+moves back to Central Time. (Of course, if the Central to Eastern switch
61+was the only difference, then these two timezones would be the same in
62+IANA's eyes, due to their cutoff date of 1970-01-01.)
63+
64+Getting back to the coding practicalities, PostgreSQL's @timestamptz@
65+type does not actually store an offset; rather, it uses the offset
66+provided to calculate UTC, and stores the timestamp as UTC. If an
67+offset is not provided, the given timestamp is assumed to be a local
68+time for whatever the @timezone@ variable is set to, and the IANA TZ
69+database is consulted to calculate an offset from UTC for the time in
70+question. Note that some local timestamps are ambiguous, in which
71+case PostgreSQL chooses one of the possible offsets.
72+
73+When retrieving a @timestamptz@, the backend looks at the @timezone@
74+connection variable and then consults the IANA TZ database to calculate
75+an offset for the timestamp in the given timezone. Note that while some
76+of the information contained in the IANA TZ database is a bit of a
77+standardized fiction, the conversion from UTC time to a
78+(local time, offset) pair is always unambiguous, and the result can
79+always be unambiguously converted back to UTC. Thus, postgresql-simple
80+can interpret this result as a 'Data.Time.ZonedTime', or use the offset to
81+convert to 'Data.Time.UTCTime'.
82+
83+By contrast, the @timestamp@ type ignores any offsets provided to it,
84+and never sends back an offset. Thus, postgresql-simple equates this
85+with 'Data.Time.LocalTime', which has no concept of an offset. One can
86+convert between @timestamptz@ and @timestamp@ using the @AT TIME ZONE@
87+operator, whose semantics also demonstrates that @timestamptz@ is
88+'Data.Time.UTCTime' whereas @timestamp@ is 'Data.Time.LocalTime'.
89+
90+The default default setting for the @timezone@ variable is @\'localtime\'@,
91+which normally corresponds to the server's local timezone. However,
92+this default can be modified on the server side for an entire cluster, or
93+on a per-user or per-database basis. On the client side, the timezone can
94+be set via the @PGTZ@ environment variable on the client, or be modified at
95+any time for the duration of the entire connection, just a single
96+transaction, or the execution context of a server-side function.
97+
98+With a few caveats, postgresql-simple is designed so that you can both send
99+and receive timestamps with the server and get a correct result, no matter
100+what the @timezone@ setting is. But it is important to understand the caveats:
101+
102+1. The correctness of server-side computations can depend on the @timezone@
103+ setting, for example when adding an @interval@ to a @timestamptz@, or
104+ when type casting between @timestamp@ and @timestamptz@.
105+
106+2. The offset in a 'Data.Time.ZonedTime' result will depend on the
107+ @timezone@ setting, although the result will always represent the
108+ same instant in time regardless of the offset.
109+
110+3. Sending a 'Data.Time.LocalTime' and interpreting it as a @timestamptz@
111+ can be useful, as it will be converted to UTC via the tz database,
112+ but correctness will depend on the @timezone@ setting. You may prefer
113+ to use an explicit @AT TIME ZONE@ instead.
114+
115+Furthermore, although these points don't involve the @timezone@ setting,
116+they are related to the last point above:
117+
118+1. Sending a 'Data.Time.UTCTime' and interpreting it as a @timestamp@ can
119+ be useful. In practice, the most common context used to disambiguate
120+ @timestamp@ is that it represents UTC, and this coding technique will
121+ work as expected in this context.
122+
123+2. Sending a 'Data.Time.ZonedTime' and interpreting it as a @timestamp@ is
124+ almost always the wrong thing to do, as the offset will be ignored and
125+ discarded. This is likely to lead to inconsistencies in the database,
126+ and may lead to partial data loss. Moreover, one should keep in mind
127+ that "ZonedTime" is misnamed, and one should not conflate an offset
128+ with a timezone.
129+
130+There are a few limitations and caveats that one might need to be aware
131+of with the current implementation when dealing with older timestamps:
132+
133+For sufficiently old timestamps in almost all timezones, the IANA TZ
134+database specifies offsets from UTC that is not an integral number of
135+minutes. This corresponds to local mean time; that is, astronomical
136+time in the city that defines the timezone. Different timezones moved
137+away from local mean time to a standard time at different points in
138+history, so \"sufficiently old\" depends on the timezone in question.
139+
140+Thus, when retrieving a @timestamptz@ postgresql will in some cases
141+provide seconds in the offset. For example:
142+
143+@
144+$ psql
145+psql (9.4.5)
146+Type \"help\" for help.
147+
148+lpsmith=> SET timezone TO \'America/New_York\';
149+SET
150+lpsmith=> VALUES (\'1883-11-18 16:59:59+00\'::timestamptz),
151+ (\'1883-11-18 17:00:00+00\'::timestamptz);
152+ column1
153+------------------------------
154+ 1883-11-18 12:03:57-04:56:02
155+ 1883-11-18 12:00:00-05
156+(2 rows)
157+@
158+
159+Both of these timestamps can be parsed as a 'Data.Time.UTCTime' type,
160+however 'Data.Time.ZonedTime' will fail on the former timestamp.
161+Because 'Data.Time.ZonedTime' assumes that offsets are an integer number
162+of minutes, there isn't an particularly good solution here.
163+
164+PostgreSQL, like most software, uses the proleptic Gregorian calendar
165+for its date calculations, extending the Gregorian calendar backwards
166+in time before its introduction and pretending that the Julian calendar
167+does not exist. For most purposes, the adoption of the Gregorian calendar
168+ranges from @1582-10-15@ to @1923-03-01@, depending on location and
169+sometimes even political allegiances within a single location.
170+
171+Timestamps BCE are not supported. For example, PostgreSQL
172+will emit \"@0045-01-01 BC@\" for the first proleptic Gregorian day of
173+the year the Roman Empire adopted the Julian Calendar, but
174+postgresql-simple does not (yet?) have the ability to either parse or
175+generate this syntax. Unfortunately this syntax isn't convenient to
176+print or especially parse.
177+
178+Also, postgresql itself cannot parse or print dates before @4714-11-24 BC@,
179+ which is the Julian date on the proleptic Gregorian Calendar. Although
180+postgresql's timestamp types are perfectly capable of representing timestamps
181+nearly 300,000 years in the past, using this would require postgresql-simple
182+and other client programs to support binary parameters and results.
183+
184+Dealing with years BCE is also complicated slightly by the fact that
185+Haskell's time library has a year \"0000\", which is a convention often
186+used by astronomers, while postgresql adopts the more historically
187+accurate convention that there is no year zero, but rather \"1 BCE\"
188+was immediately followed by \"1 CE\".
189+
190+-}
51191
52192module Database.PostgreSQL.Simple.Time
53193 ( Unbounded(..)