2
2
"""
3
3
Tests for Timestamp timezone-related methods
4
4
"""
5
+ from datetime import date , timedelta
5
6
7
+ from distutils .version import LooseVersion
6
8
import pytest
9
+ import pytz
7
10
from pytz .exceptions import AmbiguousTimeError , NonExistentTimeError
11
+ import dateutil
12
+ from dateutil .tz import gettz , tzoffset
8
13
9
14
import pandas .util .testing as tm
15
+ import pandas .util ._test_decorators as td
16
+
10
17
from pandas import Timestamp , NaT
11
18
12
19
13
20
class TestTimestampTZOperations (object ):
14
21
# --------------------------------------------------------------
15
22
# Timestamp.tz_localize
16
23
24
+ def test_tz_localize_ambiguous_bool (self ):
25
+ # make sure that we are correctly accepting bool values as ambiguous
26
+ # GH#14402
27
+ ts = Timestamp ('2015-11-01 01:00:03' )
28
+ expected0 = Timestamp ('2015-11-01 01:00:03-0500' , tz = 'US/Central' )
29
+ expected1 = Timestamp ('2015-11-01 01:00:03-0600' , tz = 'US/Central' )
30
+
31
+ with pytest .raises (pytz .AmbiguousTimeError ):
32
+ ts .tz_localize ('US/Central' )
33
+
34
+ result = ts .tz_localize ('US/Central' , ambiguous = True )
35
+ assert result == expected0
36
+
37
+ result = ts .tz_localize ('US/Central' , ambiguous = False )
38
+ assert result == expected1
39
+
17
40
def test_tz_localize_ambiguous (self ):
18
41
ts = Timestamp ('2014-11-02 01:00' )
19
42
ts_dst = ts .tz_localize ('US/Eastern' , ambiguous = True )
@@ -70,6 +93,55 @@ def test_tz_localize_roundtrip(self, stamp, tz):
70
93
assert reset == ts
71
94
assert reset .tzinfo is None
72
95
96
+ def test_tz_localize_ambiguous_compat (self ):
97
+ # validate that pytz and dateutil are compat for dst
98
+ # when the transition happens
99
+ naive = Timestamp ('2013-10-27 01:00:00' )
100
+
101
+ pytz_zone = 'Europe/London'
102
+ dateutil_zone = 'dateutil/Europe/London'
103
+ result_pytz = naive .tz_localize (pytz_zone , ambiguous = 0 )
104
+ result_dateutil = naive .tz_localize (dateutil_zone , ambiguous = 0 )
105
+ assert result_pytz .value == result_dateutil .value
106
+ assert result_pytz .value == 1382835600000000000
107
+
108
+ if LooseVersion (dateutil .__version__ ) < LooseVersion ('2.6.0' ):
109
+ # dateutil 2.6 buggy w.r.t. ambiguous=0
110
+ # see gh-14621
111
+ # see https://github.com/dateutil/dateutil/issues/321
112
+ assert (result_pytz .to_pydatetime ().tzname () ==
113
+ result_dateutil .to_pydatetime ().tzname ())
114
+ assert str (result_pytz ) == str (result_dateutil )
115
+ elif LooseVersion (dateutil .__version__ ) > LooseVersion ('2.6.0' ):
116
+ # fixed ambiguous behavior
117
+ assert result_pytz .to_pydatetime ().tzname () == 'GMT'
118
+ assert result_dateutil .to_pydatetime ().tzname () == 'BST'
119
+ assert str (result_pytz ) != str (result_dateutil )
120
+
121
+ # 1 hour difference
122
+ result_pytz = naive .tz_localize (pytz_zone , ambiguous = 1 )
123
+ result_dateutil = naive .tz_localize (dateutil_zone , ambiguous = 1 )
124
+ assert result_pytz .value == result_dateutil .value
125
+ assert result_pytz .value == 1382832000000000000
126
+
127
+ # dateutil < 2.6 is buggy w.r.t. ambiguous timezones
128
+ if LooseVersion (dateutil .__version__ ) > LooseVersion ('2.5.3' ):
129
+ # see gh-14621
130
+ assert str (result_pytz ) == str (result_dateutil )
131
+ assert (result_pytz .to_pydatetime ().tzname () ==
132
+ result_dateutil .to_pydatetime ().tzname ())
133
+
134
+ @pytest .mark .parametrize ('tz' , [pytz .timezone ('US/Eastern' ),
135
+ gettz ('US/Eastern' ),
136
+ 'US/Eastern' , 'dateutil/US/Eastern' ])
137
+ def test_timestamp_tz_localize (self , tz ):
138
+ stamp = Timestamp ('3/11/2012 04:00' )
139
+
140
+ result = stamp .tz_localize (tz )
141
+ expected = Timestamp ('3/11/2012 04:00' , tz = tz )
142
+ assert result .hour == expected .hour
143
+ assert result == expected
144
+
73
145
# ------------------------------------------------------------------
74
146
# Timestamp.tz_convert
75
147
@@ -85,3 +157,120 @@ def test_tz_convert_roundtrip(self, stamp, tz):
85
157
assert reset == Timestamp (stamp )
86
158
assert reset .tzinfo is None
87
159
assert reset == converted .tz_convert ('UTC' ).tz_localize (None )
160
+
161
+ @pytest .mark .parametrize ('tzstr' , ['US/Eastern' , 'dateutil/US/Eastern' ])
162
+ def test_astimezone (self , tzstr ):
163
+ # astimezone is an alias for tz_convert, so keep it with
164
+ # the tz_convert tests
165
+ utcdate = Timestamp ('3/11/2012 22:00' , tz = 'UTC' )
166
+ expected = utcdate .tz_convert (tzstr )
167
+ result = utcdate .astimezone (tzstr )
168
+ assert expected == result
169
+ assert isinstance (result , Timestamp )
170
+
171
+ @td .skip_if_windows
172
+ def test_tz_convert_utc_with_system_utc (self ):
173
+ from pandas ._libs .tslibs .timezones import maybe_get_tz
174
+
175
+ # from system utc to real utc
176
+ ts = Timestamp ('2001-01-05 11:56' , tz = maybe_get_tz ('dateutil/UTC' ))
177
+ # check that the time hasn't changed.
178
+ assert ts == ts .tz_convert (dateutil .tz .tzutc ())
179
+
180
+ # from system utc to real utc
181
+ ts = Timestamp ('2001-01-05 11:56' , tz = maybe_get_tz ('dateutil/UTC' ))
182
+ # check that the time hasn't changed.
183
+ assert ts == ts .tz_convert (dateutil .tz .tzutc ())
184
+
185
+ # ------------------------------------------------------------------
186
+ # Timestamp.__init__ with tz str or tzinfo
187
+
188
+ def test_timestamp_constructor_tz_utc (self ):
189
+ utc_stamp = Timestamp ('3/11/2012 05:00' , tz = 'utc' )
190
+ assert utc_stamp .tzinfo is pytz .utc
191
+ assert utc_stamp .hour == 5
192
+
193
+ utc_stamp = Timestamp ('3/11/2012 05:00' ).tz_localize ('utc' )
194
+ assert utc_stamp .hour == 5
195
+
196
+ def test_timestamp_to_datetime_tzoffset (self ):
197
+ tzinfo = tzoffset (None , 7200 )
198
+ expected = Timestamp ('3/11/2012 04:00' , tz = tzinfo )
199
+ result = Timestamp (expected .to_pydatetime ())
200
+ assert expected == result
201
+
202
+ def test_timestamp_constructor_near_dst_boundary (self ):
203
+ # GH#11481 & GH#15777
204
+ # Naive string timestamps were being localized incorrectly
205
+ # with tz_convert_single instead of tz_localize_to_utc
206
+
207
+ for tz in ['Europe/Brussels' , 'Europe/Prague' ]:
208
+ result = Timestamp ('2015-10-25 01:00' , tz = tz )
209
+ expected = Timestamp ('2015-10-25 01:00' ).tz_localize (tz )
210
+ assert result == expected
211
+
212
+ with pytest .raises (pytz .AmbiguousTimeError ):
213
+ Timestamp ('2015-10-25 02:00' , tz = tz )
214
+
215
+ result = Timestamp ('2017-03-26 01:00' , tz = 'Europe/Paris' )
216
+ expected = Timestamp ('2017-03-26 01:00' ).tz_localize ('Europe/Paris' )
217
+ assert result == expected
218
+
219
+ with pytest .raises (pytz .NonExistentTimeError ):
220
+ Timestamp ('2017-03-26 02:00' , tz = 'Europe/Paris' )
221
+
222
+ # GH#11708
223
+ naive = Timestamp ('2015-11-18 10:00:00' )
224
+ result = naive .tz_localize ('UTC' ).tz_convert ('Asia/Kolkata' )
225
+ expected = Timestamp ('2015-11-18 15:30:00+0530' , tz = 'Asia/Kolkata' )
226
+ assert result == expected
227
+
228
+ # GH#15823
229
+ result = Timestamp ('2017-03-26 00:00' , tz = 'Europe/Paris' )
230
+ expected = Timestamp ('2017-03-26 00:00:00+0100' , tz = 'Europe/Paris' )
231
+ assert result == expected
232
+
233
+ result = Timestamp ('2017-03-26 01:00' , tz = 'Europe/Paris' )
234
+ expected = Timestamp ('2017-03-26 01:00:00+0100' , tz = 'Europe/Paris' )
235
+ assert result == expected
236
+
237
+ with pytest .raises (pytz .NonExistentTimeError ):
238
+ Timestamp ('2017-03-26 02:00' , tz = 'Europe/Paris' )
239
+
240
+ result = Timestamp ('2017-03-26 02:00:00+0100' , tz = 'Europe/Paris' )
241
+ naive = Timestamp (result .value )
242
+ expected = naive .tz_localize ('UTC' ).tz_convert ('Europe/Paris' )
243
+ assert result == expected
244
+
245
+ result = Timestamp ('2017-03-26 03:00' , tz = 'Europe/Paris' )
246
+ expected = Timestamp ('2017-03-26 03:00:00+0200' , tz = 'Europe/Paris' )
247
+ assert result == expected
248
+
249
+ @pytest .mark .parametrize ('tz' , [pytz .timezone ('US/Eastern' ),
250
+ gettz ('US/Eastern' ),
251
+ 'US/Eastern' , 'dateutil/US/Eastern' ])
252
+ def test_timestamp_constructed_by_date_and_tz (self , tz ):
253
+ # GH#2993, Timestamp cannot be constructed by datetime.date
254
+ # and tz correctly
255
+
256
+ result = Timestamp (date (2012 , 3 , 11 ), tz = tz )
257
+
258
+ expected = Timestamp ('3/11/2012' , tz = tz )
259
+ assert result .hour == expected .hour
260
+ assert result == expected
261
+
262
+ @pytest .mark .parametrize ('tz' , [pytz .timezone ('US/Eastern' ),
263
+ gettz ('US/Eastern' ),
264
+ 'US/Eastern' , 'dateutil/US/Eastern' ])
265
+ def test_timestamp_add_timedelta_push_over_dst_boundary (self , tz ):
266
+ # GH#1389
267
+
268
+ # 4 hours before DST transition
269
+ stamp = Timestamp ('3/10/2012 22:00' , tz = tz )
270
+
271
+ result = stamp + timedelta (hours = 6 )
272
+
273
+ # spring forward, + "7" hours
274
+ expected = Timestamp ('3/11/2012 05:00' , tz = tz )
275
+
276
+ assert result == expected
0 commit comments