mirror of
https://github.com/msgpack/msgpack-python.git
synced 2025-10-19 20:03:16 +00:00
Fix datetime before epoch on windows in cython implementation (#436)
Cython implementation still used datetime.from_timestamp method, which does not work on windows. Update the cython implementation to use utc time and delta and add a regression test to highlight the issue.
This commit is contained in:
parent
772c830841
commit
8fb709f2e0
3 changed files with 30 additions and 13 deletions
1
Makefile
1
Makefile
|
@ -25,6 +25,7 @@ clean:
|
|||
rm -rf build
|
||||
rm -f msgpack/_cmsgpack.cpp
|
||||
rm -f msgpack/_cmsgpack.*.so
|
||||
rm -f msgpack/_cmsgpack.*.pyd
|
||||
rm -rf msgpack/__pycache__
|
||||
rm -rf test/__pycache__
|
||||
|
||||
|
|
|
@ -341,7 +341,26 @@ static int unpack_callback_ext(unpack_user* u, const char* base, const char* pos
|
|||
else if (u->timestamp == 0) { // Timestamp
|
||||
py = PyObject_CallFunction(u->timestamp_t, "(Lk)", ts.tv_sec, ts.tv_nsec);
|
||||
}
|
||||
else { // float or datetime
|
||||
else if (u->timestamp == 3) { // datetime
|
||||
// Calculate datetime using epoch + delta
|
||||
// due to limitations PyDateTime_FromTimestamp on Windows with negative timestamps
|
||||
PyObject *epoch = PyDateTimeAPI->DateTime_FromDateAndTime(1970, 1, 1, 0, 0, 0, 0, u->utc, PyDateTimeAPI->DateTimeType);
|
||||
if (epoch == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyObject* d = PyDelta_FromDSU(0, ts.tv_sec, ts.tv_nsec / 1000);
|
||||
if (d == NULL) {
|
||||
Py_DECREF(epoch);
|
||||
return -1;
|
||||
}
|
||||
|
||||
py = PyNumber_Add(epoch, d);
|
||||
|
||||
Py_DECREF(epoch);
|
||||
Py_DECREF(d);
|
||||
}
|
||||
else { // float
|
||||
PyObject *a = PyFloat_FromDouble((double)ts.tv_nsec);
|
||||
if (a == NULL) return -1;
|
||||
|
||||
|
@ -358,18 +377,7 @@ static int unpack_callback_ext(unpack_user* u, const char* base, const char* pos
|
|||
a = PyNumber_Add(b, c);
|
||||
Py_DECREF(b);
|
||||
Py_DECREF(c);
|
||||
|
||||
if (u->timestamp == 3) { // datetime
|
||||
PyObject *t = PyTuple_Pack(2, a, u->utc);
|
||||
Py_DECREF(a);
|
||||
if (t == NULL) {
|
||||
return -1;
|
||||
}
|
||||
py = PyDateTime_FromTimestamp(t);
|
||||
Py_DECREF(t);
|
||||
} else { // float
|
||||
py = a;
|
||||
}
|
||||
py = a;
|
||||
}
|
||||
} else {
|
||||
py = PyObject_CallFunction(u->ext_hook, "(iy#)", (int)typecode, pos, (Py_ssize_t)length-1);
|
||||
|
|
|
@ -99,6 +99,14 @@ def test_unpack_datetime():
|
|||
assert unpacked == datetime.datetime(1970, 1, 1, 0, 0, 42, 0, tzinfo=_utc)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[0] == 2, reason="datetime support is PY3+ only")
|
||||
def test_pack_unpack_before_epoch():
|
||||
t_in = datetime.datetime(1960, 1, 1, tzinfo=_utc)
|
||||
packed = msgpack.packb(t_in, datetime=True)
|
||||
unpacked = msgpack.unpackb(packed, timestamp=3)
|
||||
assert unpacked == t_in
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[0] == 2, reason="datetime support is PY3+ only")
|
||||
def test_pack_datetime():
|
||||
t = Timestamp(42, 14000)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue