20
20
import calendar
21
21
import collections .abc
22
22
import datetime
23
+ import warnings
23
24
24
25
from google .protobuf .internal import field_mask
25
26
33
34
_MICROS_PER_SECOND = 1000000
34
35
_SECONDS_PER_DAY = 24 * 3600
35
36
_DURATION_SECONDS_MAX = 315576000000
37
+ _TIMESTAMP_SECONDS_MIN = - 62135596800
38
+ _TIMESTAMP_SECONDS_MAX = 253402300799
36
39
37
40
_EPOCH_DATETIME_NAIVE = datetime .datetime (1970 , 1 , 1 , tzinfo = None )
38
41
_EPOCH_DATETIME_AWARE = _EPOCH_DATETIME_NAIVE .replace (
@@ -85,10 +88,10 @@ def ToJsonString(self):
85
88
and uses 3, 6 or 9 fractional digits as required to represent the
86
89
exact time. Example of the return format: '1972-01-01T10:00:20.021Z'
87
90
"""
88
- nanos = self .nanos % _NANOS_PER_SECOND
89
- total_sec = self .seconds + ( self . nanos - nanos ) // _NANOS_PER_SECOND
90
- seconds = total_sec % _SECONDS_PER_DAY
91
- days = (total_sec - seconds ) // _SECONDS_PER_DAY
91
+ _CheckTimestampValid ( self . seconds , self .nanos )
92
+ nanos = self .nanos
93
+ seconds = self . seconds % _SECONDS_PER_DAY
94
+ days = (self . seconds - seconds ) // _SECONDS_PER_DAY
92
95
dt = datetime .datetime (1970 , 1 , 1 ) + datetime .timedelta (days , seconds )
93
96
94
97
result = dt .isoformat ()
@@ -166,6 +169,7 @@ def FromJsonString(self, value):
166
169
else :
167
170
seconds += (int (timezone [1 :pos ])* 60 + int (timezone [pos + 1 :]))* 60
168
171
# Set seconds and nanos
172
+ _CheckTimestampValid (seconds , nanos )
169
173
self .seconds = int (seconds )
170
174
self .nanos = int (nanos )
171
175
@@ -175,39 +179,53 @@ def GetCurrentTime(self):
175
179
176
180
def ToNanoseconds (self ):
177
181
"""Converts Timestamp to nanoseconds since epoch."""
182
+ _CheckTimestampValid (self .seconds , self .nanos )
178
183
return self .seconds * _NANOS_PER_SECOND + self .nanos
179
184
180
185
def ToMicroseconds (self ):
181
186
"""Converts Timestamp to microseconds since epoch."""
187
+ _CheckTimestampValid (self .seconds , self .nanos )
182
188
return (self .seconds * _MICROS_PER_SECOND +
183
189
self .nanos // _NANOS_PER_MICROSECOND )
184
190
185
191
def ToMilliseconds (self ):
186
192
"""Converts Timestamp to milliseconds since epoch."""
193
+ _CheckTimestampValid (self .seconds , self .nanos )
187
194
return (self .seconds * _MILLIS_PER_SECOND +
188
195
self .nanos // _NANOS_PER_MILLISECOND )
189
196
190
197
def ToSeconds (self ):
191
198
"""Converts Timestamp to seconds since epoch."""
199
+ _CheckTimestampValid (self .seconds , self .nanos )
192
200
return self .seconds
193
201
194
202
def FromNanoseconds (self , nanos ):
195
203
"""Converts nanoseconds since epoch to Timestamp."""
196
- self .seconds = nanos // _NANOS_PER_SECOND
197
- self .nanos = nanos % _NANOS_PER_SECOND
204
+ seconds = nanos // _NANOS_PER_SECOND
205
+ nanos = nanos % _NANOS_PER_SECOND
206
+ _CheckTimestampValid (seconds , nanos )
207
+ self .seconds = seconds
208
+ self .nanos = nanos
198
209
199
210
def FromMicroseconds (self , micros ):
200
211
"""Converts microseconds since epoch to Timestamp."""
201
- self .seconds = micros // _MICROS_PER_SECOND
202
- self .nanos = (micros % _MICROS_PER_SECOND ) * _NANOS_PER_MICROSECOND
212
+ seconds = micros // _MICROS_PER_SECOND
213
+ nanos = (micros % _MICROS_PER_SECOND ) * _NANOS_PER_MICROSECOND
214
+ _CheckTimestampValid (seconds , nanos )
215
+ self .seconds = seconds
216
+ self .nanos = nanos
203
217
204
218
def FromMilliseconds (self , millis ):
205
219
"""Converts milliseconds since epoch to Timestamp."""
206
- self .seconds = millis // _MILLIS_PER_SECOND
207
- self .nanos = (millis % _MILLIS_PER_SECOND ) * _NANOS_PER_MILLISECOND
220
+ seconds = millis // _MILLIS_PER_SECOND
221
+ nanos = (millis % _MILLIS_PER_SECOND ) * _NANOS_PER_MILLISECOND
222
+ _CheckTimestampValid (seconds , nanos )
223
+ self .seconds = seconds
224
+ self .nanos = nanos
208
225
209
226
def FromSeconds (self , seconds ):
210
227
"""Converts seconds since epoch to Timestamp."""
228
+ _CheckTimestampValid (seconds , 0 )
211
229
self .seconds = seconds
212
230
self .nanos = 0
213
231
@@ -229,6 +247,7 @@ def ToDatetime(self, tzinfo=None):
229
247
# https://github.com/python/cpython/issues/109849) or full range (on some
230
248
# platforms, see https://github.com/python/cpython/issues/110042) of
231
249
# datetime.
250
+ _CheckTimestampValid (self .seconds , self .nanos )
232
251
delta = datetime .timedelta (
233
252
seconds = self .seconds ,
234
253
microseconds = _RoundTowardZero (self .nanos , _NANOS_PER_MICROSECOND ),
@@ -252,8 +271,22 @@ def FromDatetime(self, dt):
252
271
# manipulated into a long value of seconds. During the conversion from
253
272
# struct_time to long, the source date in UTC, and so it follows that the
254
273
# correct transformation is calendar.timegm()
255
- self .seconds = calendar .timegm (dt .utctimetuple ())
256
- self .nanos = dt .microsecond * _NANOS_PER_MICROSECOND
274
+ seconds = calendar .timegm (dt .utctimetuple ())
275
+ nanos = dt .microsecond * _NANOS_PER_MICROSECOND
276
+ _CheckTimestampValid (seconds , nanos )
277
+ self .seconds = seconds
278
+ self .nanos = nanos
279
+
280
+
281
+ def _CheckTimestampValid (seconds , nanos ):
282
+ if seconds < _TIMESTAMP_SECONDS_MIN or seconds > _TIMESTAMP_SECONDS_MAX :
283
+ raise ValueError (
284
+ 'Timestamp is not valid: Seconds {0} must be in range '
285
+ '[-62135596800, 253402300799].' .format (seconds ))
286
+ if nanos < 0 or nanos >= _NANOS_PER_SECOND :
287
+ raise ValueError (
288
+ 'Timestamp is not valid: Nanos {} must be in a range '
289
+ '[0, 999999].' .format (nanos ))
257
290
258
291
259
292
class Duration (object ):
0 commit comments