Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

BUG: Timestamp.tz_localize resets nanosecond #7534

Merged
merged 1 commit into from Jun 21, 2014
Jump to file or symbol
Failed to load files and symbols.
+48 −29
Split
View
@@ -248,7 +248,7 @@ Bug Fixes
- BUG in ``resample`` raises ``ValueError`` when target contains ``NaT`` (:issue:`7227`)
-
+- Bug in ``Timestamp.tz_convert`` resets ``nanosecond`` info (:issue:`7534`)
- Bug in ``Index.astype(float)`` where it would return an ``object`` dtype
``Index`` (:issue:`7464`).
@@ -1,5 +1,5 @@
# pylint: disable-msg=E1101,W0612
-from datetime import datetime, time, timedelta, tzinfo, date
+from datetime import datetime, timedelta, tzinfo, date
import sys
import os
import unittest
@@ -8,10 +8,9 @@
import numpy as np
import pytz
-from pandas import (Index, Series, TimeSeries, DataFrame, isnull,
- date_range, Timestamp)
+from pandas import (Index, Series, DataFrame, isnull, Timestamp)
-from pandas import DatetimeIndex, Int64Index, to_datetime, NaT
+from pandas import DatetimeIndex, to_datetime, NaT
from pandas import tslib
import pandas.core.datetools as datetools
@@ -20,17 +19,10 @@
import pandas.tseries.tools as tools
from pytz import NonExistentTimeError
-from pandas.util.testing import assert_series_equal, assert_almost_equal, assertRaisesRegexp
import pandas.util.testing as tm
-import pandas.lib as lib
-import pandas.core.datetools as dt
-from numpy.random import rand
from pandas.util.testing import assert_frame_equal
-import pandas.compat as compat
-from pandas.compat import range, lrange, zip, cPickle as pickle
-from pandas.core.datetools import BDay
-import pandas.core.common as com
+from pandas.compat import lrange, zip
from pandas import _np_version_under1p7
@@ -544,13 +536,13 @@ def test_localized_at_time_between_time(self):
result = ts_local.at_time(time(10, 0))
expected = ts.at_time(time(10, 0)).tz_localize(self.tzstr('US/Eastern'))
- assert_series_equal(result, expected)
+ tm.assert_series_equal(result, expected)
self.assertTrue(self.cmptz(result.index.tz, self.tz('US/Eastern')))
t1, t2 = time(10, 0), time(11, 0)
result = ts_local.between_time(t1, t2)
expected = ts.between_time(t1, t2).tz_localize(self.tzstr('US/Eastern'))
- assert_series_equal(result, expected)
+ tm.assert_series_equal(result, expected)
self.assertTrue(self.cmptz(result.index.tz, self.tz('US/Eastern')))
def test_string_index_alias_tz_aware(self):
@@ -631,7 +623,7 @@ def test_frame_no_datetime64_dtype(self):
'datetimes_with_tz' : datetimes_with_tz })
result = df.get_dtype_counts()
expected = Series({ 'datetime64[ns]' : 3, 'object' : 1 })
- assert_series_equal(result, expected)
+ tm.assert_series_equal(result, expected)
def test_hongkong_tz_convert(self):
# #1673
@@ -863,7 +855,7 @@ def test_series_frame_tz_localize(self):
# Can't localize if already tz-aware
rng = date_range('1/1/2011', periods=100, freq='H', tz='utc')
ts = Series(1, index=rng)
- assertRaisesRegexp(TypeError, 'Already tz-aware', ts.tz_localize, 'US/Eastern')
+ tm.assertRaisesRegexp(TypeError, 'Already tz-aware', ts.tz_localize, 'US/Eastern')
def test_series_frame_tz_convert(self):
rng = date_range('1/1/2011', periods=200, freq='D',
@@ -887,7 +879,7 @@ def test_series_frame_tz_convert(self):
# can't convert tz-naive
rng = date_range('1/1/2011', periods=200, freq='D')
ts = Series(1, index=rng)
- assertRaisesRegexp(TypeError, "Cannot convert tz-naive", ts.tz_convert, 'US/Eastern')
+ tm.assertRaisesRegexp(TypeError, "Cannot convert tz-naive", ts.tz_convert, 'US/Eastern')
def test_join_utc_convert(self):
rng = date_range('1/1/2011', periods=100, freq='H', tz='utc')
@@ -1033,7 +1025,7 @@ def test_arith_utc_convert(self):
expected = uts1 + uts2
self.assertEqual(result.index.tz, pytz.UTC)
- assert_series_equal(result, expected)
+ tm.assert_series_equal(result, expected)
def test_intersection(self):
rng = date_range('1/1/2011', periods=100, freq='H', tz='utc')
@@ -9,6 +9,7 @@
from pandas.tslib import period_asfreq, period_ordinal
from pandas.tseries.index import date_range
from pandas.tseries.frequencies import get_freq
+import pandas.tseries.offsets as offsets
from pandas import _np_version_under1p7
import pandas.util.testing as tm
from pandas.util.testing import assert_series_equal
@@ -61,7 +62,7 @@ def test_bounds_with_different_units(self):
for unit in time_units:
self.assertRaises(
ValueError,
- tslib.Timestamp,
+ Timestamp,
np.datetime64(date_string, dtype='M8[%s]' % unit)
)
@@ -72,27 +73,48 @@ def test_bounds_with_different_units(self):
for date_string in in_bounds_dates:
for unit in time_units:
- tslib.Timestamp(
+ Timestamp(
np.datetime64(date_string, dtype='M8[%s]' % unit)
)
+ def test_tz(self):
+ t = '2014-02-01 09:00'
+ ts = Timestamp(t)
+ local = ts.tz_localize('Asia/Tokyo')
+ self.assertEqual(local.hour, 9)
+ self.assertEqual(local, Timestamp(t, tz='Asia/Tokyo'))
+ conv = local.tz_convert('US/Eastern')
+ self.assertEqual(conv,
+ Timestamp('2014-01-31 19:00', tz='US/Eastern'))
+ self.assertEqual(conv.hour, 19)
+
+ # preserves nanosecond
+ ts = Timestamp(t) + offsets.Nano(5)
+ local = ts.tz_localize('Asia/Tokyo')
+ self.assertEqual(local.hour, 9)
+ self.assertEqual(local.nanosecond, 5)
+ conv = local.tz_convert('US/Eastern')
+ self.assertEqual(conv.nanosecond, 5)
+ self.assertEqual(conv.hour, 19)
+
def test_barely_oob_dts(self):
one_us = np.timedelta64(1)
# By definition we can't go out of bounds in [ns], so we
# convert the datetime64s to [us] so we can go out of bounds
- min_ts_us = np.datetime64(tslib.Timestamp.min).astype('M8[us]')
- max_ts_us = np.datetime64(tslib.Timestamp.max).astype('M8[us]')
+ min_ts_us = np.datetime64(Timestamp.min).astype('M8[us]')
+ max_ts_us = np.datetime64(Timestamp.max).astype('M8[us]')
# No error for the min/max datetimes
- tslib.Timestamp(min_ts_us)
- tslib.Timestamp(max_ts_us)
+ Timestamp(min_ts_us)
+ Timestamp(max_ts_us)
# One us less than the minimum is an error
- self.assertRaises(ValueError, tslib.Timestamp, min_ts_us - one_us)
+ self.assertRaises(ValueError, Timestamp, min_ts_us - one_us)
# One us more than the maximum is an error
- self.assertRaises(ValueError, tslib.Timestamp, max_ts_us + one_us)
+ self.assertRaises(ValueError, Timestamp, max_ts_us + one_us)
+
class TestDatetimeParsingWrappers(tm.TestCase):
def test_does_not_convert_mixed_integer(self):
View
@@ -341,21 +341,26 @@ class Timestamp(_Timestamp):
def is_year_end(self):
return self._get_start_end_field('is_year_end')
- def tz_localize(self, tz):
+ def tz_localize(self, tz, infer_dst=False):
"""
Convert naive Timestamp to local time zone
Parameters
----------
tz : pytz.timezone or dateutil.tz.tzfile
+ infer_dst : boolean, default False
+ Attempt to infer fall dst-transition hours based on order
Returns
-------
localized : Timestamp
"""
if self.tzinfo is None:
# tz naive, localize
- return Timestamp(self.to_pydatetime(), tz=tz)
+ tz = maybe_get_tz(tz)
+ value = tz_localize_to_utc(np.array([self.value]), tz,
+ infer_dst=infer_dst)[0]
+ return Timestamp(value, tz=tz)
else:
raise Exception('Cannot localize tz-aware Timestamp, use '
'tz_convert for conversions')