Hide keyboard shortcuts

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# 

23 

24import os 

25import pickle 

26import time 

27import unittest 

28 

29from lsst.daf.base import DateTime 

30import lsst.pex.exceptions as pexExcept 

31 

32 

33class DateTimeTestCase(unittest.TestCase): 

34 """A test case for DateTime. 

35 """ 

36 

37 def setUp(self): 

38 self.timeScales = (DateTime.TAI, DateTime.TT, DateTime.UTC) 

39 self.dateSystems = (DateTime.JD, DateTime.MJD, DateTime.EPOCH) 

40 

41 def testMJD(self): 

42 ts = DateTime(45205.125, DateTime.MJD, DateTime.UTC) 

43 self.assertEqual(ts.nsecs(DateTime.UTC), 399006000000000000) 

44 self.assertEqual(ts.nsecs(DateTime.TAI), 399006021000000000) 

45 self.assertAlmostEqual(ts.get(DateTime.MJD, DateTime.UTC), 45205.125) 

46 self.assertAlmostEqual(ts.get(DateTime.MJD, DateTime.TAI), 45205.125 + 21.0/86400.0) 

47 self.assertTrue(ts.isValid()) 

48 

49 def testLeapSecond(self): 

50 trials = ((45205., 21), 

51 (41498.99, 10), 

52 (41499.01, 11), 

53 (57203.99, 35), 

54 (57204.01, 36), 

55 (57000., 35), 

56 (57210., 36)) 

57 for mjd, diff in trials: 

58 ts = DateTime(mjd, DateTime.MJD, DateTime.UTC) 

59 delta = ts.nsecs(DateTime.TAI) - ts.nsecs(DateTime.UTC) 

60 self.assertEqual(delta/1E9, diff) 

61 

62 def testNsecs(self): 

63 ts = DateTime(1192755473000000000, DateTime.UTC) 

64 self.assertEqual(ts.nsecs(DateTime.UTC), 1192755473000000000) 

65 self.assertEqual(ts.nsecs(DateTime.TAI), 1192755506000000000) 

66 self.assertEqual(ts.nsecs(), 1192755506000000000) 

67 self.assertAlmostEqual(ts.get(DateTime.MJD, DateTime.UTC), 54392.040196759262) 

68 ts2 = ts 

69 self.assertEqual(ts, ts2) 

70 ts2 = DateTime(1192755473000000000, DateTime.UTC) 

71 self.assertEqual(ts, ts2) 

72 ts2 = DateTime(1234567890000000000, DateTime.UTC) 

73 self.assertNotEqual(ts, ts2) 

74 

75 def testBoundaryMJD(self): 

76 ts = DateTime(47892.0, DateTime.MJD, DateTime.UTC) 

77 self.assertEqual(ts.nsecs(DateTime.UTC), 631152000000000000) 

78 self.assertEqual(ts.nsecs(DateTime.TAI), 631152025000000000) 

79 self.assertEqual(ts.get(DateTime.MJD, DateTime.UTC), 47892.0) 

80 

81 def testCrossBoundaryNsecs(self): 

82 ts = DateTime(631151998000000000, DateTime.UTC) 

83 self.assertEqual(ts.nsecs(DateTime.UTC), 631151998000000000) 

84 self.assertEqual(ts.nsecs(DateTime.TAI), 631152022000000000) 

85 

86 def testNsecsTAI(self): 

87 ts = DateTime(1192755506000000000, DateTime.TAI) 

88 self.assertEqual(ts.nsecs(DateTime.UTC), 1192755473000000000) 

89 self.assertEqual(ts.nsecs(DateTime.TAI), 1192755506000000000) 

90 self.assertEqual(ts.nsecs(), 1192755506000000000) 

91 self.assertAlmostEqual(ts.get(DateTime.MJD, DateTime.UTC), 54392.040196759262) 

92 self.assertTrue(ts.isValid()) 

93 

94 def testNsecsDefault(self): 

95 ts = DateTime(1192755506000000000) 

96 self.assertEqual(ts.nsecs(DateTime.UTC), 1192755473000000000) 

97 self.assertEqual(ts.nsecs(DateTime.TAI), 1192755506000000000) 

98 self.assertEqual(ts.nsecs(), 1192755506000000000) 

99 self.assertAlmostEqual(ts.get(DateTime.MJD, DateTime.UTC), 54392.040196759262) 

100 self.assertTrue(ts.isValid()) 

101 

102 def testNow(self): 

103 successes = 0 

104 for _ in range(10): 

105 secs = time.time() 

106 ts = DateTime.now() 

107 diff = ts.nsecs(DateTime.UTC)/1.0e9 - secs 

108 if diff > -0.001 and diff < 0.1: 

109 successes += 1 

110 self.assertGreaterEqual(successes, 3) 

111 

112 def testIsoEpoch(self): 

113 ts = DateTime("19700101T000000Z", DateTime.UTC) 

114 self.assertEqual(ts.nsecs(DateTime.UTC), 0) 

115 self.assertEqual(ts.toString(ts.UTC), "1970-01-01T00:00:00.000000000Z") 

116 

117 def testIsoUTCBasic(self): 

118 """Test basic ISO string input and output of UTC dates 

119 """ 

120 for dateSep in ("-", ""): # "-" date separator is optional 

121 for timeSep in (":", ""): # ":" time separator is optional 

122 for decPt in (".", ","): # "." or "," may be used as decimal point 

123 dateStr = "2009{0}04{0}02T07{1}26{1}39{2}314159265Z".format(dateSep, timeSep, decPt) 

124 ts = DateTime(dateStr, DateTime.UTC) 

125 self.assertEqual(ts.nsecs(DateTime.TT), 1238657265498159265) 

126 self.assertEqual(ts.nsecs(DateTime.TAI), 1238657233314159265) 

127 self.assertEqual(ts.nsecs(DateTime.UTC), 1238657199314159265) 

128 self.assertEqual(ts.toString(ts.UTC), "2009-04-02T07:26:39.314159265Z") 

129 

130 def testIsoNonUTCBasics(self): 

131 """Test basic ISO string input and output of TAI and TT dates 

132 """ 

133 for scale in (DateTime.TAI, DateTime.TT): 

134 for dateSep in ("-", ""): # "-" date separator is optional 

135 for timeSep in (":", ""): # ":" time separator is optional 

136 for decPt in (".", ","): # "." or "," may be used as decimal point 

137 dateStr = "2009{0}04{0}02T07{1}26{1}39{2}314159265".format(dateSep, timeSep, decPt) 

138 ts = DateTime(dateStr, scale) 

139 self.assertEqual(ts.toString(scale), "2009-04-02T07:26:39.314159265") 

140 self.assertTrue(ts.isValid()) 

141 

142 def testIsoExpanded(self): 

143 ts = DateTime("2009-04-02T07:26:39.314159265Z", DateTime.UTC) 

144 self.assertEqual(ts.nsecs(DateTime.TAI), 1238657233314159265) 

145 self.assertEqual(ts.nsecs(DateTime.UTC), 1238657199314159265) 

146 self.assertEqual(ts.toString(ts.UTC), "2009-04-02T07:26:39.314159265Z") 

147 self.assertTrue(ts.isValid()) 

148 

149 def testIsoNoNSecs(self): 

150 ts = DateTime("2009-04-02T07:26:39Z", DateTime.UTC) 

151 self.assertEqual(ts.nsecs(DateTime.TAI), 1238657233000000000) 

152 self.assertEqual(ts.nsecs(DateTime.UTC), 1238657199000000000) 

153 self.assertEqual(ts.toString(ts.UTC), "2009-04-02T07:26:39.000000000Z") 

154 self.assertTrue(ts.isValid()) 

155 

156 def testIsoThrow(self): 

157 with self.assertRaises(pexExcept.DomainError): 

158 DateTime("2009-04-01T23:36:05", DateTime.UTC) # Z time zone required for UTC 

159 for scale in (DateTime.TAI, DateTime.TT): 

160 with self.assertRaises(pexExcept.DomainError): 

161 DateTime("2009-04-01T23:36:05Z", scale) # Z time zone forbidden for TAI or TT 

162 

163 for scale in self.timeScales: 

164 with self.assertRaises(pexExcept.DomainError): 

165 DateTime("20090401", scale) # time required 

166 with self.assertRaises(pexExcept.DomainError): 

167 DateTime("20090401T", DateTime.UTC) # time required 

168 with self.assertRaises(pexExcept.DomainError): 

169 DateTime("2009-04-01T", DateTime.UTC) # time required 

170 with self.assertRaises(pexExcept.DomainError): 

171 DateTime("2009-04-01T23:36:05-0700", DateTime.UTC) # time zone offset not supported 

172 with self.assertRaises(pexExcept.DomainError): 

173 DateTime("2009/04/01T23:36:05Z", DateTime.UTC) # "/" not valid 

174 with self.assertRaises(pexExcept.DomainError): 

175 DateTime("2009-04-01T23:36", DateTime.UTC) # partial time 

176 with self.assertRaises(pexExcept.DomainError): 

177 DateTime("2009-04", DateTime.UTC) # partial date without time 

178 with self.assertRaises(pexExcept.DomainError): 

179 DateTime("2009-04T23:36.05", DateTime.UTC) # partial date with time 

180 with self.assertRaises(pexExcept.DomainError): 

181 DateTime("09-04-01T23:36:05", DateTime.UTC) # 2 digit year 

182 

183 # earliest allowed UTC date is the earliest date in the leap second 

184 # table 

185 try: 

186 minLeapSecUTC = "1961-01-01T00:00:00Z" 

187 dt = DateTime(minLeapSecUTC, DateTime.UTC) 

188 dt.toString(DateTime.UTC) 

189 except Exception: 

190 self.fail("minLeapSecUTC={} failed, but should be OK".format(minLeapSecUTC)) 

191 with self.assertRaises(pexExcept.DomainError): 

192 DateTime("1960-01-01T23:59:59Z", DateTime.UTC) # just before leap second table starts 

193 

194 # earliest allowed date for TAI and TT is year = 1902 

195 for timeSys in (DateTime.TAI, DateTime.TT): 

196 try: 

197 earliestDate = "1902-01-01T00:00:00" 

198 dt = DateTime(earliestDate, timeSys) 

199 dt.toString(DateTime.TAI) 

200 dt.toString(DateTime.TT) 

201 except Exception: 

202 self.fail("{} system={} failed, but should be OK".format(earliestDate, timeSys)) 

203 

204 # dates before the leap second table can be created using TAI or TT, 

205 # but not viewed in UTC 

206 earlyDt = DateTime("1960-01-01T00:00:00", DateTime.TAI) 

207 with self.assertRaises(pexExcept.DomainError): 

208 earlyDt.toString(DateTime.UTC) 

209 

210 with self.assertRaises(pexExcept.DomainError): 

211 DateTime("1901-12-12T23:59:59Z", DateTime.TAI) # too early 

212 with self.assertRaises(pexExcept.DomainError): 

213 DateTime("1700-01-01T00:00:00Z", DateTime.TAI) # way too early 

214 with self.assertRaises(pexExcept.DomainError): 

215 DateTime("2262-01-01T00:00:00Z", DateTime.TAI) # too late 

216 with self.assertRaises(pexExcept.DomainError): 

217 DateTime("3200-01-01T00:00:00Z", DateTime.TAI) # way too late 

218 

219 def testWraparound(self): 

220 """Test that a date later than 2038-01-19, 03:14:07 does not wrap 

221 around. 

222 

223 This will fail on old versions of unix, and indicates that DateTime 

224 is not safe. 

225 """ 

226 dateStr = "2040-01-01T00:00:00.000000000" 

227 self.assertEqual(str(DateTime(dateStr, DateTime.TAI)), "DateTime(\"{}\", TAI)".format(dateStr)) 

228 

229 def testDM7622(self): 

230 """Test DM-7622: date with unix time = -1 seconds must be usable 

231 

232 Note that the call in question parses the ISO string without paying 

233 attention to the scale (it applies the scale later), 

234 so the same ISO string is wanted in all cases 

235 (except with a trailing Z for UTC, and without for TAI and TT) 

236 """ 

237 negOneSecIso = "1969-12-31T23:59:59.000000000" 

238 for scale in self.timeScales: 

239 dateStr = negOneSecIso + ("Z" if scale == DateTime.UTC else "") 

240 try: 

241 dt = DateTime(dateStr, scale) 

242 except Exception: 

243 self.fail("Date {} in scale {} unusable".format(dateStr, scale)) 

244 self.assertEqual(dt.nsecs(scale), int(-1e9)) 

245 

246 def testStr(self): 

247 timeStr1 = "2004-03-01T12:39:45.1" 

248 fullTimeStr1 = "2004-03-01T12:39:45.100000000" 

249 dt1 = DateTime(timeStr1, DateTime.TAI) 

250 self.assertEqual(str(dt1), "DateTime(\"{}\", TAI)".format(fullTimeStr1)) 

251 self.assertEqual(repr(dt1), "DateTime(\"{}\", TAI)".format(fullTimeStr1)) 

252 

253 timeStr2 = "2004-03-01T12:39:45.000000001" 

254 dt2 = DateTime(timeStr2, DateTime.TAI) 

255 self.assertEqual(str(dt2), "DateTime(\"{}\", TAI)".format(timeStr2)) 

256 self.assertEqual(repr(dt2), "DateTime(\"{}\", TAI)".format(timeStr2)) 

257 

258 def testNsecsTT(self): 

259 ts = DateTime(1192755538184000000, DateTime.TT) 

260 self.assertEqual(ts.nsecs(DateTime.UTC), 1192755473000000000) 

261 self.assertEqual(ts.nsecs(DateTime.TAI), 1192755506000000000) 

262 self.assertEqual(ts.nsecs(), 1192755506000000000) 

263 self.assertAlmostEqual(ts.get(DateTime.MJD, DateTime.UTC), 54392.040196759262) 

264 self.assertTrue(ts.isValid()) 

265 

266 def testFracSecs(self): 

267 ts = DateTime("2004-03-01T12:39:45.1Z", DateTime.UTC) 

268 self.assertEqual(ts.toString(ts.UTC), '2004-03-01T12:39:45.100000000Z') 

269 ts = DateTime("2004-03-01T12:39:45.01Z", DateTime.UTC) 

270 self.assertEqual(ts.toString(ts.UTC), '2004-03-01T12:39:45.010000000Z') 

271 ts = DateTime("2004-03-01T12:39:45.000000001Z", DateTime.UTC) # nanosecond 

272 self.assertEqual(ts.toString(ts.UTC), '2004-03-01T12:39:45.000000001Z') 

273 ts = DateTime("2004-03-01T12:39:45.0000000001Z", DateTime.UTC) # too small 

274 self.assertEqual(ts.toString(ts.UTC), '2004-03-01T12:39:45.000000000Z') 

275 

276 def testInvalid(self): 

277 ts = DateTime() 

278 self.assertFalse(ts.isValid()) 

279 for scale in self.timeScales: 

280 self.assertEqual(ts.nsecs(scale), DateTime.invalid_nsecs) 

281 for system in self.dateSystems: 

282 with self.assertRaises(RuntimeError): 

283 ts.get(system, scale) 

284 with self.assertRaises(RuntimeError): 

285 ts.gmtime(scale) 

286 with self.assertRaises(RuntimeError): 

287 ts.timespec(scale) 

288 with self.assertRaises(RuntimeError): 

289 ts.timeval(scale) 

290 with self.assertRaises(RuntimeError): 

291 ts.toString(scale) 

292 self.assertEqual(repr(ts), "DateTime()") 

293 

294 def testNegative(self): 

295 ts = DateTime("1969-03-01T00:00:32Z", DateTime.UTC) 

296 self.assertEqual(ts.toString(ts.UTC), '1969-03-01T00:00:32.000000000Z') 

297 ts = DateTime("1969-01-01T00:00:00Z", DateTime.UTC) 

298 self.assertEqual(ts.toString(ts.UTC), '1969-01-01T00:00:00.000000000Z') 

299 ts = DateTime("1969-01-01T00:00:40Z", DateTime.UTC) 

300 self.assertEqual(ts.toString(ts.UTC), '1969-01-01T00:00:40.000000000Z') 

301 ts = DateTime("1969-01-01T00:00:38Z", DateTime.UTC) 

302 self.assertEqual(ts.toString(ts.UTC), '1969-01-01T00:00:38.000000000Z') 

303 ts = DateTime("1969-03-01T12:39:45Z", DateTime.UTC) 

304 self.assertEqual(ts.toString(ts.UTC), '1969-03-01T12:39:45.000000000Z') 

305 ts = DateTime("1969-03-01T12:39:45.000000001Z", DateTime.UTC) 

306 self.assertEqual(ts.toString(ts.UTC), '1969-03-01T12:39:45.000000001Z') 

307 self.assertTrue(ts.isValid()) 

308 

309 # Note slight inaccuracy in UTC-TAI-UTC round-trip 

310 ts = DateTime("1969-03-01T12:39:45.12345Z", DateTime.UTC) 

311 self.assertEqual(ts.toString(ts.UTC), '1969-03-01T12:39:45.123449996Z') 

312 ts = DateTime("1969-03-01T12:39:45.123456Z", DateTime.UTC) 

313 self.assertEqual(ts.toString(ts.UTC), '1969-03-01T12:39:45.123455996Z') 

314 

315 ts = DateTime(-1, DateTime.TAI) 

316 self.assertEqual(ts.toString(ts.UTC), '1969-12-31T23:59:51.999918239Z') 

317 ts = DateTime(0, DateTime.TAI) 

318 self.assertEqual(ts.toString(ts.UTC), '1969-12-31T23:59:51.999918240Z') 

319 ts = DateTime(1, DateTime.TAI) 

320 self.assertEqual(ts.toString(ts.UTC), '1969-12-31T23:59:51.999918241Z') 

321 

322 ts = DateTime(-1, DateTime.UTC) 

323 self.assertEqual(ts.toString(ts.UTC), '1969-12-31T23:59:59.999999999Z') 

324 ts = DateTime(0, DateTime.UTC) 

325 self.assertEqual(ts.toString(ts.UTC), '1970-01-01T00:00:00.000000000Z') 

326 ts = DateTime(1, DateTime.UTC) 

327 self.assertEqual(ts.toString(ts.UTC), '1970-01-01T00:00:00.000000001Z') 

328 

329 def testConvert(self): 

330 year = 2012 

331 month = 7 

332 day = 19 

333 hour = 18 

334 minute = 29 

335 second = 33 

336 

337 ts = DateTime(year, month, day, hour, minute, second, DateTime.UTC) 

338 dt = ts.toPython(DateTime.UTC) 

339 

340 self.assertEqual(dt.year, year) 

341 self.assertEqual(dt.month, month) 

342 self.assertEqual(dt.day, day) 

343 self.assertEqual(dt.hour, hour) 

344 self.assertEqual(dt.minute, minute) 

345 self.assertEqual(dt.second, second) 

346 

347 def testPickle(self): 

348 ts = DateTime(int(1192755473000000000), DateTime.UTC) 

349 nts = pickle.loads(pickle.dumps(ts)) 

350 self.assertEqual(nts.nsecs(DateTime.UTC), int(1192755473000000000)) 

351 

352 

353class TimeZoneBaseTestCase(DateTimeTestCase): 

354 timezone = "" 

355 

356 def setUp(self): 

357 DateTimeTestCase.setUp(self) 

358 self.tz = os.environ.setdefault('TZ', "") 

359 os.environ['TZ'] = self.timezone 

360 

361 def tearDown(self): 

362 if self.tz == "": 

363 del os.environ['TZ'] 

364 else: 

365 os.environ['TZ'] = self.tz 

366 

367 

368class BritishTimeTestCase(TimeZoneBaseTestCase): 

369 timezone = "Europe/London" 

370 

371 

372class BritishTime2TestCase(TimeZoneBaseTestCase): 

373 timezone = "GMT0BST" 

374 

375 

376class PacificTimeTestCase(TimeZoneBaseTestCase): 

377 timezone = "PST8PDT" 

378 

379 

380if __name__ == '__main__': 380 ↛ 381line 380 didn't jump to line 381, because the condition on line 380 was never true

381 unittest.main()