Skip to content

Commit 28bdd97

Browse files
committed
fix(datetime): round to milliseconds precision because the smallest unit for a JS Date is 1ms
1 parent 2864237 commit 28bdd97

File tree

1 file changed

+14
-0
lines changed

1 file changed

+14
-0
lines changed

src/DateType.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
#include <Python.h>
1010
#include <datetime.h>
1111

12+
// https://github.com/python/cpython/blob/v3.10.11/Modules/_datetimemodule.c#L89-L92
13+
#define DATE_SET_MICROSECOND(o, v) \
14+
(((o)->data[7] = ((v) & 0xff0000) >> 16), \
15+
((o)->data[8] = ((v) & 0x00ff00) >> 8), \
16+
((o)->data[9] = ((v) & 0x0000ff)))
17+
1218
DateType::DateType(PyObject *object) : PyType(object) {}
1319

1420
DateType::DateType(JSContext *cx, JS::HandleObject dateObj) {
@@ -25,7 +31,15 @@ DateType::DateType(JSContext *cx, JS::HandleObject dateObj) {
2531
PyTuple_SetItem(timestampArg, 1, PyDateTime_TimeZone_UTC); // Make the resulting Python datetime object timezone-aware
2632
// See https://docs.python.org/3/library/datetime.html#aware-and-naive-objects
2733
pyObject = PyDateTime_FromTimestamp(timestampArg);
34+
Py_INCREF(PyDateTime_TimeZone_UTC); // PyTuple_SetItem steals the reference
2835
Py_DECREF(timestampArg);
36+
37+
// Round to milliseconds precision because the smallest unit for a JS Date is 1ms
38+
double microseconds = PyDateTime_DATE_GET_MICROSECOND(pyObject);
39+
DATE_SET_MICROSECOND(
40+
(PyDateTime_DateTime *)pyObject,
41+
std::lround(microseconds / 1000) * 1000
42+
);
2943
}
3044

3145
JSObject *DateType::toJsDate(JSContext *cx) {

0 commit comments

Comments
 (0)