Coverage for tests/test_dateTime.py : 14%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#
2# LSST Data Management System
3#
4# Copyright 2008-2017 AURA/LSST.
5#
6# This product includes software developed by the
7# LSST Project (http://www.lsst.org/).
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the LSST License Statement and
20# the GNU General Public License along with this program. If not,
21# see <http://www.lsstcorp.org/LegalNotices/>.
22#
24import os
25import pickle
26import time
27import unittest
29from lsst.daf.base import DateTime
30import lsst.pex.exceptions as pexExcept
33class DateTimeTestCase(unittest.TestCase):
34 """A test case for DateTime."""
36 def setUp(self):
37 self.timeScales = (DateTime.TAI, DateTime.TT, DateTime.UTC)
38 self.dateSystems = (DateTime.JD, DateTime.MJD, DateTime.EPOCH)
40 def testMJD(self):
41 ts = DateTime(45205.125, DateTime.MJD, DateTime.UTC)
42 self.assertEqual(ts.nsecs(DateTime.UTC), 399006000000000000)
43 self.assertEqual(ts.nsecs(DateTime.TAI), 399006021000000000)
44 self.assertAlmostEqual(ts.get(DateTime.MJD, DateTime.UTC), 45205.125)
45 self.assertAlmostEqual(ts.get(DateTime.MJD, DateTime.TAI), 45205.125 + 21.0/86400.0)
46 self.assertTrue(ts.isValid())
48 def testLeapSecond(self):
49 trials = ((45205., 21),
50 (41498.99, 10),
51 (41499.01, 11),
52 (57203.99, 35),
53 (57204.01, 36),
54 (57000., 35),
55 (57210., 36))
56 for mjd, diff in trials:
57 ts = DateTime(mjd, DateTime.MJD, DateTime.UTC)
58 delta = ts.nsecs(DateTime.TAI) - ts.nsecs(DateTime.UTC)
59 self.assertEqual(delta/1E9, diff)
61 def testNsecs(self):
62 ts = DateTime(1192755473000000000, DateTime.UTC)
63 self.assertEqual(ts.nsecs(DateTime.UTC), 1192755473000000000)
64 self.assertEqual(ts.nsecs(DateTime.TAI), 1192755506000000000)
65 self.assertEqual(ts.nsecs(), 1192755506000000000)
66 self.assertAlmostEqual(ts.get(DateTime.MJD, DateTime.UTC), 54392.040196759262)
67 ts2 = ts
68 self.assertEqual(ts, ts2)
69 ts2 = DateTime(1192755473000000000, DateTime.UTC)
70 self.assertEqual(ts, ts2)
71 ts2 = DateTime(1234567890000000000, DateTime.UTC)
72 self.assertNotEqual(ts, ts2)
74 def testBoundaryMJD(self):
75 ts = DateTime(47892.0, DateTime.MJD, DateTime.UTC)
76 self.assertEqual(ts.nsecs(DateTime.UTC), 631152000000000000)
77 self.assertEqual(ts.nsecs(DateTime.TAI), 631152025000000000)
78 self.assertEqual(ts.get(DateTime.MJD, DateTime.UTC), 47892.0)
80 def testCrossBoundaryNsecs(self):
81 ts = DateTime(631151998000000000, DateTime.UTC)
82 self.assertEqual(ts.nsecs(DateTime.UTC), 631151998000000000)
83 self.assertEqual(ts.nsecs(DateTime.TAI), 631152022000000000)
85 def testNsecsTAI(self):
86 ts = DateTime(1192755506000000000, DateTime.TAI)
87 self.assertEqual(ts.nsecs(DateTime.UTC), 1192755473000000000)
88 self.assertEqual(ts.nsecs(DateTime.TAI), 1192755506000000000)
89 self.assertEqual(ts.nsecs(), 1192755506000000000)
90 self.assertAlmostEqual(ts.get(DateTime.MJD, DateTime.UTC), 54392.040196759262)
91 self.assertTrue(ts.isValid())
93 def testNsecsDefault(self):
94 ts = DateTime(1192755506000000000)
95 self.assertEqual(ts.nsecs(DateTime.UTC), 1192755473000000000)
96 self.assertEqual(ts.nsecs(DateTime.TAI), 1192755506000000000)
97 self.assertEqual(ts.nsecs(), 1192755506000000000)
98 self.assertAlmostEqual(ts.get(DateTime.MJD, DateTime.UTC), 54392.040196759262)
99 self.assertTrue(ts.isValid())
101 def testNow(self):
102 successes = 0
103 for _ in range(10):
104 secs = time.time()
105 ts = DateTime.now()
106 diff = ts.nsecs(DateTime.UTC)/1.0e9 - secs
107 if diff > -0.001 and diff < 0.1:
108 successes += 1
109 self.assertGreaterEqual(successes, 3)
111 def testIsoEpoch(self):
112 ts = DateTime("19700101T000000Z", DateTime.UTC)
113 self.assertEqual(ts.nsecs(DateTime.UTC), 0)
114 self.assertEqual(ts.toString(ts.UTC), "1970-01-01T00:00:00.000000000Z")
116 def testIsoUTCBasic(self):
117 """Test basic ISO string input and output of UTC dates"""
118 for dateSep in ("-", ""): # "-" date separator is optional
119 for timeSep in (":", ""): # ":" time separator is optional
120 for decPt in (".", ","): # "." or "," may be used as decimal point
121 dateStr = "2009{0}04{0}02T07{1}26{1}39{2}314159265Z".format(dateSep, timeSep, decPt)
122 ts = DateTime(dateStr, DateTime.UTC)
123 self.assertEqual(ts.nsecs(DateTime.TT), 1238657265498159265)
124 self.assertEqual(ts.nsecs(DateTime.TAI), 1238657233314159265)
125 self.assertEqual(ts.nsecs(DateTime.UTC), 1238657199314159265)
126 self.assertEqual(ts.toString(ts.UTC), "2009-04-02T07:26:39.314159265Z")
128 def testIsoNonUTCBasics(self):
129 """Test basic ISO string input and output of TAI and TT dates"""
130 for scale in (DateTime.TAI, DateTime.TT):
131 for dateSep in ("-", ""): # "-" date separator is optional
132 for timeSep in (":", ""): # ":" time separator is optional
133 for decPt in (".", ","): # "." or "," may be used as decimal point
134 dateStr = "2009{0}04{0}02T07{1}26{1}39{2}314159265".format(dateSep, timeSep, decPt)
135 ts = DateTime(dateStr, scale)
136 self.assertEqual(ts.toString(scale), "2009-04-02T07:26:39.314159265")
137 self.assertTrue(ts.isValid())
139 def testIsoExpanded(self):
140 ts = DateTime("2009-04-02T07:26:39.314159265Z", DateTime.UTC)
141 self.assertEqual(ts.nsecs(DateTime.TAI), 1238657233314159265)
142 self.assertEqual(ts.nsecs(DateTime.UTC), 1238657199314159265)
143 self.assertEqual(ts.toString(ts.UTC), "2009-04-02T07:26:39.314159265Z")
144 self.assertTrue(ts.isValid())
146 def testIsoNoNSecs(self):
147 ts = DateTime("2009-04-02T07:26:39Z", DateTime.UTC)
148 self.assertEqual(ts.nsecs(DateTime.TAI), 1238657233000000000)
149 self.assertEqual(ts.nsecs(DateTime.UTC), 1238657199000000000)
150 self.assertEqual(ts.toString(ts.UTC), "2009-04-02T07:26:39.000000000Z")
151 self.assertTrue(ts.isValid())
153 def testIsoThrow(self):
154 with self.assertRaises(pexExcept.DomainError):
155 DateTime("2009-04-01T23:36:05", DateTime.UTC) # Z time zone required for UTC
156 for scale in (DateTime.TAI, DateTime.TT):
157 with self.assertRaises(pexExcept.DomainError):
158 DateTime("2009-04-01T23:36:05Z", scale) # Z time zone forbidden for TAI or TT
160 for scale in self.timeScales:
161 with self.assertRaises(pexExcept.DomainError):
162 DateTime("20090401", scale) # time required
163 with self.assertRaises(pexExcept.DomainError):
164 DateTime("20090401T", DateTime.UTC) # time required
165 with self.assertRaises(pexExcept.DomainError):
166 DateTime("2009-04-01T", DateTime.UTC) # time required
167 with self.assertRaises(pexExcept.DomainError):
168 DateTime("2009-04-01T23:36:05-0700", DateTime.UTC) # time zone offset not supported
169 with self.assertRaises(pexExcept.DomainError):
170 DateTime("2009/04/01T23:36:05Z", DateTime.UTC) # "/" not valid
171 with self.assertRaises(pexExcept.DomainError):
172 DateTime("2009-04-01T23:36", DateTime.UTC) # partial time
173 with self.assertRaises(pexExcept.DomainError):
174 DateTime("2009-04", DateTime.UTC) # partial date without time
175 with self.assertRaises(pexExcept.DomainError):
176 DateTime("2009-04T23:36.05", DateTime.UTC) # partial date with time
177 with self.assertRaises(pexExcept.DomainError):
178 DateTime("09-04-01T23:36:05", DateTime.UTC) # 2 digit year
180 # earliest allowed UTC date is the earliest date in the leap second
181 # table
182 try:
183 minLeapSecUTC = "1961-01-01T00:00:00Z"
184 dt = DateTime(minLeapSecUTC, DateTime.UTC)
185 dt.toString(DateTime.UTC)
186 except Exception:
187 self.fail("minLeapSecUTC={} failed, but should be OK".format(minLeapSecUTC))
188 with self.assertRaises(pexExcept.DomainError):
189 DateTime("1960-01-01T23:59:59Z", DateTime.UTC) # just before leap second table starts
191 # earliest allowed date for TAI and TT is year = 1902
192 for timeSys in (DateTime.TAI, DateTime.TT):
193 try:
194 earliestDate = "1902-01-01T00:00:00"
195 dt = DateTime(earliestDate, timeSys)
196 dt.toString(DateTime.TAI)
197 dt.toString(DateTime.TT)
198 except Exception:
199 self.fail("{} system={} failed, but should be OK".format(earliestDate, timeSys))
201 # dates before the leap second table can be created using TAI or TT,
202 # but not viewed in UTC
203 earlyDt = DateTime("1960-01-01T00:00:00", DateTime.TAI)
204 with self.assertRaises(pexExcept.DomainError):
205 earlyDt.toString(DateTime.UTC)
207 with self.assertRaises(pexExcept.DomainError):
208 DateTime("1901-12-12T23:59:59Z", DateTime.TAI) # too early
209 with self.assertRaises(pexExcept.DomainError):
210 DateTime("1700-01-01T00:00:00Z", DateTime.TAI) # way too early
211 with self.assertRaises(pexExcept.DomainError):
212 DateTime("2262-01-01T00:00:00Z", DateTime.TAI) # too late
213 with self.assertRaises(pexExcept.DomainError):
214 DateTime("3200-01-01T00:00:00Z", DateTime.TAI) # way too late
216 def testWraparound(self):
217 """Test that a date later than 2038-01-19, 03:14:07 does not wrap
218 around.
220 This will fail on old versions of unix, and indicates that DateTime
221 is not safe.
222 """
223 dateStr = "2040-01-01T00:00:00.000000000"
224 self.assertEqual(str(DateTime(dateStr, DateTime.TAI)), "DateTime(\"{}\", TAI)".format(dateStr))
226 def testDM7622(self):
227 """Test DM-7622: date with unix time = -1 seconds must be usable
229 Note that the call in question parses the ISO string without paying
230 attention to the scale (it applies the scale later),
231 so the same ISO string is wanted in all cases
232 (except with a trailing Z for UTC, and without for TAI and TT)
233 """
234 negOneSecIso = "1969-12-31T23:59:59.000000000"
235 for scale in self.timeScales:
236 dateStr = negOneSecIso + ("Z" if scale == DateTime.UTC else "")
237 try:
238 dt = DateTime(dateStr, scale)
239 except Exception:
240 self.fail("Date {} unusable; DM-7622 is still with us".format(dateStr, scale))
241 self.assertEqual(dt.nsecs(scale), int(-1e9))
243 def testStr(self):
244 timeStr1 = "2004-03-01T12:39:45.1"
245 fullTimeStr1 = "2004-03-01T12:39:45.100000000"
246 dt1 = DateTime(timeStr1, DateTime.TAI)
247 self.assertEqual(str(dt1), "DateTime(\"{}\", TAI)".format(fullTimeStr1))
248 self.assertEqual(repr(dt1), "DateTime(\"{}\", TAI)".format(fullTimeStr1))
250 timeStr2 = "2004-03-01T12:39:45.000000001"
251 dt2 = DateTime(timeStr2, DateTime.TAI)
252 self.assertEqual(str(dt2), "DateTime(\"{}\", TAI)".format(timeStr2))
253 self.assertEqual(repr(dt2), "DateTime(\"{}\", TAI)".format(timeStr2))
255 def testNsecsTT(self):
256 ts = DateTime(1192755538184000000, DateTime.TT)
257 self.assertEqual(ts.nsecs(DateTime.UTC), 1192755473000000000)
258 self.assertEqual(ts.nsecs(DateTime.TAI), 1192755506000000000)
259 self.assertEqual(ts.nsecs(), 1192755506000000000)
260 self.assertAlmostEqual(ts.get(DateTime.MJD, DateTime.UTC), 54392.040196759262)
261 self.assertTrue(ts.isValid())
263 def testFracSecs(self):
264 ts = DateTime("2004-03-01T12:39:45.1Z", DateTime.UTC)
265 self.assertEqual(ts.toString(ts.UTC), '2004-03-01T12:39:45.100000000Z')
266 ts = DateTime("2004-03-01T12:39:45.01Z", DateTime.UTC)
267 self.assertEqual(ts.toString(ts.UTC), '2004-03-01T12:39:45.010000000Z')
268 ts = DateTime("2004-03-01T12:39:45.000000001Z", DateTime.UTC) # nanosecond
269 self.assertEqual(ts.toString(ts.UTC), '2004-03-01T12:39:45.000000001Z')
270 ts = DateTime("2004-03-01T12:39:45.0000000001Z", DateTime.UTC) # too small
271 self.assertEqual(ts.toString(ts.UTC), '2004-03-01T12:39:45.000000000Z')
273 def testInvalid(self):
274 ts = DateTime()
275 self.assertFalse(ts.isValid())
276 for scale in self.timeScales:
277 self.assertEqual(ts.nsecs(scale), DateTime.invalid_nsecs)
278 for system in self.dateSystems:
279 with self.assertRaises(RuntimeError):
280 ts.get(system, scale)
281 with self.assertRaises(RuntimeError):
282 ts.gmtime(scale)
283 with self.assertRaises(RuntimeError):
284 ts.timespec(scale)
285 with self.assertRaises(RuntimeError):
286 ts.timeval(scale)
287 with self.assertRaises(RuntimeError):
288 ts.toString(scale)
289 self.assertEqual(repr(ts), "DateTime()")
291 def testNegative(self):
292 ts = DateTime("1969-03-01T00:00:32Z", DateTime.UTC)
293 self.assertEqual(ts.toString(ts.UTC), '1969-03-01T00:00:32.000000000Z')
294 ts = DateTime("1969-01-01T00:00:00Z", DateTime.UTC)
295 self.assertEqual(ts.toString(ts.UTC), '1969-01-01T00:00:00.000000000Z')
296 ts = DateTime("1969-01-01T00:00:40Z", DateTime.UTC)
297 self.assertEqual(ts.toString(ts.UTC), '1969-01-01T00:00:40.000000000Z')
298 ts = DateTime("1969-01-01T00:00:38Z", DateTime.UTC)
299 self.assertEqual(ts.toString(ts.UTC), '1969-01-01T00:00:38.000000000Z')
300 ts = DateTime("1969-03-01T12:39:45Z", DateTime.UTC)
301 self.assertEqual(ts.toString(ts.UTC), '1969-03-01T12:39:45.000000000Z')
302 ts = DateTime("1969-03-01T12:39:45.000000001Z", DateTime.UTC)
303 self.assertEqual(ts.toString(ts.UTC), '1969-03-01T12:39:45.000000001Z')
304 self.assertTrue(ts.isValid())
306 # Note slight inaccuracy in UTC-TAI-UTC round-trip
307 ts = DateTime("1969-03-01T12:39:45.12345Z", DateTime.UTC)
308 self.assertEqual(ts.toString(ts.UTC), '1969-03-01T12:39:45.123449996Z')
309 ts = DateTime("1969-03-01T12:39:45.123456Z", DateTime.UTC)
310 self.assertEqual(ts.toString(ts.UTC), '1969-03-01T12:39:45.123455996Z')
312 ts = DateTime(-1, DateTime.TAI)
313 self.assertEqual(ts.toString(ts.UTC), '1969-12-31T23:59:51.999918239Z')
314 ts = DateTime(0, DateTime.TAI)
315 self.assertEqual(ts.toString(ts.UTC), '1969-12-31T23:59:51.999918240Z')
316 ts = DateTime(1, DateTime.TAI)
317 self.assertEqual(ts.toString(ts.UTC), '1969-12-31T23:59:51.999918241Z')
319 ts = DateTime(-1, DateTime.UTC)
320 self.assertEqual(ts.toString(ts.UTC), '1969-12-31T23:59:59.999999999Z')
321 ts = DateTime(0, DateTime.UTC)
322 self.assertEqual(ts.toString(ts.UTC), '1970-01-01T00:00:00.000000000Z')
323 ts = DateTime(1, DateTime.UTC)
324 self.assertEqual(ts.toString(ts.UTC), '1970-01-01T00:00:00.000000001Z')
326 def testConvert(self):
327 year = 2012
328 month = 7
329 day = 19
330 hour = 18
331 minute = 29
332 second = 33
334 ts = DateTime(year, month, day, hour, minute, second, DateTime.UTC)
335 dt = ts.toPython(DateTime.UTC)
337 self.assertEqual(dt.year, year)
338 self.assertEqual(dt.month, month)
339 self.assertEqual(dt.day, day)
340 self.assertEqual(dt.hour, hour)
341 self.assertEqual(dt.minute, minute)
342 self.assertEqual(dt.second, second)
344 def testPickle(self):
345 ts = DateTime(int(1192755473000000000), DateTime.UTC)
346 nts = pickle.loads(pickle.dumps(ts))
347 self.assertEqual(nts.nsecs(DateTime.UTC), int(1192755473000000000))
350class TimeZoneBaseTestCase(DateTimeTestCase):
351 timezone = ""
353 def setUp(self):
354 DateTimeTestCase.setUp(self)
355 self.tz = os.environ.setdefault('TZ', "")
356 os.environ['TZ'] = self.timezone
358 def tearDown(self):
359 if self.tz == "":
360 del os.environ['TZ']
361 else:
362 os.environ['TZ'] = self.tz
365class BritishTimeTestCase(TimeZoneBaseTestCase):
366 timezone = "Europe/London"
369class BritishTime2TestCase(TimeZoneBaseTestCase):
370 timezone = "GMT0BST"
373class PacificTimeTestCase(TimeZoneBaseTestCase):
374 timezone = "PST8PDT"
377if __name__ == '__main__': 377 ↛ 378line 377 didn't jump to line 378, because the condition on line 377 was never true
378 unittest.main()