github.com/apache/beam/sdks/v2@v2.48.2/python/apache_beam/utils/timestamp_test.py (about) 1 # 2 # Licensed to the Apache Software Foundation (ASF) under one or more 3 # contributor license agreements. See the NOTICE file distributed with 4 # this work for additional information regarding copyright ownership. 5 # The ASF licenses this file to You under the Apache License, Version 2.0 6 # (the "License"); you may not use this file except in compliance with 7 # the License. You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 # 17 18 """Unit tests for time utilities.""" 19 20 # pytype: skip-file 21 22 import datetime 23 import unittest 24 25 import pytz 26 from google.protobuf import duration_pb2 27 from google.protobuf import timestamp_pb2 28 29 from apache_beam.utils.timestamp import Duration 30 from apache_beam.utils.timestamp import Timestamp 31 32 33 class TimestampTest(unittest.TestCase): 34 def test_of(self): 35 interval = Timestamp(123) 36 self.assertEqual(id(interval), id(Timestamp.of(interval))) 37 self.assertEqual(interval, Timestamp.of(123.0)) 38 with self.assertRaises(TypeError): 39 Timestamp.of(Duration(10)) 40 41 def test_precision(self): 42 self.assertEqual(Timestamp(10000000) % 0.1, 0) 43 self.assertEqual(Timestamp(10000000) % 0.05, 0) 44 self.assertEqual(Timestamp(10000000) % 0.000005, 0) 45 self.assertEqual(Timestamp(10000000) % Duration(0.1), 0) 46 self.assertEqual(Timestamp(10000000) % Duration(0.05), 0) 47 self.assertEqual(Timestamp(10000000) % Duration(0.000005), 0) 48 49 def test_utc_timestamp(self): 50 self.assertEqual(Timestamp(10000000).to_rfc3339(), '1970-04-26T17:46:40Z') 51 self.assertEqual( 52 Timestamp(10000000.000001).to_rfc3339(), '1970-04-26T17:46:40.000001Z') 53 self.assertEqual( 54 Timestamp(1458343379.123456).to_rfc3339(), 55 '2016-03-18T23:22:59.123456Z') 56 57 def test_from_rfc3339(self): 58 test_cases = [ 59 (10000000, '1970-04-26T17:46:40Z'), 60 (10000000.000001, '1970-04-26T17:46:40.000001Z'), 61 (1458343379.123456, '2016-03-18T23:22:59.123456Z'), 62 ] 63 for seconds_float, rfc3339_str in test_cases: 64 self.assertEqual( 65 Timestamp(seconds_float), Timestamp.from_rfc3339(rfc3339_str)) 66 self.assertEqual( 67 rfc3339_str, Timestamp.from_rfc3339(rfc3339_str).to_rfc3339()) 68 69 def test_from_rfc3339_with_timezone(self): 70 test_cases = [ 71 (1458328979.123456, '2016-03-18T23:22:59.123456+04:00'), 72 (1458357779.123456, '2016-03-18T23:22:59.123456-04:00'), 73 ] 74 for seconds_float, rfc3339_str in test_cases: 75 self.assertEqual( 76 Timestamp(seconds_float), Timestamp.from_rfc3339(rfc3339_str)) 77 78 def test_from_rfc3339_failure(self): 79 with self.assertRaisesRegex(ValueError, 'parse'): 80 Timestamp.from_rfc3339('not rfc3339') 81 with self.assertRaisesRegex(ValueError, 'parse'): 82 Timestamp.from_rfc3339('2016-03-18T23:22:59.123456Z unparseable') 83 84 def test_from_utc_datetime(self): 85 self.assertEqual( 86 Timestamp.from_utc_datetime( 87 datetime.datetime(1970, 1, 1, tzinfo=pytz.utc)), 88 Timestamp(0)) 89 with self.assertRaisesRegex(ValueError, r'UTC'): 90 Timestamp.from_utc_datetime( 91 datetime.datetime(1970, 1, 1, tzinfo=pytz.timezone('US/Eastern'))) 92 with self.assertRaisesRegex(ValueError, r'dt has no timezone info'): 93 Timestamp.from_utc_datetime(datetime.datetime(1970, 1, 1, tzinfo=None)) 94 95 def test_arithmetic(self): 96 # Supported operations. 97 self.assertEqual(Timestamp(123) + 456, 579) 98 self.assertEqual(Timestamp(123) + Duration(456), 579) 99 self.assertEqual(456 + Timestamp(123), 579) 100 self.assertEqual(Duration(456) + Timestamp(123), 579) 101 self.assertEqual(Timestamp(123) - 456, -333) 102 self.assertEqual(Timestamp(123) - Duration(456), -333) 103 self.assertEqual(Timestamp(1230) % 456, 318) 104 self.assertEqual(Timestamp(1230) % Duration(456), 318) 105 self.assertEqual(Timestamp(123) - Timestamp(100), 23) 106 107 # Check that direct comparison of Timestamp and Duration is allowed. 108 self.assertTrue(Duration(123) == Timestamp(123)) 109 self.assertTrue(Timestamp(123) == Duration(123)) 110 self.assertFalse(Duration(123) == Timestamp(1230)) 111 self.assertFalse(Timestamp(123) == Duration(1230)) 112 113 # Check return types. 114 self.assertEqual((Timestamp(123) + 456).__class__, Timestamp) 115 self.assertEqual((Timestamp(123) + Duration(456)).__class__, Timestamp) 116 self.assertEqual((456 + Timestamp(123)).__class__, Timestamp) 117 self.assertEqual((Duration(456) + Timestamp(123)).__class__, Timestamp) 118 self.assertEqual((Timestamp(123) - 456).__class__, Timestamp) 119 self.assertEqual((Timestamp(123) - Duration(456)).__class__, Timestamp) 120 self.assertEqual((Timestamp(1230) % 456).__class__, Duration) 121 self.assertEqual((Timestamp(1230) % Duration(456)).__class__, Duration) 122 self.assertEqual((Timestamp(123) - Timestamp(100)).__class__, Duration) 123 124 # Unsupported operations. 125 with self.assertRaises(TypeError): 126 self.assertEqual(Timestamp(123) * 456, 56088) 127 with self.assertRaises(TypeError): 128 self.assertEqual(Timestamp(123) * Duration(456), 56088) 129 with self.assertRaises(TypeError): 130 self.assertEqual(456 * Timestamp(123), 56088) 131 with self.assertRaises(TypeError): 132 self.assertEqual(Duration(456) * Timestamp(123), 56088) 133 with self.assertRaises(TypeError): 134 self.assertEqual(456 - Timestamp(123), 333) 135 with self.assertRaises(TypeError): 136 self.assertEqual(Duration(456) - Timestamp(123), 333) 137 with self.assertRaises(TypeError): 138 self.assertEqual(-Timestamp(123), -123) # pylint: disable=invalid-unary-operand-type 139 with self.assertRaises(TypeError): 140 self.assertEqual(-Timestamp(123), -Duration(123)) # pylint: disable=invalid-unary-operand-type 141 with self.assertRaises(TypeError): 142 self.assertEqual(1230 % Timestamp(456), 318) 143 with self.assertRaises(TypeError): 144 self.assertEqual(Duration(1230) % Timestamp(456), 318) 145 146 def test_sort_order(self): 147 self.assertEqual([-63, Timestamp(-3), 2, 9, Timestamp(292.3), 500], 148 sorted([9, 2, Timestamp(-3), Timestamp(292.3), -63, 500])) 149 self.assertEqual([4, 5, Timestamp(6), Timestamp(7), 8, 9], 150 sorted([9, 8, Timestamp(7), Timestamp(6), 5, 4])) 151 152 def test_str(self): 153 self.assertEqual('Timestamp(1.234567)', str(Timestamp(1.234567))) 154 self.assertEqual('Timestamp(-1.234567)', str(Timestamp(-1.234567))) 155 self.assertEqual( 156 'Timestamp(-999999999.900000)', str(Timestamp(-999999999.9))) 157 self.assertEqual('Timestamp(999999999)', str(Timestamp(999999999))) 158 self.assertEqual('Timestamp(-999999999)', str(Timestamp(-999999999))) 159 160 def test_now(self): 161 now = Timestamp.now() 162 self.assertTrue(isinstance(now, Timestamp)) 163 164 def test_from_proto(self): 165 ts_proto = timestamp_pb2.Timestamp(seconds=1234, nanos=56000) 166 actual_ts = Timestamp.from_proto(ts_proto) 167 expected_ts = Timestamp(seconds=1234, micros=56) 168 self.assertEqual(actual_ts, expected_ts) 169 170 def test_from_proto_fails_with_truncation(self): 171 # TODO(https://github.com/apache/beam/issues/19922): Better define 172 # timestamps. 173 with self.assertRaises(ValueError): 174 Timestamp.from_proto(timestamp_pb2.Timestamp(seconds=1234, nanos=56789)) 175 176 def test_to_proto(self): 177 ts = Timestamp(seconds=1234, micros=56) 178 actual_ts_proto = Timestamp.to_proto(ts) 179 expected_ts_proto = timestamp_pb2.Timestamp(seconds=1234, nanos=56000) 180 self.assertEqual(actual_ts_proto, expected_ts_proto) 181 182 def test_equality(self): 183 for min_val in (Timestamp(1), Duration(1), 1, 1.1): 184 for max_val in (Timestamp(123), Duration(123), 123, 123.4): 185 self.assertTrue(min_val < max_val, "%s < %s" % (min_val, max_val)) 186 self.assertTrue(min_val <= max_val, "%s <= %s" % (min_val, max_val)) 187 self.assertTrue(max_val > min_val, "%s > %s" % (max_val, min_val)) 188 self.assertTrue(max_val >= min_val, "%s >= %s" % (max_val, min_val)) 189 190 191 class DurationTest(unittest.TestCase): 192 def test_of(self): 193 interval = Duration(123) 194 self.assertEqual(id(interval), id(Duration.of(interval))) 195 self.assertEqual(interval, Duration.of(123.0)) 196 with self.assertRaises(TypeError): 197 Duration.of(Timestamp(10)) 198 199 def test_precision(self): 200 self.assertEqual(Duration(10000000) % 0.1, 0) 201 self.assertEqual(Duration(10000000) % 0.05, 0) 202 self.assertEqual(Duration(10000000) % 0.000005, 0) 203 204 def test_arithmetic(self): 205 self.assertEqual(Duration(123) + 456, 579) 206 self.assertEqual(456 + Duration(123), 579) 207 self.assertEqual(Duration(123) * 456, 56088) 208 self.assertEqual(456 * Duration(123), 56088) 209 self.assertEqual(Duration(123) - 456, -333) 210 self.assertEqual(456 - Duration(123), 333) 211 self.assertEqual(-Duration(123), -123) 212 213 def test_sort_order(self): 214 self.assertEqual([-63, Duration(-3), 2, 9, Duration(292.3), 500], 215 sorted([9, 2, Duration(-3), Duration(292.3), -63, 500])) 216 self.assertEqual([4, 5, Duration(6), Duration(7), 8, 9], 217 sorted([9, 8, Duration(7), Duration(6), 5, 4])) 218 219 def test_str(self): 220 self.assertEqual('Duration(1.234567)', str(Duration(1.234567))) 221 self.assertEqual('Duration(-1.234567)', str(Duration(-1.234567))) 222 self.assertEqual('Duration(-999999999.900000)', str(Duration(-999999999.9))) 223 self.assertEqual('Duration(999999999)', str(Duration(999999999))) 224 self.assertEqual('Duration(-999999999)', str(Duration(-999999999))) 225 226 def test_from_proto(self): 227 dur_proto = duration_pb2.Duration(seconds=1234, nanos=56000) 228 actual_dur = Duration.from_proto(dur_proto) 229 expected_dur = Duration(seconds=1234, micros=56) 230 self.assertEqual(actual_dur, expected_dur) 231 232 def test_from_proto_fails_with_truncation(self): 233 # TODO(https://github.com/apache/beam/issues/19922): Better define 234 # durations. 235 with self.assertRaises(ValueError): 236 Duration.from_proto(duration_pb2.Duration(seconds=1234, nanos=56789)) 237 238 def test_to_proto(self): 239 dur = Duration(seconds=1234, micros=56) 240 actual_dur_proto = Duration.to_proto(dur) 241 expected_dur_proto = duration_pb2.Duration(seconds=1234, nanos=56000) 242 self.assertEqual(actual_dur_proto, expected_dur_proto) 243 244 245 if __name__ == '__main__': 246 unittest.main()