Skip to content

Commit 1a12ead

Browse files
ravinimmijreback
authored andcommitted
BUG: is_normalized returned False for local tz
closes #13459 Author: Ravi Kumar Nimmi <[email protected]> Closes #13484 from ravinimmi/bugfix and squashes the following commits: 4d48367 [Ravi Kumar Nimmi] BUG: is_normalized returned False for local tz
1 parent 0f351dc commit 1a12ead

File tree

5 files changed

+76
-34
lines changed

5 files changed

+76
-34
lines changed

doc/source/whatsnew/v0.18.2.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,7 @@ Bug Fixes
485485

486486
- Bug in various index types, which did not propagate the name of passed index (:issue:`12309`)
487487
- Bug in ``DatetimeIndex``, which did not honour the ``copy=True`` (:issue:`13205`)
488+
- Bug in ``DatetimeIndex.is_normalized`` returns incorrectly for normalized date_range in case of local timezones (:issue:`13459`)
488489

489490
- Bug in ``DataFrame.to_csv()`` in which float values were being quoted even though quotations were specified for non-numeric values only (:issue:`12922`, :issue:`13259`)
490491
- Bug in ``MultiIndex`` slicing where extra elements were returned when level is non-unique (:issue:`12896`)

pandas/io/tests/test_pytables.py

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
assert_panel_equal,
3535
assert_frame_equal,
3636
assert_series_equal,
37-
assert_produces_warning)
37+
assert_produces_warning,
38+
set_timezone)
3839
from pandas import concat, Timestamp
3940
from pandas import compat
4041
from pandas.compat import range, lrange, u
@@ -5309,14 +5310,6 @@ def test_store_timezone(self):
53095310
# issue storing datetime.date with a timezone as it resets when read
53105311
# back in a new timezone
53115312

5312-
import platform
5313-
if platform.system() == "Windows":
5314-
raise nose.SkipTest("timezone setting not supported on windows")
5315-
5316-
import datetime
5317-
import time
5318-
import os
5319-
53205313
# original method
53215314
with ensure_clean_store(self.path) as store:
53225315

@@ -5327,34 +5320,17 @@ def test_store_timezone(self):
53275320
assert_frame_equal(result, df)
53285321

53295322
# with tz setting
5330-
orig_tz = os.environ.get('TZ')
5331-
5332-
def setTZ(tz):
5333-
if tz is None:
5334-
try:
5335-
del os.environ['TZ']
5336-
except:
5337-
pass
5338-
else:
5339-
os.environ['TZ'] = tz
5340-
time.tzset()
5341-
5342-
try:
5343-
5344-
with ensure_clean_store(self.path) as store:
5323+
with ensure_clean_store(self.path) as store:
53455324

5346-
setTZ('EST5EDT')
5325+
with set_timezone('EST5EDT'):
53475326
today = datetime.date(2013, 9, 10)
53485327
df = DataFrame([1, 2, 3], index=[today, today, today])
53495328
store['obj1'] = df
53505329

5351-
setTZ('CST6CDT')
5330+
with set_timezone('CST6CDT'):
53525331
result = store['obj1']
53535332

5354-
assert_frame_equal(result, df)
5355-
5356-
finally:
5357-
setTZ(orig_tz)
5333+
assert_frame_equal(result, df)
53585334

53595335
def test_legacy_datetimetz_object(self):
53605336
# legacy from < 0.17.0

pandas/tseries/tests/test_timezones.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
import pandas.util.testing as tm
2020
from pandas.types.api import DatetimeTZDtype
21-
from pandas.util.testing import assert_frame_equal
21+
from pandas.util.testing import assert_frame_equal, set_timezone
2222
from pandas.compat import lrange, zip
2323

2424
try:
@@ -1398,6 +1398,26 @@ def test_normalize_tz(self):
13981398
self.assertTrue(result.is_normalized)
13991399
self.assertFalse(rng.is_normalized)
14001400

1401+
def test_normalize_tz_local(self):
1402+
# GH 13459
1403+
from dateutil.tz import tzlocal
1404+
1405+
timezones = ['US/Pacific', 'US/Eastern', 'UTC', 'Asia/Kolkata',
1406+
'Asia/Shanghai', 'Australia/Canberra']
1407+
1408+
for timezone in timezones:
1409+
with set_timezone(timezone):
1410+
rng = date_range('1/1/2000 9:30', periods=10, freq='D',
1411+
tz=tzlocal())
1412+
1413+
result = rng.normalize()
1414+
expected = date_range('1/1/2000', periods=10, freq='D',
1415+
tz=tzlocal())
1416+
self.assert_index_equal(result, expected)
1417+
1418+
self.assertTrue(result.is_normalized)
1419+
self.assertFalse(rng.is_normalized)
1420+
14011421
def test_tzaware_offset(self):
14021422
dates = date_range('2012-11-01', periods=3, tz='US/Pacific')
14031423
offset = dates + offsets.Hour(5)

pandas/tslib.pyx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4810,12 +4810,10 @@ def dates_normalized(ndarray[int64_t] stamps, tz=None):
48104810
elif _is_tzlocal(tz):
48114811
for i in range(n):
48124812
pandas_datetime_to_datetimestruct(stamps[i], PANDAS_FR_ns, &dts)
4813-
if (dts.min + dts.sec + dts.us) > 0:
4814-
return False
48154813
dt = datetime(dts.year, dts.month, dts.day, dts.hour, dts.min,
48164814
dts.sec, dts.us, tz)
48174815
dt = dt + tz.utcoffset(dt)
4818-
if dt.hour > 0:
4816+
if (dt.hour + dt.minute + dt.second + dt.microsecond) > 0:
48194817
return False
48204818
else:
48214819
trans, deltas, typ = _get_dst_info(tz)

pandas/util/testing.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2667,3 +2667,50 @@ def patch(ob, attr, value):
26672667
delattr(ob, attr)
26682668
else:
26692669
setattr(ob, attr, old)
2670+
2671+
2672+
@contextmanager
2673+
def set_timezone(tz):
2674+
"""Context manager for temporarily setting a timezone.
2675+
2676+
Parameters
2677+
----------
2678+
tz : str
2679+
A string representing a valid timezone.
2680+
2681+
Examples
2682+
--------
2683+
2684+
>>> from datetime import datetime
2685+
>>> from dateutil.tz import tzlocal
2686+
>>> tzlocal().tzname(datetime.now())
2687+
'IST'
2688+
2689+
>>> with set_timezone('US/Eastern'):
2690+
... tzlocal().tzname(datetime.now())
2691+
...
2692+
'EDT'
2693+
"""
2694+
if is_platform_windows():
2695+
import nose
2696+
raise nose.SkipTest("timezone setting not supported on windows")
2697+
2698+
import os
2699+
import time
2700+
2701+
def setTZ(tz):
2702+
if tz is None:
2703+
try:
2704+
del os.environ['TZ']
2705+
except:
2706+
pass
2707+
else:
2708+
os.environ['TZ'] = tz
2709+
time.tzset()
2710+
2711+
orig_tz = os.environ.get('TZ')
2712+
setTZ(tz)
2713+
try:
2714+
yield
2715+
finally:
2716+
setTZ(orig_tz)

0 commit comments

Comments
 (0)