Skip to content

Commit fb8b578

Browse files
committed
refactor(datetime): revert back to use PyDateTime_FromDateAndTime because on Windows the timestamp is restricted to years from 1970 through 2038
1 parent 28bdd97 commit fb8b578

File tree

1 file changed

+23
-24
lines changed

1 file changed

+23
-24
lines changed

src/DateType.cc

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,36 @@
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-
1812
DateType::DateType(PyObject *object) : PyType(object) {}
1913

2014
DateType::DateType(JSContext *cx, JS::HandleObject dateObj) {
2115
if (!PyDateTimeAPI) { PyDateTime_IMPORT; } // for PyDateTime_FromTimestamp
2216

23-
// Convert by the timestamp value
2417
JS::Rooted<JS::ValueArray<0>> args(cx);
25-
JS::Rooted<JS::Value> timeValue(cx);
26-
JS_CallFunctionName(cx, dateObj, "getTime", args, &timeValue);
27-
double milliseconds = timeValue.toNumber();
28-
29-
PyObject *timestampArg = PyTuple_New(2);
30-
PyTuple_SetItem(timestampArg, 0, PyFloat_FromDouble(milliseconds / 1000));
31-
PyTuple_SetItem(timestampArg, 1, PyDateTime_TimeZone_UTC); // Make the resulting Python datetime object timezone-aware
32-
// See https://docs.python.org/3/library/datetime.html#aware-and-naive-objects
33-
pyObject = PyDateTime_FromTimestamp(timestampArg);
34-
Py_INCREF(PyDateTime_TimeZone_UTC); // PyTuple_SetItem steals the reference
35-
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
18+
JS::Rooted<JS::Value> year(cx);
19+
JS::Rooted<JS::Value> month(cx);
20+
JS::Rooted<JS::Value> day(cx);
21+
JS::Rooted<JS::Value> hour(cx);
22+
JS::Rooted<JS::Value> minute(cx);
23+
JS::Rooted<JS::Value> second(cx);
24+
JS::Rooted<JS::Value> usecond(cx);
25+
JS_CallFunctionName(cx, dateObj, "getUTCFullYear", args, &year);
26+
JS_CallFunctionName(cx, dateObj, "getUTCMonth", args, &month);
27+
JS_CallFunctionName(cx, dateObj, "getUTCDate", args, &day);
28+
JS_CallFunctionName(cx, dateObj, "getUTCHours", args, &hour);
29+
JS_CallFunctionName(cx, dateObj, "getUTCMinutes", args, &minute);
30+
JS_CallFunctionName(cx, dateObj, "getUTCSeconds", args, &second);
31+
JS_CallFunctionName(cx, dateObj, "getUTCMilliseconds", args, &usecond);
32+
33+
pyObject = PyDateTimeAPI->DateTime_FromDateAndTime(
34+
year.toNumber(), month.toNumber() + 1, day.toNumber(),
35+
hour.toNumber(), minute.toNumber(), second.toNumber(),
36+
usecond.toNumber() * 1000,
37+
PyDateTime_TimeZone_UTC, // Make the resulting Python datetime object timezone-aware
38+
// See https://docs.python.org/3/library/datetime.html#aware-and-naive-objects
39+
PyDateTimeAPI->DateTimeType
4240
);
41+
Py_INCREF(PyDateTime_TimeZone_UTC);
4342
}
4443

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

0 commit comments

Comments
 (0)