Skip to content

Commit 0799940

Browse files
srf94bmoscon
authored andcommitted
Better datetime to ms (pandas-dev#549)
* Avoid floating point in datetime_to_ms (Issue 483) * Added integration test for datetime_to_ms bug * Truncate microseconds not round
1 parent 9f2d5c0 commit 0799940

File tree

4 files changed

+30
-5
lines changed

4 files changed

+30
-5
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
### 1.66
44
* Bugfix: #168 Do not allow empty string as a column name
5+
* Bugfix: #483 Remove potential floating point error from datetime_to_ms
56

67
### 1.65 (2018-04-16)
78
* Bugfix: #534 VersionStore: overwriting a symbol with different dtype (but same data format) does not

arctic/date/_util.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,8 @@ def _add_tzone(dtm):
163163
def datetime_to_ms(d):
164164
"""Convert a Python datetime object to a millisecond epoch (UTC) time value."""
165165
try:
166-
return long((calendar.timegm(_add_tzone(d).utctimetuple()) + d.microsecond / 1000000.0) * 1e3)
166+
millisecond = d.microsecond // 1000
167+
return calendar.timegm(_add_tzone(d).utctimetuple()) * 1000 + millisecond
167168
except AttributeError:
168169
raise TypeError('expect Python datetime object, not %s' % type(d))
169170

tests/integration/tickstore/test_ts_write.py

+16-4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
import numpy as np
44
from pandas.util.testing import assert_frame_equal
55
import pytest
6-
7-
from arctic import arctic as m
8-
from arctic.date import mktz
6+
import pytz
7+
from arctic.date import mktz, DateRange
98
from arctic.exceptions import OverlappingDataException, \
109
NoDataFoundException
1110
from arctic.tickstore.tickstore import SYMBOL, START, END, COUNT, COLUMNS
@@ -79,7 +78,7 @@ def test_ts_write_pandas(tickstore_lib):
7978

8079
read = tickstore_lib.read('SYM', columns=None)
8180
assert_frame_equal(read, data, check_names=False)
82-
81+
8382

8483
def test_ts_write_named_col(tickstore_lib):
8584
data = DUMMY_DATA
@@ -96,3 +95,16 @@ def test_ts_write_named_col(tickstore_lib):
9695

9796
read = tickstore_lib.read('SYM')
9897
assert(read.index.name is None)
98+
99+
100+
def test_millisecond_roundtrip(tickstore_lib):
101+
test_time = dt(2004, 1, 14, 8, 30, 4, 807000, tzinfo=pytz.utc)
102+
103+
data = [{'index': test_time, 'price': 9142.12, 'qualifiers': ''}]
104+
tickstore_lib.write('blah', data)
105+
106+
data_range = DateRange(dt(2004, 1, 14, tzinfo=pytz.utc),
107+
dt(2004, 1, 15, tzinfo=pytz.utc))
108+
reread = tickstore_lib.read('blah', data_range)
109+
110+
assert reread.index[0].to_datetime() == test_time

tests/unit/date/test_datetime_to_ms_roundtrip.py

+11
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,14 @@ def test_datetime_roundtrip_est_tz():
7171
pdt = datetime.datetime(2012, 1, 12, 12, 12, 12, 123000, tzinfo=mktz('EST'))
7272
pdt2 = ms_to_datetime(datetime_to_ms(pdt))
7373
assert pdt2.replace(tzinfo=mktz()) == pdt
74+
75+
76+
@pytest.mark.parametrize("microseconds,expected", [
77+
(807000, 1074069004807),
78+
(807243, 1074069004807),
79+
(807675, 1074069004807)
80+
])
81+
def test_millisecond_conversion(microseconds, expected):
82+
pdt = datetime.datetime(2004, 1, 14, 8, 30, 4, microseconds, tzinfo=pytz.utc)
83+
pdt2 = datetime_to_ms(pdt)
84+
assert pdt2 == expected

0 commit comments

Comments
 (0)