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()