|
9 | 9 | #include <Python.h> |
10 | 10 | #include <datetime.h> |
11 | 11 |
|
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 | | - |
18 | 12 | DateType::DateType(PyObject *object) : PyType(object) {} |
19 | 13 |
|
20 | 14 | DateType::DateType(JSContext *cx, JS::HandleObject dateObj) { |
21 | 15 | if (!PyDateTimeAPI) { PyDateTime_IMPORT; } // for PyDateTime_FromTimestamp |
22 | 16 |
|
23 | | - // Convert by the timestamp value |
24 | 17 | 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 |
42 | 40 | ); |
| 41 | + Py_INCREF(PyDateTime_TimeZone_UTC); |
43 | 42 | } |
44 | 43 |
|
45 | 44 | JSObject *DateType::toJsDate(JSContext *cx) { |
|
0 commit comments