@@ -17,6 +17,19 @@ correspond; for example, a conversion that consistently added hour
17when printed to a string and subtracted an hour when parsed from string
17when printed to a string and subtracted an hour when parsed from string
18would still pass these tests.
18would still pass these tests.
21+Right now, we are checking that 1400+ timestamps in the range of 1860 to
22+2060 round trip from postgresql to haskell and back in 5 different timezones.
23+In addition to UTC, the four timezones were selected so that 2 have a positive
24+offset, and 2 have a negative offset, and that 2 have an offset of a
25+whole number of hours, while the other two do not.
27+It may be worth adding a few more timezones to ensure better test coverage.
29+We are checking a handful of selected timestamps to ensure we hit
30+various corner-cases in the code, in addition to 1400 timestamps randomly
31+generated with granularity of seconds down to microseconds in powers of ten.
22module Time (testTime) where
35module Time (testTime) where
@@ -35,13 +48,13 @@ testTime env@TestEnv{..} = TestCase $ do
35 initializeTable env
48 initializeTable env
36 execute_ conn "SET timezone TO 'UTC'"
49 execute_ conn "SET timezone TO 'UTC'"
37 checkRoundTrips env
50 checkRoundTrips env
38− execute_ conn "SET timezone TO 'America/Chicago'"
51+ execute_ conn "SET timezone TO 'America/Chicago'" -- -5:00
39 checkRoundTrips env
52 checkRoundTrips env
40− execute_ conn "SET timezone TO 'Asia/Tokyo'"
53+ execute_ conn "SET timezone TO 'Asia/Tokyo'" -- +9:00
41 checkRoundTrips env
54 checkRoundTrips env
42− execute_ conn "SET timezone TO 'Asia/Kathmandu'"
55+ execute_ conn "SET timezone TO 'Asia/Kathmandu'" -- +5:45
43 checkRoundTrips env
56 checkRoundTrips env
44− execute_ conn "SET timezone TO 'America/St_Johns'"
57+ execute_ conn "SET timezone TO 'America/St_Johns'" -- -3:30
45 checkRoundTrips env
58 checkRoundTrips env
47initializeTable :: TestEnv -> IO ()
60initializeTable :: TestEnv -> IO ()
@@ -49,10 +62,37 @@ initializeTable TestEnv{..} = withTransaction conn $ do
49 execute_ conn
62 execute_ conn
50 [sql| CREATE TEMPORARY TABLE testtime
63 [sql| CREATE TEMPORARY TABLE testtime
51 ( x serial, y timestamptz, PRIMARY KEY(x) ) |]
64 ( x serial, y timestamptz, PRIMARY KEY(x) ) |]
66+ let test :: ByteString -> IO () = \x -> do
68+ INSERT INTO testtime (y) VALUES (?)
72+ test "1883-11-18 11:59:59-05:50:36"
73+ test "1883-11-18 12:09:23-05:50:36"
74+ test "1883-11-18 12:00:00-06"
76+ test "1887-12-31 23:59:59+09:18:59"
77+ test "1888-01-01 00:18:58+09:18:59"
78+ test "1888-01-01 00:00:00+09"
80+ test "1919-12-31 23:59:59+05:41:16"
81+ test "1919-12-31 23:48:44+05:30"
82+ test "1985-12-31 23:59:59+05:30"
83+ test "1986-01-01 00:15:00+05:45"
85+ test "1935-03-29 23:59:59-03:30:52"
86+ test "1935-03-30 00:00:52-03:30"
88+ -- While the above special cases are probably a decent start, there
89+ -- are probably more that are well worth adding to ensure better
52 let pop :: ByteString -> Double -> IO () = \x y ->
92 let pop :: ByteString -> Double -> IO () = \x y ->
53 replicateM_ numTests $ execute conn
93 replicateM_ numTests $ execute conn
54 [sql| INSERT INTO testtime (y) VALUES
94 [sql| INSERT INTO testtime (y) VALUES
55− ('1936-01-01 00:00:00+00'::timestamptz
95+ ('1860-01-01 00:00:00+00'::timestamptz
56 + ?::interval * ROUND(RANDOM() * ?)) |] (x,y)
96 + ?::interval * ROUND(RANDOM() * ?)) |] (x,y)
57 pop "1 microsecond" 6.3113904e15
97 pop "1 microsecond" 6.3113904e15
58 pop "10 microseconds" 6.3113904e14
98 pop "10 microseconds" 6.3113904e14