Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
QReS Timezone Policy
--------------------
"Time", and its representation in software, has a lot of tricky subtleties.
If you write any QReS code which involves temporal quantities (and chances
are good that you will --- it's a reservation system), please adhere to the
following guidelines.
Try to use the utilities in "quux/time.lisp" as much as possible. Avoid
writing time-manipulation code from scratch, and even avoid adding new
functionality to time.lisp without review. (There are things which have
been purposefully omitted because, although they would seem like handy
functions, they actually are not.)
-matto m.
Some Guidelines: UTC or Local time? A tricky question.
--------------------------------------------------------
Rule #0A: Policy or not, all time-related variables (or DB columns) must
have names which explicitly declare whether the quantity is
'local' or 'UTC', or a 'zoned-time' object.
How? Simple; use the suffixes "-local", "-utc" and "-zul":
Lisp SQL
o local: foobar-local foobar_local
o UTC: foobar-utc foobar_utc
o zoned: foobar-zul foobar_zul
Rule #0B: All time-related variables must also have names which explicitly
declare whether the quantity is used as just a 'date', just a
'tofd' (time-of-day), or a complete 'time' (i.e. date+tofd).
Rule #1: If both the UTC and local-time perspectives are ever relevant for
some quantity, then use a 'zoned-time' object, so that the local
TZ-offset is stored along with the time.
This gives the system a chance of catching and dealing with
changes/errors in TZ, and avoids the need to recalculate the
TZ every time the quantity is used.
Rule #2: If the UTC perspective is ever relevant, then store UTC in
the database. In other words, 'zoned-time' should be stored
as a UTC time and a local time. (An alternate combination
is UTC and TZ-offset, but often it is more useful to be able
to perform a SQL query on the local time than on the tz-offset.)
This allows DB operators to make intelligent calculations
of physical order and duration.
Rule #3: NEVER use lisp's 'decode-universal-time' or 'encode-universal-time'.
(Use quux's 'decode-integer-time', 'encode-integer-time', and their
relatives instead.)
Rule #4: ALWAYS supply a timezone of "0" to 'decode-universal-time'
and to 'encode-universal-time'. (The local TZ of the machine
on which the server is running is *never* useful.)
Rule #5: Temporal quantities are opaque.
Use the symbolic constants such as "$1hour" or "$24hours" to
generate temporal quantities.
Use the functions exported from quux/time.lisp to manipulate,
parse, write, compare, etc. times.
Rule #6: Temporal quantities which have physical meaning (e.g. which
label the moments at which events occur and/or which will
be compared to one another to sort those events) must use
UTC.
A Taxonomy of Time
------------------
o Time vs Date vs Time-of-Day
"Time" refers to a fully-specified 'moment'. A "Time" quantity
can be broken into two major components, "Date" and "Time of Day".
"Time of Day" is the duration elapsed since the last midnight,
typically broken down further into hours, minutes, and seconds.
"Date" is a kind of a label for the most recent midnight, broken
down further into year, month, and day.
o Local vs UTC
A UTC 'time' is a fully-specified moment in the spacetime fabric
of the universe (i.e. date + tofd). It is a real, physical quantity.
A local 'time' is more or less just a facsimile representation of a
bunch of fields (month, day, hour...). It has dubious physical
meaning beyond that. It is not necessarily meaningful to compare
local times from different locales; nor is it always meaningful
to compare local times from the *same* locale!
Local 'tofd' and local 'date' are useful concepts, as they really
name subsets of the full set of time components (year, month, day...).
UTC 'tofd' and UTC 'date' are not generally useful by themselves.
o Date (and Time) as an Interval
Although temporal quantities label moments, they typically *mean*
intervals. Temporal intervals are expressed as half-open intervals
[m1, m2) between moment m1 and m2.
A 'time' based in seconds is the interval [s, s+1) from a particular
moment s to the next moment, one second later. Since all seconds
are the same duration, 'time' quantities are well-formed in both
UTC and local times. The meanings of 'time' as a moment or an
interval are compatible (i.e. specifying any moment s uniquely
identifies the s+1 which defines the interval).
A 'date' based in days is the interval [d, d+1) from a particular
midnight moment d to the next, one "day" later. However, days
are not all the same duration; the duration of a day is affected
by timezone changes (e.g. daylight saving time). For this reason:
o A 'day' is only meaningful when treated as an interval,
i.e. both start and end times are required.
o A 'day' is an inherently local quantity --- its duration
is determined by the timezone rules in effect for a
particular location.
o 'UTC date' is meaningless, since timezone transformations
cannot guarantee translation of a "UTC day" interval into
"local day" interval.