17db96d56Sopenharmony_ci/*  C implementation for the date/time type documented at
27db96d56Sopenharmony_ci *  https://www.zope.dev/Members/fdrake/DateTimeWiki/FrontPage
37db96d56Sopenharmony_ci */
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_ci/* bpo-35081: Defining this prevents including the C API capsule;
67db96d56Sopenharmony_ci * internal versions of the  Py*_Check macros which do not require
77db96d56Sopenharmony_ci * the capsule are defined below */
87db96d56Sopenharmony_ci#define _PY_DATETIME_IMPL
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ci#ifndef Py_BUILD_CORE_BUILTIN
117db96d56Sopenharmony_ci#  define Py_BUILD_CORE_MODULE 1
127db96d56Sopenharmony_ci#endif
137db96d56Sopenharmony_ci#define NEEDS_PY_IDENTIFIER
147db96d56Sopenharmony_ci
157db96d56Sopenharmony_ci#include "Python.h"
167db96d56Sopenharmony_ci#include "pycore_long.h"          // _PyLong_GetOne()
177db96d56Sopenharmony_ci#include "pycore_object.h"        // _PyObject_Init()
187db96d56Sopenharmony_ci#include "datetime.h"
197db96d56Sopenharmony_ci#include "structmember.h"         // PyMemberDef
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci#include <time.h>
227db96d56Sopenharmony_ci
237db96d56Sopenharmony_ci#ifdef MS_WINDOWS
247db96d56Sopenharmony_ci#  include <winsock2.h>         /* struct timeval */
257db96d56Sopenharmony_ci#endif
267db96d56Sopenharmony_ci
277db96d56Sopenharmony_ci#define PyDate_Check(op) PyObject_TypeCheck(op, &PyDateTime_DateType)
287db96d56Sopenharmony_ci#define PyDate_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_DateType)
297db96d56Sopenharmony_ci
307db96d56Sopenharmony_ci#define PyDateTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_DateTimeType)
317db96d56Sopenharmony_ci#define PyDateTime_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_DateTimeType)
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ci#define PyTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeType)
347db96d56Sopenharmony_ci#define PyTime_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_TimeType)
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_ci#define PyDelta_Check(op) PyObject_TypeCheck(op, &PyDateTime_DeltaType)
377db96d56Sopenharmony_ci#define PyDelta_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_DeltaType)
387db96d56Sopenharmony_ci
397db96d56Sopenharmony_ci#define PyTZInfo_Check(op) PyObject_TypeCheck(op, &PyDateTime_TZInfoType)
407db96d56Sopenharmony_ci#define PyTZInfo_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_TZInfoType)
417db96d56Sopenharmony_ci
427db96d56Sopenharmony_ci#define PyTimezone_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeZoneType)
437db96d56Sopenharmony_ci
447db96d56Sopenharmony_ci/*[clinic input]
457db96d56Sopenharmony_cimodule datetime
467db96d56Sopenharmony_ciclass datetime.datetime "PyDateTime_DateTime *" "&PyDateTime_DateTimeType"
477db96d56Sopenharmony_ciclass datetime.date "PyDateTime_Date *" "&PyDateTime_DateType"
487db96d56Sopenharmony_ciclass datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "&PyDateTime_IsoCalendarDateType"
497db96d56Sopenharmony_ci[clinic start generated code]*/
507db96d56Sopenharmony_ci/*[clinic end generated code: output=da39a3ee5e6b4b0d input=81bec0fa19837f63]*/
517db96d56Sopenharmony_ci
527db96d56Sopenharmony_ci#include "clinic/_datetimemodule.c.h"
537db96d56Sopenharmony_ci
547db96d56Sopenharmony_ci/* We require that C int be at least 32 bits, and use int virtually
557db96d56Sopenharmony_ci * everywhere.  In just a few cases we use a temp long, where a Python
567db96d56Sopenharmony_ci * API returns a C long.  In such cases, we have to ensure that the
577db96d56Sopenharmony_ci * final result fits in a C int (this can be an issue on 64-bit boxes).
587db96d56Sopenharmony_ci */
597db96d56Sopenharmony_ci#if SIZEOF_INT < 4
607db96d56Sopenharmony_ci#       error "_datetime.c requires that C int have at least 32 bits"
617db96d56Sopenharmony_ci#endif
627db96d56Sopenharmony_ci
637db96d56Sopenharmony_ci#define MINYEAR 1
647db96d56Sopenharmony_ci#define MAXYEAR 9999
657db96d56Sopenharmony_ci#define MAXORDINAL 3652059 /* date(9999,12,31).toordinal() */
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ci/* Nine decimal digits is easy to communicate, and leaves enough room
687db96d56Sopenharmony_ci * so that two delta days can be added w/o fear of overflowing a signed
697db96d56Sopenharmony_ci * 32-bit int, and with plenty of room left over to absorb any possible
707db96d56Sopenharmony_ci * carries from adding seconds.
717db96d56Sopenharmony_ci */
727db96d56Sopenharmony_ci#define MAX_DELTA_DAYS 999999999
737db96d56Sopenharmony_ci
747db96d56Sopenharmony_ci/* Rename the long macros in datetime.h to more reasonable short names. */
757db96d56Sopenharmony_ci#define GET_YEAR                PyDateTime_GET_YEAR
767db96d56Sopenharmony_ci#define GET_MONTH               PyDateTime_GET_MONTH
777db96d56Sopenharmony_ci#define GET_DAY                 PyDateTime_GET_DAY
787db96d56Sopenharmony_ci#define DATE_GET_HOUR           PyDateTime_DATE_GET_HOUR
797db96d56Sopenharmony_ci#define DATE_GET_MINUTE         PyDateTime_DATE_GET_MINUTE
807db96d56Sopenharmony_ci#define DATE_GET_SECOND         PyDateTime_DATE_GET_SECOND
817db96d56Sopenharmony_ci#define DATE_GET_MICROSECOND    PyDateTime_DATE_GET_MICROSECOND
827db96d56Sopenharmony_ci#define DATE_GET_FOLD           PyDateTime_DATE_GET_FOLD
837db96d56Sopenharmony_ci
847db96d56Sopenharmony_ci/* Date accessors for date and datetime. */
857db96d56Sopenharmony_ci#define SET_YEAR(o, v)          (((o)->data[0] = ((v) & 0xff00) >> 8), \
867db96d56Sopenharmony_ci                 ((o)->data[1] = ((v) & 0x00ff)))
877db96d56Sopenharmony_ci#define SET_MONTH(o, v)         (PyDateTime_GET_MONTH(o) = (v))
887db96d56Sopenharmony_ci#define SET_DAY(o, v)           (PyDateTime_GET_DAY(o) = (v))
897db96d56Sopenharmony_ci
907db96d56Sopenharmony_ci/* Date/Time accessors for datetime. */
917db96d56Sopenharmony_ci#define DATE_SET_HOUR(o, v)     (PyDateTime_DATE_GET_HOUR(o) = (v))
927db96d56Sopenharmony_ci#define DATE_SET_MINUTE(o, v)   (PyDateTime_DATE_GET_MINUTE(o) = (v))
937db96d56Sopenharmony_ci#define DATE_SET_SECOND(o, v)   (PyDateTime_DATE_GET_SECOND(o) = (v))
947db96d56Sopenharmony_ci#define DATE_SET_MICROSECOND(o, v)      \
957db96d56Sopenharmony_ci    (((o)->data[7] = ((v) & 0xff0000) >> 16), \
967db96d56Sopenharmony_ci     ((o)->data[8] = ((v) & 0x00ff00) >> 8), \
977db96d56Sopenharmony_ci     ((o)->data[9] = ((v) & 0x0000ff)))
987db96d56Sopenharmony_ci#define DATE_SET_FOLD(o, v)   (PyDateTime_DATE_GET_FOLD(o) = (v))
997db96d56Sopenharmony_ci
1007db96d56Sopenharmony_ci/* Time accessors for time. */
1017db96d56Sopenharmony_ci#define TIME_GET_HOUR           PyDateTime_TIME_GET_HOUR
1027db96d56Sopenharmony_ci#define TIME_GET_MINUTE         PyDateTime_TIME_GET_MINUTE
1037db96d56Sopenharmony_ci#define TIME_GET_SECOND         PyDateTime_TIME_GET_SECOND
1047db96d56Sopenharmony_ci#define TIME_GET_MICROSECOND    PyDateTime_TIME_GET_MICROSECOND
1057db96d56Sopenharmony_ci#define TIME_GET_FOLD           PyDateTime_TIME_GET_FOLD
1067db96d56Sopenharmony_ci#define TIME_SET_HOUR(o, v)     (PyDateTime_TIME_GET_HOUR(o) = (v))
1077db96d56Sopenharmony_ci#define TIME_SET_MINUTE(o, v)   (PyDateTime_TIME_GET_MINUTE(o) = (v))
1087db96d56Sopenharmony_ci#define TIME_SET_SECOND(o, v)   (PyDateTime_TIME_GET_SECOND(o) = (v))
1097db96d56Sopenharmony_ci#define TIME_SET_MICROSECOND(o, v)      \
1107db96d56Sopenharmony_ci    (((o)->data[3] = ((v) & 0xff0000) >> 16), \
1117db96d56Sopenharmony_ci     ((o)->data[4] = ((v) & 0x00ff00) >> 8), \
1127db96d56Sopenharmony_ci     ((o)->data[5] = ((v) & 0x0000ff)))
1137db96d56Sopenharmony_ci#define TIME_SET_FOLD(o, v)   (PyDateTime_TIME_GET_FOLD(o) = (v))
1147db96d56Sopenharmony_ci
1157db96d56Sopenharmony_ci/* Delta accessors for timedelta. */
1167db96d56Sopenharmony_ci#define GET_TD_DAYS(o)          (((PyDateTime_Delta *)(o))->days)
1177db96d56Sopenharmony_ci#define GET_TD_SECONDS(o)       (((PyDateTime_Delta *)(o))->seconds)
1187db96d56Sopenharmony_ci#define GET_TD_MICROSECONDS(o)  (((PyDateTime_Delta *)(o))->microseconds)
1197db96d56Sopenharmony_ci
1207db96d56Sopenharmony_ci#define SET_TD_DAYS(o, v)       ((o)->days = (v))
1217db96d56Sopenharmony_ci#define SET_TD_SECONDS(o, v)    ((o)->seconds = (v))
1227db96d56Sopenharmony_ci#define SET_TD_MICROSECONDS(o, v) ((o)->microseconds = (v))
1237db96d56Sopenharmony_ci
1247db96d56Sopenharmony_ci#define HASTZINFO               _PyDateTime_HAS_TZINFO
1257db96d56Sopenharmony_ci#define GET_TIME_TZINFO         PyDateTime_TIME_GET_TZINFO
1267db96d56Sopenharmony_ci#define GET_DT_TZINFO           PyDateTime_DATE_GET_TZINFO
1277db96d56Sopenharmony_ci/* M is a char or int claiming to be a valid month.  The macro is equivalent
1287db96d56Sopenharmony_ci * to the two-sided Python test
1297db96d56Sopenharmony_ci *      1 <= M <= 12
1307db96d56Sopenharmony_ci */
1317db96d56Sopenharmony_ci#define MONTH_IS_SANE(M) ((unsigned int)(M) - 1 < 12)
1327db96d56Sopenharmony_ci
1337db96d56Sopenharmony_ci/* Forward declarations. */
1347db96d56Sopenharmony_cistatic PyTypeObject PyDateTime_DateType;
1357db96d56Sopenharmony_cistatic PyTypeObject PyDateTime_DateTimeType;
1367db96d56Sopenharmony_cistatic PyTypeObject PyDateTime_DeltaType;
1377db96d56Sopenharmony_cistatic PyTypeObject PyDateTime_IsoCalendarDateType;
1387db96d56Sopenharmony_cistatic PyTypeObject PyDateTime_TimeType;
1397db96d56Sopenharmony_cistatic PyTypeObject PyDateTime_TZInfoType;
1407db96d56Sopenharmony_cistatic PyTypeObject PyDateTime_TimeZoneType;
1417db96d56Sopenharmony_ci
1427db96d56Sopenharmony_cistatic int check_tzinfo_subclass(PyObject *p);
1437db96d56Sopenharmony_ci
1447db96d56Sopenharmony_ci_Py_IDENTIFIER(as_integer_ratio);
1457db96d56Sopenharmony_ci_Py_IDENTIFIER(fromutc);
1467db96d56Sopenharmony_ci_Py_IDENTIFIER(isoformat);
1477db96d56Sopenharmony_ci_Py_IDENTIFIER(strftime);
1487db96d56Sopenharmony_ci
1497db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
1507db96d56Sopenharmony_ci * Math utilities.
1517db96d56Sopenharmony_ci */
1527db96d56Sopenharmony_ci
1537db96d56Sopenharmony_ci/* k = i+j overflows iff k differs in sign from both inputs,
1547db96d56Sopenharmony_ci * iff k^i has sign bit set and k^j has sign bit set,
1557db96d56Sopenharmony_ci * iff (k^i)&(k^j) has sign bit set.
1567db96d56Sopenharmony_ci */
1577db96d56Sopenharmony_ci#define SIGNED_ADD_OVERFLOWED(RESULT, I, J) \
1587db96d56Sopenharmony_ci    ((((RESULT) ^ (I)) & ((RESULT) ^ (J))) < 0)
1597db96d56Sopenharmony_ci
1607db96d56Sopenharmony_ci/* Compute Python divmod(x, y), returning the quotient and storing the
1617db96d56Sopenharmony_ci * remainder into *r.  The quotient is the floor of x/y, and that's
1627db96d56Sopenharmony_ci * the real point of this.  C will probably truncate instead (C99
1637db96d56Sopenharmony_ci * requires truncation; C89 left it implementation-defined).
1647db96d56Sopenharmony_ci * Simplification:  we *require* that y > 0 here.  That's appropriate
1657db96d56Sopenharmony_ci * for all the uses made of it.  This simplifies the code and makes
1667db96d56Sopenharmony_ci * the overflow case impossible (divmod(LONG_MIN, -1) is the only
1677db96d56Sopenharmony_ci * overflow case).
1687db96d56Sopenharmony_ci */
1697db96d56Sopenharmony_cistatic int
1707db96d56Sopenharmony_cidivmod(int x, int y, int *r)
1717db96d56Sopenharmony_ci{
1727db96d56Sopenharmony_ci    int quo;
1737db96d56Sopenharmony_ci
1747db96d56Sopenharmony_ci    assert(y > 0);
1757db96d56Sopenharmony_ci    quo = x / y;
1767db96d56Sopenharmony_ci    *r = x - quo * y;
1777db96d56Sopenharmony_ci    if (*r < 0) {
1787db96d56Sopenharmony_ci        --quo;
1797db96d56Sopenharmony_ci        *r += y;
1807db96d56Sopenharmony_ci    }
1817db96d56Sopenharmony_ci    assert(0 <= *r && *r < y);
1827db96d56Sopenharmony_ci    return quo;
1837db96d56Sopenharmony_ci}
1847db96d56Sopenharmony_ci
1857db96d56Sopenharmony_ci/* Nearest integer to m / n for integers m and n. Half-integer results
1867db96d56Sopenharmony_ci * are rounded to even.
1877db96d56Sopenharmony_ci */
1887db96d56Sopenharmony_cistatic PyObject *
1897db96d56Sopenharmony_cidivide_nearest(PyObject *m, PyObject *n)
1907db96d56Sopenharmony_ci{
1917db96d56Sopenharmony_ci    PyObject *result;
1927db96d56Sopenharmony_ci    PyObject *temp;
1937db96d56Sopenharmony_ci
1947db96d56Sopenharmony_ci    temp = _PyLong_DivmodNear(m, n);
1957db96d56Sopenharmony_ci    if (temp == NULL)
1967db96d56Sopenharmony_ci        return NULL;
1977db96d56Sopenharmony_ci    result = PyTuple_GET_ITEM(temp, 0);
1987db96d56Sopenharmony_ci    Py_INCREF(result);
1997db96d56Sopenharmony_ci    Py_DECREF(temp);
2007db96d56Sopenharmony_ci
2017db96d56Sopenharmony_ci    return result;
2027db96d56Sopenharmony_ci}
2037db96d56Sopenharmony_ci
2047db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
2057db96d56Sopenharmony_ci * General calendrical helper functions
2067db96d56Sopenharmony_ci */
2077db96d56Sopenharmony_ci
2087db96d56Sopenharmony_ci/* For each month ordinal in 1..12, the number of days in that month,
2097db96d56Sopenharmony_ci * and the number of days before that month in the same year.  These
2107db96d56Sopenharmony_ci * are correct for non-leap years only.
2117db96d56Sopenharmony_ci */
2127db96d56Sopenharmony_cistatic const int _days_in_month[] = {
2137db96d56Sopenharmony_ci    0, /* unused; this vector uses 1-based indexing */
2147db96d56Sopenharmony_ci    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
2157db96d56Sopenharmony_ci};
2167db96d56Sopenharmony_ci
2177db96d56Sopenharmony_cistatic const int _days_before_month[] = {
2187db96d56Sopenharmony_ci    0, /* unused; this vector uses 1-based indexing */
2197db96d56Sopenharmony_ci    0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
2207db96d56Sopenharmony_ci};
2217db96d56Sopenharmony_ci
2227db96d56Sopenharmony_ci/* year -> 1 if leap year, else 0. */
2237db96d56Sopenharmony_cistatic int
2247db96d56Sopenharmony_ciis_leap(int year)
2257db96d56Sopenharmony_ci{
2267db96d56Sopenharmony_ci    /* Cast year to unsigned.  The result is the same either way, but
2277db96d56Sopenharmony_ci     * C can generate faster code for unsigned mod than for signed
2287db96d56Sopenharmony_ci     * mod (especially for % 4 -- a good compiler should just grab
2297db96d56Sopenharmony_ci     * the last 2 bits when the LHS is unsigned).
2307db96d56Sopenharmony_ci     */
2317db96d56Sopenharmony_ci    const unsigned int ayear = (unsigned int)year;
2327db96d56Sopenharmony_ci    return ayear % 4 == 0 && (ayear % 100 != 0 || ayear % 400 == 0);
2337db96d56Sopenharmony_ci}
2347db96d56Sopenharmony_ci
2357db96d56Sopenharmony_ci/* year, month -> number of days in that month in that year */
2367db96d56Sopenharmony_cistatic int
2377db96d56Sopenharmony_cidays_in_month(int year, int month)
2387db96d56Sopenharmony_ci{
2397db96d56Sopenharmony_ci    assert(month >= 1);
2407db96d56Sopenharmony_ci    assert(month <= 12);
2417db96d56Sopenharmony_ci    if (month == 2 && is_leap(year))
2427db96d56Sopenharmony_ci        return 29;
2437db96d56Sopenharmony_ci    else
2447db96d56Sopenharmony_ci        return _days_in_month[month];
2457db96d56Sopenharmony_ci}
2467db96d56Sopenharmony_ci
2477db96d56Sopenharmony_ci/* year, month -> number of days in year preceding first day of month */
2487db96d56Sopenharmony_cistatic int
2497db96d56Sopenharmony_cidays_before_month(int year, int month)
2507db96d56Sopenharmony_ci{
2517db96d56Sopenharmony_ci    int days;
2527db96d56Sopenharmony_ci
2537db96d56Sopenharmony_ci    assert(month >= 1);
2547db96d56Sopenharmony_ci    assert(month <= 12);
2557db96d56Sopenharmony_ci    days = _days_before_month[month];
2567db96d56Sopenharmony_ci    if (month > 2 && is_leap(year))
2577db96d56Sopenharmony_ci        ++days;
2587db96d56Sopenharmony_ci    return days;
2597db96d56Sopenharmony_ci}
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ci/* year -> number of days before January 1st of year.  Remember that we
2627db96d56Sopenharmony_ci * start with year 1, so days_before_year(1) == 0.
2637db96d56Sopenharmony_ci */
2647db96d56Sopenharmony_cistatic int
2657db96d56Sopenharmony_cidays_before_year(int year)
2667db96d56Sopenharmony_ci{
2677db96d56Sopenharmony_ci    int y = year - 1;
2687db96d56Sopenharmony_ci    /* This is incorrect if year <= 0; we really want the floor
2697db96d56Sopenharmony_ci     * here.  But so long as MINYEAR is 1, the smallest year this
2707db96d56Sopenharmony_ci     * can see is 1.
2717db96d56Sopenharmony_ci     */
2727db96d56Sopenharmony_ci    assert (year >= 1);
2737db96d56Sopenharmony_ci    return y*365 + y/4 - y/100 + y/400;
2747db96d56Sopenharmony_ci}
2757db96d56Sopenharmony_ci
2767db96d56Sopenharmony_ci/* Number of days in 4, 100, and 400 year cycles.  That these have
2777db96d56Sopenharmony_ci * the correct values is asserted in the module init function.
2787db96d56Sopenharmony_ci */
2797db96d56Sopenharmony_ci#define DI4Y    1461    /* days_before_year(5); days in 4 years */
2807db96d56Sopenharmony_ci#define DI100Y  36524   /* days_before_year(101); days in 100 years */
2817db96d56Sopenharmony_ci#define DI400Y  146097  /* days_before_year(401); days in 400 years  */
2827db96d56Sopenharmony_ci
2837db96d56Sopenharmony_ci/* ordinal -> year, month, day, considering 01-Jan-0001 as day 1. */
2847db96d56Sopenharmony_cistatic void
2857db96d56Sopenharmony_ciord_to_ymd(int ordinal, int *year, int *month, int *day)
2867db96d56Sopenharmony_ci{
2877db96d56Sopenharmony_ci    int n, n1, n4, n100, n400, leapyear, preceding;
2887db96d56Sopenharmony_ci
2897db96d56Sopenharmony_ci    /* ordinal is a 1-based index, starting at 1-Jan-1.  The pattern of
2907db96d56Sopenharmony_ci     * leap years repeats exactly every 400 years.  The basic strategy is
2917db96d56Sopenharmony_ci     * to find the closest 400-year boundary at or before ordinal, then
2927db96d56Sopenharmony_ci     * work with the offset from that boundary to ordinal.  Life is much
2937db96d56Sopenharmony_ci     * clearer if we subtract 1 from ordinal first -- then the values
2947db96d56Sopenharmony_ci     * of ordinal at 400-year boundaries are exactly those divisible
2957db96d56Sopenharmony_ci     * by DI400Y:
2967db96d56Sopenharmony_ci     *
2977db96d56Sopenharmony_ci     *    D  M   Y            n              n-1
2987db96d56Sopenharmony_ci     *    -- --- ----        ----------     ----------------
2997db96d56Sopenharmony_ci     *    31 Dec -400        -DI400Y       -DI400Y -1
3007db96d56Sopenharmony_ci     *     1 Jan -399         -DI400Y +1   -DI400Y      400-year boundary
3017db96d56Sopenharmony_ci     *    ...
3027db96d56Sopenharmony_ci     *    30 Dec  000        -1             -2
3037db96d56Sopenharmony_ci     *    31 Dec  000         0             -1
3047db96d56Sopenharmony_ci     *     1 Jan  001         1              0          400-year boundary
3057db96d56Sopenharmony_ci     *     2 Jan  001         2              1
3067db96d56Sopenharmony_ci     *     3 Jan  001         3              2
3077db96d56Sopenharmony_ci     *    ...
3087db96d56Sopenharmony_ci     *    31 Dec  400         DI400Y        DI400Y -1
3097db96d56Sopenharmony_ci     *     1 Jan  401         DI400Y +1     DI400Y      400-year boundary
3107db96d56Sopenharmony_ci     */
3117db96d56Sopenharmony_ci    assert(ordinal >= 1);
3127db96d56Sopenharmony_ci    --ordinal;
3137db96d56Sopenharmony_ci    n400 = ordinal / DI400Y;
3147db96d56Sopenharmony_ci    n = ordinal % DI400Y;
3157db96d56Sopenharmony_ci    *year = n400 * 400 + 1;
3167db96d56Sopenharmony_ci
3177db96d56Sopenharmony_ci    /* Now n is the (non-negative) offset, in days, from January 1 of
3187db96d56Sopenharmony_ci     * year, to the desired date.  Now compute how many 100-year cycles
3197db96d56Sopenharmony_ci     * precede n.
3207db96d56Sopenharmony_ci     * Note that it's possible for n100 to equal 4!  In that case 4 full
3217db96d56Sopenharmony_ci     * 100-year cycles precede the desired day, which implies the
3227db96d56Sopenharmony_ci     * desired day is December 31 at the end of a 400-year cycle.
3237db96d56Sopenharmony_ci     */
3247db96d56Sopenharmony_ci    n100 = n / DI100Y;
3257db96d56Sopenharmony_ci    n = n % DI100Y;
3267db96d56Sopenharmony_ci
3277db96d56Sopenharmony_ci    /* Now compute how many 4-year cycles precede it. */
3287db96d56Sopenharmony_ci    n4 = n / DI4Y;
3297db96d56Sopenharmony_ci    n = n % DI4Y;
3307db96d56Sopenharmony_ci
3317db96d56Sopenharmony_ci    /* And now how many single years.  Again n1 can be 4, and again
3327db96d56Sopenharmony_ci     * meaning that the desired day is December 31 at the end of the
3337db96d56Sopenharmony_ci     * 4-year cycle.
3347db96d56Sopenharmony_ci     */
3357db96d56Sopenharmony_ci    n1 = n / 365;
3367db96d56Sopenharmony_ci    n = n % 365;
3377db96d56Sopenharmony_ci
3387db96d56Sopenharmony_ci    *year += n100 * 100 + n4 * 4 + n1;
3397db96d56Sopenharmony_ci    if (n1 == 4 || n100 == 4) {
3407db96d56Sopenharmony_ci        assert(n == 0);
3417db96d56Sopenharmony_ci        *year -= 1;
3427db96d56Sopenharmony_ci        *month = 12;
3437db96d56Sopenharmony_ci        *day = 31;
3447db96d56Sopenharmony_ci        return;
3457db96d56Sopenharmony_ci    }
3467db96d56Sopenharmony_ci
3477db96d56Sopenharmony_ci    /* Now the year is correct, and n is the offset from January 1.  We
3487db96d56Sopenharmony_ci     * find the month via an estimate that's either exact or one too
3497db96d56Sopenharmony_ci     * large.
3507db96d56Sopenharmony_ci     */
3517db96d56Sopenharmony_ci    leapyear = n1 == 3 && (n4 != 24 || n100 == 3);
3527db96d56Sopenharmony_ci    assert(leapyear == is_leap(*year));
3537db96d56Sopenharmony_ci    *month = (n + 50) >> 5;
3547db96d56Sopenharmony_ci    preceding = (_days_before_month[*month] + (*month > 2 && leapyear));
3557db96d56Sopenharmony_ci    if (preceding > n) {
3567db96d56Sopenharmony_ci        /* estimate is too large */
3577db96d56Sopenharmony_ci        *month -= 1;
3587db96d56Sopenharmony_ci        preceding -= days_in_month(*year, *month);
3597db96d56Sopenharmony_ci    }
3607db96d56Sopenharmony_ci    n -= preceding;
3617db96d56Sopenharmony_ci    assert(0 <= n);
3627db96d56Sopenharmony_ci    assert(n < days_in_month(*year, *month));
3637db96d56Sopenharmony_ci
3647db96d56Sopenharmony_ci    *day = n + 1;
3657db96d56Sopenharmony_ci}
3667db96d56Sopenharmony_ci
3677db96d56Sopenharmony_ci/* year, month, day -> ordinal, considering 01-Jan-0001 as day 1. */
3687db96d56Sopenharmony_cistatic int
3697db96d56Sopenharmony_ciymd_to_ord(int year, int month, int day)
3707db96d56Sopenharmony_ci{
3717db96d56Sopenharmony_ci    return days_before_year(year) + days_before_month(year, month) + day;
3727db96d56Sopenharmony_ci}
3737db96d56Sopenharmony_ci
3747db96d56Sopenharmony_ci/* Day of week, where Monday==0, ..., Sunday==6.  1/1/1 was a Monday. */
3757db96d56Sopenharmony_cistatic int
3767db96d56Sopenharmony_ciweekday(int year, int month, int day)
3777db96d56Sopenharmony_ci{
3787db96d56Sopenharmony_ci    return (ymd_to_ord(year, month, day) + 6) % 7;
3797db96d56Sopenharmony_ci}
3807db96d56Sopenharmony_ci
3817db96d56Sopenharmony_ci/* Ordinal of the Monday starting week 1 of the ISO year.  Week 1 is the
3827db96d56Sopenharmony_ci * first calendar week containing a Thursday.
3837db96d56Sopenharmony_ci */
3847db96d56Sopenharmony_cistatic int
3857db96d56Sopenharmony_ciiso_week1_monday(int year)
3867db96d56Sopenharmony_ci{
3877db96d56Sopenharmony_ci    int first_day = ymd_to_ord(year, 1, 1);     /* ord of 1/1 */
3887db96d56Sopenharmony_ci    /* 0 if 1/1 is a Monday, 1 if a Tue, etc. */
3897db96d56Sopenharmony_ci    int first_weekday = (first_day + 6) % 7;
3907db96d56Sopenharmony_ci    /* ordinal of closest Monday at or before 1/1 */
3917db96d56Sopenharmony_ci    int week1_monday  = first_day - first_weekday;
3927db96d56Sopenharmony_ci
3937db96d56Sopenharmony_ci    if (first_weekday > 3)      /* if 1/1 was Fri, Sat, Sun */
3947db96d56Sopenharmony_ci        week1_monday += 7;
3957db96d56Sopenharmony_ci    return week1_monday;
3967db96d56Sopenharmony_ci}
3977db96d56Sopenharmony_ci
3987db96d56Sopenharmony_cistatic int
3997db96d56Sopenharmony_ciiso_to_ymd(const int iso_year, const int iso_week, const int iso_day,
4007db96d56Sopenharmony_ci           int *year, int *month, int *day) {
4017db96d56Sopenharmony_ci    if (iso_week <= 0 || iso_week >= 53) {
4027db96d56Sopenharmony_ci        int out_of_range = 1;
4037db96d56Sopenharmony_ci        if (iso_week == 53) {
4047db96d56Sopenharmony_ci            // ISO years have 53 weeks in it on years starting with a Thursday
4057db96d56Sopenharmony_ci            // and on leap years starting on Wednesday
4067db96d56Sopenharmony_ci            int first_weekday = weekday(iso_year, 1, 1);
4077db96d56Sopenharmony_ci            if (first_weekday == 3 || (first_weekday == 2 && is_leap(iso_year))) {
4087db96d56Sopenharmony_ci                out_of_range = 0;
4097db96d56Sopenharmony_ci            }
4107db96d56Sopenharmony_ci        }
4117db96d56Sopenharmony_ci
4127db96d56Sopenharmony_ci        if (out_of_range) {
4137db96d56Sopenharmony_ci            return -2;
4147db96d56Sopenharmony_ci        }
4157db96d56Sopenharmony_ci    }
4167db96d56Sopenharmony_ci
4177db96d56Sopenharmony_ci    if (iso_day <= 0 || iso_day >= 8) {
4187db96d56Sopenharmony_ci        return -3;
4197db96d56Sopenharmony_ci    }
4207db96d56Sopenharmony_ci
4217db96d56Sopenharmony_ci    // Convert (Y, W, D) to (Y, M, D) in-place
4227db96d56Sopenharmony_ci    int day_1 = iso_week1_monday(iso_year);
4237db96d56Sopenharmony_ci
4247db96d56Sopenharmony_ci    int day_offset = (iso_week - 1)*7 + iso_day - 1;
4257db96d56Sopenharmony_ci
4267db96d56Sopenharmony_ci    ord_to_ymd(day_1 + day_offset, year, month, day);
4277db96d56Sopenharmony_ci    return 0;
4287db96d56Sopenharmony_ci}
4297db96d56Sopenharmony_ci
4307db96d56Sopenharmony_ci
4317db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
4327db96d56Sopenharmony_ci * Range checkers.
4337db96d56Sopenharmony_ci */
4347db96d56Sopenharmony_ci
4357db96d56Sopenharmony_ci/* Check that -MAX_DELTA_DAYS <= days <= MAX_DELTA_DAYS.  If so, return 0.
4367db96d56Sopenharmony_ci * If not, raise OverflowError and return -1.
4377db96d56Sopenharmony_ci */
4387db96d56Sopenharmony_cistatic int
4397db96d56Sopenharmony_cicheck_delta_day_range(int days)
4407db96d56Sopenharmony_ci{
4417db96d56Sopenharmony_ci    if (-MAX_DELTA_DAYS <= days && days <= MAX_DELTA_DAYS)
4427db96d56Sopenharmony_ci        return 0;
4437db96d56Sopenharmony_ci    PyErr_Format(PyExc_OverflowError,
4447db96d56Sopenharmony_ci                 "days=%d; must have magnitude <= %d",
4457db96d56Sopenharmony_ci                 days, MAX_DELTA_DAYS);
4467db96d56Sopenharmony_ci    return -1;
4477db96d56Sopenharmony_ci}
4487db96d56Sopenharmony_ci
4497db96d56Sopenharmony_ci/* Check that date arguments are in range.  Return 0 if they are.  If they
4507db96d56Sopenharmony_ci * aren't, raise ValueError and return -1.
4517db96d56Sopenharmony_ci */
4527db96d56Sopenharmony_cistatic int
4537db96d56Sopenharmony_cicheck_date_args(int year, int month, int day)
4547db96d56Sopenharmony_ci{
4557db96d56Sopenharmony_ci
4567db96d56Sopenharmony_ci    if (year < MINYEAR || year > MAXYEAR) {
4577db96d56Sopenharmony_ci        PyErr_Format(PyExc_ValueError, "year %i is out of range", year);
4587db96d56Sopenharmony_ci        return -1;
4597db96d56Sopenharmony_ci    }
4607db96d56Sopenharmony_ci    if (month < 1 || month > 12) {
4617db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
4627db96d56Sopenharmony_ci                        "month must be in 1..12");
4637db96d56Sopenharmony_ci        return -1;
4647db96d56Sopenharmony_ci    }
4657db96d56Sopenharmony_ci    if (day < 1 || day > days_in_month(year, month)) {
4667db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
4677db96d56Sopenharmony_ci                        "day is out of range for month");
4687db96d56Sopenharmony_ci        return -1;
4697db96d56Sopenharmony_ci    }
4707db96d56Sopenharmony_ci    return 0;
4717db96d56Sopenharmony_ci}
4727db96d56Sopenharmony_ci
4737db96d56Sopenharmony_ci/* Check that time arguments are in range.  Return 0 if they are.  If they
4747db96d56Sopenharmony_ci * aren't, raise ValueError and return -1.
4757db96d56Sopenharmony_ci */
4767db96d56Sopenharmony_cistatic int
4777db96d56Sopenharmony_cicheck_time_args(int h, int m, int s, int us, int fold)
4787db96d56Sopenharmony_ci{
4797db96d56Sopenharmony_ci    if (h < 0 || h > 23) {
4807db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
4817db96d56Sopenharmony_ci                        "hour must be in 0..23");
4827db96d56Sopenharmony_ci        return -1;
4837db96d56Sopenharmony_ci    }
4847db96d56Sopenharmony_ci    if (m < 0 || m > 59) {
4857db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
4867db96d56Sopenharmony_ci                        "minute must be in 0..59");
4877db96d56Sopenharmony_ci        return -1;
4887db96d56Sopenharmony_ci    }
4897db96d56Sopenharmony_ci    if (s < 0 || s > 59) {
4907db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
4917db96d56Sopenharmony_ci                        "second must be in 0..59");
4927db96d56Sopenharmony_ci        return -1;
4937db96d56Sopenharmony_ci    }
4947db96d56Sopenharmony_ci    if (us < 0 || us > 999999) {
4957db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
4967db96d56Sopenharmony_ci                        "microsecond must be in 0..999999");
4977db96d56Sopenharmony_ci        return -1;
4987db96d56Sopenharmony_ci    }
4997db96d56Sopenharmony_ci    if (fold != 0 && fold != 1) {
5007db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
5017db96d56Sopenharmony_ci                        "fold must be either 0 or 1");
5027db96d56Sopenharmony_ci        return -1;
5037db96d56Sopenharmony_ci    }
5047db96d56Sopenharmony_ci    return 0;
5057db96d56Sopenharmony_ci}
5067db96d56Sopenharmony_ci
5077db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
5087db96d56Sopenharmony_ci * Normalization utilities.
5097db96d56Sopenharmony_ci */
5107db96d56Sopenharmony_ci
5117db96d56Sopenharmony_ci/* One step of a mixed-radix conversion.  A "hi" unit is equivalent to
5127db96d56Sopenharmony_ci * factor "lo" units.  factor must be > 0.  If *lo is less than 0, or
5137db96d56Sopenharmony_ci * at least factor, enough of *lo is converted into "hi" units so that
5147db96d56Sopenharmony_ci * 0 <= *lo < factor.  The input values must be such that int overflow
5157db96d56Sopenharmony_ci * is impossible.
5167db96d56Sopenharmony_ci */
5177db96d56Sopenharmony_cistatic void
5187db96d56Sopenharmony_cinormalize_pair(int *hi, int *lo, int factor)
5197db96d56Sopenharmony_ci{
5207db96d56Sopenharmony_ci    assert(factor > 0);
5217db96d56Sopenharmony_ci    assert(lo != hi);
5227db96d56Sopenharmony_ci    if (*lo < 0 || *lo >= factor) {
5237db96d56Sopenharmony_ci        const int num_hi = divmod(*lo, factor, lo);
5247db96d56Sopenharmony_ci        const int new_hi = *hi + num_hi;
5257db96d56Sopenharmony_ci        assert(! SIGNED_ADD_OVERFLOWED(new_hi, *hi, num_hi));
5267db96d56Sopenharmony_ci        *hi = new_hi;
5277db96d56Sopenharmony_ci    }
5287db96d56Sopenharmony_ci    assert(0 <= *lo && *lo < factor);
5297db96d56Sopenharmony_ci}
5307db96d56Sopenharmony_ci
5317db96d56Sopenharmony_ci/* Fiddle days (d), seconds (s), and microseconds (us) so that
5327db96d56Sopenharmony_ci *      0 <= *s < 24*3600
5337db96d56Sopenharmony_ci *      0 <= *us < 1000000
5347db96d56Sopenharmony_ci * The input values must be such that the internals don't overflow.
5357db96d56Sopenharmony_ci * The way this routine is used, we don't get close.
5367db96d56Sopenharmony_ci */
5377db96d56Sopenharmony_cistatic void
5387db96d56Sopenharmony_cinormalize_d_s_us(int *d, int *s, int *us)
5397db96d56Sopenharmony_ci{
5407db96d56Sopenharmony_ci    if (*us < 0 || *us >= 1000000) {
5417db96d56Sopenharmony_ci        normalize_pair(s, us, 1000000);
5427db96d56Sopenharmony_ci        /* |s| can't be bigger than about
5437db96d56Sopenharmony_ci         * |original s| + |original us|/1000000 now.
5447db96d56Sopenharmony_ci         */
5457db96d56Sopenharmony_ci
5467db96d56Sopenharmony_ci    }
5477db96d56Sopenharmony_ci    if (*s < 0 || *s >= 24*3600) {
5487db96d56Sopenharmony_ci        normalize_pair(d, s, 24*3600);
5497db96d56Sopenharmony_ci        /* |d| can't be bigger than about
5507db96d56Sopenharmony_ci         * |original d| +
5517db96d56Sopenharmony_ci         * (|original s| + |original us|/1000000) / (24*3600) now.
5527db96d56Sopenharmony_ci         */
5537db96d56Sopenharmony_ci    }
5547db96d56Sopenharmony_ci    assert(0 <= *s && *s < 24*3600);
5557db96d56Sopenharmony_ci    assert(0 <= *us && *us < 1000000);
5567db96d56Sopenharmony_ci}
5577db96d56Sopenharmony_ci
5587db96d56Sopenharmony_ci/* Fiddle years (y), months (m), and days (d) so that
5597db96d56Sopenharmony_ci *      1 <= *m <= 12
5607db96d56Sopenharmony_ci *      1 <= *d <= days_in_month(*y, *m)
5617db96d56Sopenharmony_ci * The input values must be such that the internals don't overflow.
5627db96d56Sopenharmony_ci * The way this routine is used, we don't get close.
5637db96d56Sopenharmony_ci */
5647db96d56Sopenharmony_cistatic int
5657db96d56Sopenharmony_cinormalize_y_m_d(int *y, int *m, int *d)
5667db96d56Sopenharmony_ci{
5677db96d56Sopenharmony_ci    int dim;            /* # of days in month */
5687db96d56Sopenharmony_ci
5697db96d56Sopenharmony_ci    /* In actual use, m is always the month component extracted from a
5707db96d56Sopenharmony_ci     * date/datetime object.  Therefore it is always in [1, 12] range.
5717db96d56Sopenharmony_ci     */
5727db96d56Sopenharmony_ci
5737db96d56Sopenharmony_ci    assert(1 <= *m && *m <= 12);
5747db96d56Sopenharmony_ci
5757db96d56Sopenharmony_ci    /* Now only day can be out of bounds (year may also be out of bounds
5767db96d56Sopenharmony_ci     * for a datetime object, but we don't care about that here).
5777db96d56Sopenharmony_ci     * If day is out of bounds, what to do is arguable, but at least the
5787db96d56Sopenharmony_ci     * method here is principled and explainable.
5797db96d56Sopenharmony_ci     */
5807db96d56Sopenharmony_ci    dim = days_in_month(*y, *m);
5817db96d56Sopenharmony_ci    if (*d < 1 || *d > dim) {
5827db96d56Sopenharmony_ci        /* Move day-1 days from the first of the month.  First try to
5837db96d56Sopenharmony_ci         * get off cheap if we're only one day out of range
5847db96d56Sopenharmony_ci         * (adjustments for timezone alone can't be worse than that).
5857db96d56Sopenharmony_ci         */
5867db96d56Sopenharmony_ci        if (*d == 0) {
5877db96d56Sopenharmony_ci            --*m;
5887db96d56Sopenharmony_ci            if (*m > 0)
5897db96d56Sopenharmony_ci                *d = days_in_month(*y, *m);
5907db96d56Sopenharmony_ci            else {
5917db96d56Sopenharmony_ci                --*y;
5927db96d56Sopenharmony_ci                *m = 12;
5937db96d56Sopenharmony_ci                *d = 31;
5947db96d56Sopenharmony_ci            }
5957db96d56Sopenharmony_ci        }
5967db96d56Sopenharmony_ci        else if (*d == dim + 1) {
5977db96d56Sopenharmony_ci            /* move forward a day */
5987db96d56Sopenharmony_ci            ++*m;
5997db96d56Sopenharmony_ci            *d = 1;
6007db96d56Sopenharmony_ci            if (*m > 12) {
6017db96d56Sopenharmony_ci                *m = 1;
6027db96d56Sopenharmony_ci                ++*y;
6037db96d56Sopenharmony_ci            }
6047db96d56Sopenharmony_ci        }
6057db96d56Sopenharmony_ci        else {
6067db96d56Sopenharmony_ci            int ordinal = ymd_to_ord(*y, *m, 1) +
6077db96d56Sopenharmony_ci                                      *d - 1;
6087db96d56Sopenharmony_ci            if (ordinal < 1 || ordinal > MAXORDINAL) {
6097db96d56Sopenharmony_ci                goto error;
6107db96d56Sopenharmony_ci            } else {
6117db96d56Sopenharmony_ci                ord_to_ymd(ordinal, y, m, d);
6127db96d56Sopenharmony_ci                return 0;
6137db96d56Sopenharmony_ci            }
6147db96d56Sopenharmony_ci        }
6157db96d56Sopenharmony_ci    }
6167db96d56Sopenharmony_ci    assert(*m > 0);
6177db96d56Sopenharmony_ci    assert(*d > 0);
6187db96d56Sopenharmony_ci    if (MINYEAR <= *y && *y <= MAXYEAR)
6197db96d56Sopenharmony_ci        return 0;
6207db96d56Sopenharmony_ci error:
6217db96d56Sopenharmony_ci    PyErr_SetString(PyExc_OverflowError,
6227db96d56Sopenharmony_ci            "date value out of range");
6237db96d56Sopenharmony_ci    return -1;
6247db96d56Sopenharmony_ci
6257db96d56Sopenharmony_ci}
6267db96d56Sopenharmony_ci
6277db96d56Sopenharmony_ci/* Fiddle out-of-bounds months and days so that the result makes some kind
6287db96d56Sopenharmony_ci * of sense.  The parameters are both inputs and outputs.  Returns < 0 on
6297db96d56Sopenharmony_ci * failure, where failure means the adjusted year is out of bounds.
6307db96d56Sopenharmony_ci */
6317db96d56Sopenharmony_cistatic int
6327db96d56Sopenharmony_cinormalize_date(int *year, int *month, int *day)
6337db96d56Sopenharmony_ci{
6347db96d56Sopenharmony_ci    return normalize_y_m_d(year, month, day);
6357db96d56Sopenharmony_ci}
6367db96d56Sopenharmony_ci
6377db96d56Sopenharmony_ci/* Force all the datetime fields into range.  The parameters are both
6387db96d56Sopenharmony_ci * inputs and outputs.  Returns < 0 on error.
6397db96d56Sopenharmony_ci */
6407db96d56Sopenharmony_cistatic int
6417db96d56Sopenharmony_cinormalize_datetime(int *year, int *month, int *day,
6427db96d56Sopenharmony_ci                   int *hour, int *minute, int *second,
6437db96d56Sopenharmony_ci                   int *microsecond)
6447db96d56Sopenharmony_ci{
6457db96d56Sopenharmony_ci    normalize_pair(second, microsecond, 1000000);
6467db96d56Sopenharmony_ci    normalize_pair(minute, second, 60);
6477db96d56Sopenharmony_ci    normalize_pair(hour, minute, 60);
6487db96d56Sopenharmony_ci    normalize_pair(day, hour, 24);
6497db96d56Sopenharmony_ci    return normalize_date(year, month, day);
6507db96d56Sopenharmony_ci}
6517db96d56Sopenharmony_ci
6527db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
6537db96d56Sopenharmony_ci * Basic object allocation:  tp_alloc implementations.  These allocate
6547db96d56Sopenharmony_ci * Python objects of the right size and type, and do the Python object-
6557db96d56Sopenharmony_ci * initialization bit.  If there's not enough memory, they return NULL after
6567db96d56Sopenharmony_ci * setting MemoryError.  All data members remain uninitialized trash.
6577db96d56Sopenharmony_ci *
6587db96d56Sopenharmony_ci * We abuse the tp_alloc "nitems" argument to communicate whether a tzinfo
6597db96d56Sopenharmony_ci * member is needed.  This is ugly, imprecise, and possibly insecure.
6607db96d56Sopenharmony_ci * tp_basicsize for the time and datetime types is set to the size of the
6617db96d56Sopenharmony_ci * struct that has room for the tzinfo member, so subclasses in Python will
6627db96d56Sopenharmony_ci * allocate enough space for a tzinfo member whether or not one is actually
6637db96d56Sopenharmony_ci * needed.  That's the "ugly and imprecise" parts.  The "possibly insecure"
6647db96d56Sopenharmony_ci * part is that PyType_GenericAlloc() (which subclasses in Python end up
6657db96d56Sopenharmony_ci * using) just happens today to effectively ignore the nitems argument
6667db96d56Sopenharmony_ci * when tp_itemsize is 0, which it is for these type objects.  If that
6677db96d56Sopenharmony_ci * changes, perhaps the callers of tp_alloc slots in this file should
6687db96d56Sopenharmony_ci * be changed to force a 0 nitems argument unless the type being allocated
6697db96d56Sopenharmony_ci * is a base type implemented in this file (so that tp_alloc is time_alloc
6707db96d56Sopenharmony_ci * or datetime_alloc below, which know about the nitems abuse).
6717db96d56Sopenharmony_ci */
6727db96d56Sopenharmony_ci
6737db96d56Sopenharmony_cistatic PyObject *
6747db96d56Sopenharmony_citime_alloc(PyTypeObject *type, Py_ssize_t aware)
6757db96d56Sopenharmony_ci{
6767db96d56Sopenharmony_ci    size_t size = aware ? sizeof(PyDateTime_Time) : sizeof(_PyDateTime_BaseTime);
6777db96d56Sopenharmony_ci    PyObject *self = (PyObject *)PyObject_Malloc(size);
6787db96d56Sopenharmony_ci    if (self == NULL) {
6797db96d56Sopenharmony_ci        return PyErr_NoMemory();
6807db96d56Sopenharmony_ci    }
6817db96d56Sopenharmony_ci    _PyObject_Init(self, type);
6827db96d56Sopenharmony_ci    return self;
6837db96d56Sopenharmony_ci}
6847db96d56Sopenharmony_ci
6857db96d56Sopenharmony_cistatic PyObject *
6867db96d56Sopenharmony_cidatetime_alloc(PyTypeObject *type, Py_ssize_t aware)
6877db96d56Sopenharmony_ci{
6887db96d56Sopenharmony_ci    size_t size = aware ? sizeof(PyDateTime_DateTime) : sizeof(_PyDateTime_BaseDateTime);
6897db96d56Sopenharmony_ci    PyObject *self = (PyObject *)PyObject_Malloc(size);
6907db96d56Sopenharmony_ci    if (self == NULL) {
6917db96d56Sopenharmony_ci        return PyErr_NoMemory();
6927db96d56Sopenharmony_ci    }
6937db96d56Sopenharmony_ci    _PyObject_Init(self, type);
6947db96d56Sopenharmony_ci    return self;
6957db96d56Sopenharmony_ci}
6967db96d56Sopenharmony_ci
6977db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
6987db96d56Sopenharmony_ci * Helpers for setting object fields.  These work on pointers to the
6997db96d56Sopenharmony_ci * appropriate base class.
7007db96d56Sopenharmony_ci */
7017db96d56Sopenharmony_ci
7027db96d56Sopenharmony_ci/* For date and datetime. */
7037db96d56Sopenharmony_cistatic void
7047db96d56Sopenharmony_ciset_date_fields(PyDateTime_Date *self, int y, int m, int d)
7057db96d56Sopenharmony_ci{
7067db96d56Sopenharmony_ci    self->hashcode = -1;
7077db96d56Sopenharmony_ci    SET_YEAR(self, y);
7087db96d56Sopenharmony_ci    SET_MONTH(self, m);
7097db96d56Sopenharmony_ci    SET_DAY(self, d);
7107db96d56Sopenharmony_ci}
7117db96d56Sopenharmony_ci
7127db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
7137db96d56Sopenharmony_ci * String parsing utilities and helper functions
7147db96d56Sopenharmony_ci */
7157db96d56Sopenharmony_ci
7167db96d56Sopenharmony_cistatic unsigned char
7177db96d56Sopenharmony_ciis_digit(const char c) {
7187db96d56Sopenharmony_ci    return ((unsigned int)(c - '0')) < 10;
7197db96d56Sopenharmony_ci}
7207db96d56Sopenharmony_ci
7217db96d56Sopenharmony_cistatic const char *
7227db96d56Sopenharmony_ciparse_digits(const char *ptr, int *var, size_t num_digits)
7237db96d56Sopenharmony_ci{
7247db96d56Sopenharmony_ci    for (size_t i = 0; i < num_digits; ++i) {
7257db96d56Sopenharmony_ci        unsigned int tmp = (unsigned int)(*(ptr++) - '0');
7267db96d56Sopenharmony_ci        if (tmp > 9) {
7277db96d56Sopenharmony_ci            return NULL;
7287db96d56Sopenharmony_ci        }
7297db96d56Sopenharmony_ci        *var *= 10;
7307db96d56Sopenharmony_ci        *var += (signed int)tmp;
7317db96d56Sopenharmony_ci    }
7327db96d56Sopenharmony_ci
7337db96d56Sopenharmony_ci    return ptr;
7347db96d56Sopenharmony_ci}
7357db96d56Sopenharmony_ci
7367db96d56Sopenharmony_cistatic int
7377db96d56Sopenharmony_ciparse_isoformat_date(const char *dtstr, const size_t len, int *year, int *month, int *day)
7387db96d56Sopenharmony_ci{
7397db96d56Sopenharmony_ci    /* Parse the date components of the result of date.isoformat()
7407db96d56Sopenharmony_ci     *
7417db96d56Sopenharmony_ci     *  Return codes:
7427db96d56Sopenharmony_ci     *       0:  Success
7437db96d56Sopenharmony_ci     *      -1:  Failed to parse date component
7447db96d56Sopenharmony_ci     *      -2:  Inconsistent date separator usage
7457db96d56Sopenharmony_ci     *      -3:  Failed to parse ISO week.
7467db96d56Sopenharmony_ci     *      -4:  Failed to parse ISO day.
7477db96d56Sopenharmony_ci     *      -5, -6: Failure in iso_to_ymd
7487db96d56Sopenharmony_ci     */
7497db96d56Sopenharmony_ci    const char *p = dtstr;
7507db96d56Sopenharmony_ci    p = parse_digits(p, year, 4);
7517db96d56Sopenharmony_ci    if (NULL == p) {
7527db96d56Sopenharmony_ci        return -1;
7537db96d56Sopenharmony_ci    }
7547db96d56Sopenharmony_ci
7557db96d56Sopenharmony_ci    const unsigned char uses_separator = (*p == '-');
7567db96d56Sopenharmony_ci    if (uses_separator) {
7577db96d56Sopenharmony_ci        ++p;
7587db96d56Sopenharmony_ci    }
7597db96d56Sopenharmony_ci
7607db96d56Sopenharmony_ci    if(*p == 'W') {
7617db96d56Sopenharmony_ci        // This is an isocalendar-style date string
7627db96d56Sopenharmony_ci        p++;
7637db96d56Sopenharmony_ci        int iso_week = 0;
7647db96d56Sopenharmony_ci        int iso_day = 0;
7657db96d56Sopenharmony_ci
7667db96d56Sopenharmony_ci        p = parse_digits(p, &iso_week, 2);
7677db96d56Sopenharmony_ci        if (NULL == p) {
7687db96d56Sopenharmony_ci            return -3;
7697db96d56Sopenharmony_ci        }
7707db96d56Sopenharmony_ci
7717db96d56Sopenharmony_ci        assert(p > dtstr);
7727db96d56Sopenharmony_ci        if ((size_t)(p - dtstr) < len) {
7737db96d56Sopenharmony_ci            if (uses_separator && *(p++) != '-') {
7747db96d56Sopenharmony_ci                return -2;
7757db96d56Sopenharmony_ci            }
7767db96d56Sopenharmony_ci
7777db96d56Sopenharmony_ci            p = parse_digits(p, &iso_day, 1);
7787db96d56Sopenharmony_ci            if (NULL == p) {
7797db96d56Sopenharmony_ci                return -4;
7807db96d56Sopenharmony_ci            }
7817db96d56Sopenharmony_ci        } else {
7827db96d56Sopenharmony_ci            iso_day = 1;
7837db96d56Sopenharmony_ci        }
7847db96d56Sopenharmony_ci
7857db96d56Sopenharmony_ci        int rv = iso_to_ymd(*year, iso_week, iso_day, year, month, day);
7867db96d56Sopenharmony_ci        if (rv) {
7877db96d56Sopenharmony_ci            return -3 + rv;
7887db96d56Sopenharmony_ci        } else {
7897db96d56Sopenharmony_ci            return 0;
7907db96d56Sopenharmony_ci        }
7917db96d56Sopenharmony_ci    }
7927db96d56Sopenharmony_ci
7937db96d56Sopenharmony_ci    p = parse_digits(p, month, 2);
7947db96d56Sopenharmony_ci    if (NULL == p) {
7957db96d56Sopenharmony_ci        return -1;
7967db96d56Sopenharmony_ci    }
7977db96d56Sopenharmony_ci
7987db96d56Sopenharmony_ci    if (uses_separator && *(p++) != '-') {
7997db96d56Sopenharmony_ci        return -2;
8007db96d56Sopenharmony_ci    }
8017db96d56Sopenharmony_ci    p = parse_digits(p, day, 2);
8027db96d56Sopenharmony_ci    if (p == NULL) {
8037db96d56Sopenharmony_ci        return -1;
8047db96d56Sopenharmony_ci    }
8057db96d56Sopenharmony_ci    return 0;
8067db96d56Sopenharmony_ci}
8077db96d56Sopenharmony_ci
8087db96d56Sopenharmony_cistatic int
8097db96d56Sopenharmony_ciparse_hh_mm_ss_ff(const char *tstr, const char *tstr_end, int *hour,
8107db96d56Sopenharmony_ci                  int *minute, int *second, int *microsecond)
8117db96d56Sopenharmony_ci{
8127db96d56Sopenharmony_ci    *hour = *minute = *second = *microsecond = 0;
8137db96d56Sopenharmony_ci    const char *p = tstr;
8147db96d56Sopenharmony_ci    const char *p_end = tstr_end;
8157db96d56Sopenharmony_ci    int *vals[3] = {hour, minute, second};
8167db96d56Sopenharmony_ci    // This is initialized to satisfy an erroneous compiler warning.
8177db96d56Sopenharmony_ci    unsigned char has_separator = 1;
8187db96d56Sopenharmony_ci
8197db96d56Sopenharmony_ci    // Parse [HH[:?MM[:?SS]]]
8207db96d56Sopenharmony_ci    for (size_t i = 0; i < 3; ++i) {
8217db96d56Sopenharmony_ci        p = parse_digits(p, vals[i], 2);
8227db96d56Sopenharmony_ci        if (NULL == p) {
8237db96d56Sopenharmony_ci            return -3;
8247db96d56Sopenharmony_ci        }
8257db96d56Sopenharmony_ci
8267db96d56Sopenharmony_ci        char c = *(p++);
8277db96d56Sopenharmony_ci        if (i == 0) {
8287db96d56Sopenharmony_ci            has_separator = (c == ':');
8297db96d56Sopenharmony_ci        }
8307db96d56Sopenharmony_ci
8317db96d56Sopenharmony_ci        if (p >= p_end) {
8327db96d56Sopenharmony_ci            return c != '\0';
8337db96d56Sopenharmony_ci        }
8347db96d56Sopenharmony_ci        else if (has_separator && (c == ':')) {
8357db96d56Sopenharmony_ci            continue;
8367db96d56Sopenharmony_ci        }
8377db96d56Sopenharmony_ci        else if (c == '.' || c == ',') {
8387db96d56Sopenharmony_ci            break;
8397db96d56Sopenharmony_ci        } else if (!has_separator) {
8407db96d56Sopenharmony_ci            --p;
8417db96d56Sopenharmony_ci        } else {
8427db96d56Sopenharmony_ci            return -4;  // Malformed time separator
8437db96d56Sopenharmony_ci        }
8447db96d56Sopenharmony_ci    }
8457db96d56Sopenharmony_ci
8467db96d56Sopenharmony_ci    // Parse fractional components
8477db96d56Sopenharmony_ci    size_t len_remains = p_end - p;
8487db96d56Sopenharmony_ci    size_t to_parse = len_remains;
8497db96d56Sopenharmony_ci    if (len_remains >= 6) {
8507db96d56Sopenharmony_ci        to_parse = 6;
8517db96d56Sopenharmony_ci    }
8527db96d56Sopenharmony_ci
8537db96d56Sopenharmony_ci    p = parse_digits(p, microsecond, to_parse);
8547db96d56Sopenharmony_ci    if (NULL == p) {
8557db96d56Sopenharmony_ci        return -3;
8567db96d56Sopenharmony_ci    }
8577db96d56Sopenharmony_ci
8587db96d56Sopenharmony_ci    static int correction[] = {
8597db96d56Sopenharmony_ci        100000, 10000, 1000, 100, 10
8607db96d56Sopenharmony_ci    };
8617db96d56Sopenharmony_ci
8627db96d56Sopenharmony_ci    if (to_parse < 6) {
8637db96d56Sopenharmony_ci        *microsecond *= correction[to_parse-1];
8647db96d56Sopenharmony_ci    }
8657db96d56Sopenharmony_ci
8667db96d56Sopenharmony_ci    while (is_digit(*p)){
8677db96d56Sopenharmony_ci        ++p; // skip truncated digits
8687db96d56Sopenharmony_ci    }
8697db96d56Sopenharmony_ci
8707db96d56Sopenharmony_ci    // Return 1 if it's not the end of the string
8717db96d56Sopenharmony_ci    return *p != '\0';
8727db96d56Sopenharmony_ci}
8737db96d56Sopenharmony_ci
8747db96d56Sopenharmony_cistatic int
8757db96d56Sopenharmony_ciparse_isoformat_time(const char *dtstr, size_t dtlen, int *hour, int *minute,
8767db96d56Sopenharmony_ci                     int *second, int *microsecond, int *tzoffset,
8777db96d56Sopenharmony_ci                     int *tzmicrosecond)
8787db96d56Sopenharmony_ci{
8797db96d56Sopenharmony_ci    // Parse the time portion of a datetime.isoformat() string
8807db96d56Sopenharmony_ci    //
8817db96d56Sopenharmony_ci    // Return codes:
8827db96d56Sopenharmony_ci    //      0:  Success (no tzoffset)
8837db96d56Sopenharmony_ci    //      1:  Success (with tzoffset)
8847db96d56Sopenharmony_ci    //     -3:  Failed to parse time component
8857db96d56Sopenharmony_ci    //     -4:  Failed to parse time separator
8867db96d56Sopenharmony_ci    //     -5:  Malformed timezone string
8877db96d56Sopenharmony_ci
8887db96d56Sopenharmony_ci    const char *p = dtstr;
8897db96d56Sopenharmony_ci    const char *p_end = dtstr + dtlen;
8907db96d56Sopenharmony_ci
8917db96d56Sopenharmony_ci    const char *tzinfo_pos = p;
8927db96d56Sopenharmony_ci    do {
8937db96d56Sopenharmony_ci        if (*tzinfo_pos == 'Z' || *tzinfo_pos == '+' || *tzinfo_pos == '-') {
8947db96d56Sopenharmony_ci            break;
8957db96d56Sopenharmony_ci        }
8967db96d56Sopenharmony_ci    } while (++tzinfo_pos < p_end);
8977db96d56Sopenharmony_ci
8987db96d56Sopenharmony_ci    int rv = parse_hh_mm_ss_ff(dtstr, tzinfo_pos, hour, minute, second,
8997db96d56Sopenharmony_ci                               microsecond);
9007db96d56Sopenharmony_ci
9017db96d56Sopenharmony_ci    if (rv < 0) {
9027db96d56Sopenharmony_ci        return rv;
9037db96d56Sopenharmony_ci    }
9047db96d56Sopenharmony_ci    else if (tzinfo_pos == p_end) {
9057db96d56Sopenharmony_ci        // We know that there's no time zone, so if there's stuff at the
9067db96d56Sopenharmony_ci        // end of the string it's an error.
9077db96d56Sopenharmony_ci        if (rv == 1) {
9087db96d56Sopenharmony_ci            return -5;
9097db96d56Sopenharmony_ci        }
9107db96d56Sopenharmony_ci        else {
9117db96d56Sopenharmony_ci            return 0;
9127db96d56Sopenharmony_ci        }
9137db96d56Sopenharmony_ci    }
9147db96d56Sopenharmony_ci
9157db96d56Sopenharmony_ci    // Special case UTC / Zulu time.
9167db96d56Sopenharmony_ci    if (*tzinfo_pos == 'Z') {
9177db96d56Sopenharmony_ci        *tzoffset = 0;
9187db96d56Sopenharmony_ci        *tzmicrosecond = 0;
9197db96d56Sopenharmony_ci
9207db96d56Sopenharmony_ci        if (*(tzinfo_pos + 1) != '\0') {
9217db96d56Sopenharmony_ci            return -5;
9227db96d56Sopenharmony_ci        } else {
9237db96d56Sopenharmony_ci            return 1;
9247db96d56Sopenharmony_ci        }
9257db96d56Sopenharmony_ci    }
9267db96d56Sopenharmony_ci
9277db96d56Sopenharmony_ci    int tzsign = (*tzinfo_pos == '-') ? -1 : 1;
9287db96d56Sopenharmony_ci    tzinfo_pos++;
9297db96d56Sopenharmony_ci    int tzhour = 0, tzminute = 0, tzsecond = 0;
9307db96d56Sopenharmony_ci    rv = parse_hh_mm_ss_ff(tzinfo_pos, p_end, &tzhour, &tzminute, &tzsecond,
9317db96d56Sopenharmony_ci                           tzmicrosecond);
9327db96d56Sopenharmony_ci
9337db96d56Sopenharmony_ci    *tzoffset = tzsign * ((tzhour * 3600) + (tzminute * 60) + tzsecond);
9347db96d56Sopenharmony_ci    *tzmicrosecond *= tzsign;
9357db96d56Sopenharmony_ci
9367db96d56Sopenharmony_ci    return rv ? -5 : 1;
9377db96d56Sopenharmony_ci}
9387db96d56Sopenharmony_ci
9397db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
9407db96d56Sopenharmony_ci * Create various objects, mostly without range checking.
9417db96d56Sopenharmony_ci */
9427db96d56Sopenharmony_ci
9437db96d56Sopenharmony_ci/* Create a date instance with no range checking. */
9447db96d56Sopenharmony_cistatic PyObject *
9457db96d56Sopenharmony_cinew_date_ex(int year, int month, int day, PyTypeObject *type)
9467db96d56Sopenharmony_ci{
9477db96d56Sopenharmony_ci    PyDateTime_Date *self;
9487db96d56Sopenharmony_ci
9497db96d56Sopenharmony_ci    if (check_date_args(year, month, day) < 0) {
9507db96d56Sopenharmony_ci        return NULL;
9517db96d56Sopenharmony_ci    }
9527db96d56Sopenharmony_ci
9537db96d56Sopenharmony_ci    self = (PyDateTime_Date *)(type->tp_alloc(type, 0));
9547db96d56Sopenharmony_ci    if (self != NULL)
9557db96d56Sopenharmony_ci        set_date_fields(self, year, month, day);
9567db96d56Sopenharmony_ci    return (PyObject *)self;
9577db96d56Sopenharmony_ci}
9587db96d56Sopenharmony_ci
9597db96d56Sopenharmony_ci#define new_date(year, month, day) \
9607db96d56Sopenharmony_ci    new_date_ex(year, month, day, &PyDateTime_DateType)
9617db96d56Sopenharmony_ci
9627db96d56Sopenharmony_ci// Forward declaration
9637db96d56Sopenharmony_cistatic PyObject *
9647db96d56Sopenharmony_cinew_datetime_ex(int, int, int, int, int, int, int, PyObject *, PyTypeObject *);
9657db96d56Sopenharmony_ci
9667db96d56Sopenharmony_ci/* Create date instance with no range checking, or call subclass constructor */
9677db96d56Sopenharmony_cistatic PyObject *
9687db96d56Sopenharmony_cinew_date_subclass_ex(int year, int month, int day, PyObject *cls)
9697db96d56Sopenharmony_ci{
9707db96d56Sopenharmony_ci    PyObject *result;
9717db96d56Sopenharmony_ci    // We have "fast path" constructors for two subclasses: date and datetime
9727db96d56Sopenharmony_ci    if ((PyTypeObject *)cls == &PyDateTime_DateType) {
9737db96d56Sopenharmony_ci        result = new_date_ex(year, month, day, (PyTypeObject *)cls);
9747db96d56Sopenharmony_ci    }
9757db96d56Sopenharmony_ci    else if ((PyTypeObject *)cls == &PyDateTime_DateTimeType) {
9767db96d56Sopenharmony_ci        result = new_datetime_ex(year, month, day, 0, 0, 0, 0, Py_None,
9777db96d56Sopenharmony_ci                                 (PyTypeObject *)cls);
9787db96d56Sopenharmony_ci    }
9797db96d56Sopenharmony_ci    else {
9807db96d56Sopenharmony_ci        result = PyObject_CallFunction(cls, "iii", year, month, day);
9817db96d56Sopenharmony_ci    }
9827db96d56Sopenharmony_ci
9837db96d56Sopenharmony_ci    return result;
9847db96d56Sopenharmony_ci}
9857db96d56Sopenharmony_ci
9867db96d56Sopenharmony_ci/* Create a datetime instance with no range checking. */
9877db96d56Sopenharmony_cistatic PyObject *
9887db96d56Sopenharmony_cinew_datetime_ex2(int year, int month, int day, int hour, int minute,
9897db96d56Sopenharmony_ci                 int second, int usecond, PyObject *tzinfo, int fold, PyTypeObject *type)
9907db96d56Sopenharmony_ci{
9917db96d56Sopenharmony_ci    PyDateTime_DateTime *self;
9927db96d56Sopenharmony_ci    char aware = tzinfo != Py_None;
9937db96d56Sopenharmony_ci
9947db96d56Sopenharmony_ci    if (check_date_args(year, month, day) < 0) {
9957db96d56Sopenharmony_ci        return NULL;
9967db96d56Sopenharmony_ci    }
9977db96d56Sopenharmony_ci    if (check_time_args(hour, minute, second, usecond, fold) < 0) {
9987db96d56Sopenharmony_ci        return NULL;
9997db96d56Sopenharmony_ci    }
10007db96d56Sopenharmony_ci    if (check_tzinfo_subclass(tzinfo) < 0) {
10017db96d56Sopenharmony_ci        return NULL;
10027db96d56Sopenharmony_ci    }
10037db96d56Sopenharmony_ci
10047db96d56Sopenharmony_ci    self = (PyDateTime_DateTime *) (type->tp_alloc(type, aware));
10057db96d56Sopenharmony_ci    if (self != NULL) {
10067db96d56Sopenharmony_ci        self->hastzinfo = aware;
10077db96d56Sopenharmony_ci        set_date_fields((PyDateTime_Date *)self, year, month, day);
10087db96d56Sopenharmony_ci        DATE_SET_HOUR(self, hour);
10097db96d56Sopenharmony_ci        DATE_SET_MINUTE(self, minute);
10107db96d56Sopenharmony_ci        DATE_SET_SECOND(self, second);
10117db96d56Sopenharmony_ci        DATE_SET_MICROSECOND(self, usecond);
10127db96d56Sopenharmony_ci        if (aware) {
10137db96d56Sopenharmony_ci            Py_INCREF(tzinfo);
10147db96d56Sopenharmony_ci            self->tzinfo = tzinfo;
10157db96d56Sopenharmony_ci        }
10167db96d56Sopenharmony_ci        DATE_SET_FOLD(self, fold);
10177db96d56Sopenharmony_ci    }
10187db96d56Sopenharmony_ci    return (PyObject *)self;
10197db96d56Sopenharmony_ci}
10207db96d56Sopenharmony_ci
10217db96d56Sopenharmony_cistatic PyObject *
10227db96d56Sopenharmony_cinew_datetime_ex(int year, int month, int day, int hour, int minute,
10237db96d56Sopenharmony_ci                int second, int usecond, PyObject *tzinfo, PyTypeObject *type)
10247db96d56Sopenharmony_ci{
10257db96d56Sopenharmony_ci    return new_datetime_ex2(year, month, day, hour, minute, second, usecond,
10267db96d56Sopenharmony_ci                            tzinfo, 0, type);
10277db96d56Sopenharmony_ci}
10287db96d56Sopenharmony_ci
10297db96d56Sopenharmony_ci#define new_datetime(y, m, d, hh, mm, ss, us, tzinfo, fold) \
10307db96d56Sopenharmony_ci    new_datetime_ex2(y, m, d, hh, mm, ss, us, tzinfo, fold, \
10317db96d56Sopenharmony_ci                    &PyDateTime_DateTimeType)
10327db96d56Sopenharmony_ci
10337db96d56Sopenharmony_cistatic PyObject *
10347db96d56Sopenharmony_cinew_datetime_subclass_fold_ex(int year, int month, int day, int hour, int minute,
10357db96d56Sopenharmony_ci                              int second, int usecond, PyObject *tzinfo,
10367db96d56Sopenharmony_ci                              int fold, PyObject *cls) {
10377db96d56Sopenharmony_ci    PyObject* dt;
10387db96d56Sopenharmony_ci    if ((PyTypeObject*)cls == &PyDateTime_DateTimeType) {
10397db96d56Sopenharmony_ci        // Use the fast path constructor
10407db96d56Sopenharmony_ci        dt = new_datetime(year, month, day, hour, minute, second, usecond,
10417db96d56Sopenharmony_ci                          tzinfo, fold);
10427db96d56Sopenharmony_ci    } else {
10437db96d56Sopenharmony_ci        // Subclass
10447db96d56Sopenharmony_ci        dt = PyObject_CallFunction(cls, "iiiiiiiO",
10457db96d56Sopenharmony_ci                                   year,
10467db96d56Sopenharmony_ci                                   month,
10477db96d56Sopenharmony_ci                                   day,
10487db96d56Sopenharmony_ci                                   hour,
10497db96d56Sopenharmony_ci                                   minute,
10507db96d56Sopenharmony_ci                                   second,
10517db96d56Sopenharmony_ci                                   usecond,
10527db96d56Sopenharmony_ci                                   tzinfo);
10537db96d56Sopenharmony_ci    }
10547db96d56Sopenharmony_ci
10557db96d56Sopenharmony_ci    return dt;
10567db96d56Sopenharmony_ci}
10577db96d56Sopenharmony_ci
10587db96d56Sopenharmony_cistatic PyObject *
10597db96d56Sopenharmony_cinew_datetime_subclass_ex(int year, int month, int day, int hour, int minute,
10607db96d56Sopenharmony_ci                              int second, int usecond, PyObject *tzinfo,
10617db96d56Sopenharmony_ci                              PyObject *cls) {
10627db96d56Sopenharmony_ci    return new_datetime_subclass_fold_ex(year, month, day, hour, minute,
10637db96d56Sopenharmony_ci                                         second, usecond, tzinfo, 0,
10647db96d56Sopenharmony_ci                                         cls);
10657db96d56Sopenharmony_ci}
10667db96d56Sopenharmony_ci
10677db96d56Sopenharmony_ci/* Create a time instance with no range checking. */
10687db96d56Sopenharmony_cistatic PyObject *
10697db96d56Sopenharmony_cinew_time_ex2(int hour, int minute, int second, int usecond,
10707db96d56Sopenharmony_ci             PyObject *tzinfo, int fold, PyTypeObject *type)
10717db96d56Sopenharmony_ci{
10727db96d56Sopenharmony_ci    PyDateTime_Time *self;
10737db96d56Sopenharmony_ci    char aware = tzinfo != Py_None;
10747db96d56Sopenharmony_ci
10757db96d56Sopenharmony_ci    if (check_time_args(hour, minute, second, usecond, fold) < 0) {
10767db96d56Sopenharmony_ci        return NULL;
10777db96d56Sopenharmony_ci    }
10787db96d56Sopenharmony_ci    if (check_tzinfo_subclass(tzinfo) < 0) {
10797db96d56Sopenharmony_ci        return NULL;
10807db96d56Sopenharmony_ci    }
10817db96d56Sopenharmony_ci
10827db96d56Sopenharmony_ci    self = (PyDateTime_Time *) (type->tp_alloc(type, aware));
10837db96d56Sopenharmony_ci    if (self != NULL) {
10847db96d56Sopenharmony_ci        self->hastzinfo = aware;
10857db96d56Sopenharmony_ci        self->hashcode = -1;
10867db96d56Sopenharmony_ci        TIME_SET_HOUR(self, hour);
10877db96d56Sopenharmony_ci        TIME_SET_MINUTE(self, minute);
10887db96d56Sopenharmony_ci        TIME_SET_SECOND(self, second);
10897db96d56Sopenharmony_ci        TIME_SET_MICROSECOND(self, usecond);
10907db96d56Sopenharmony_ci        if (aware) {
10917db96d56Sopenharmony_ci            Py_INCREF(tzinfo);
10927db96d56Sopenharmony_ci            self->tzinfo = tzinfo;
10937db96d56Sopenharmony_ci        }
10947db96d56Sopenharmony_ci        TIME_SET_FOLD(self, fold);
10957db96d56Sopenharmony_ci    }
10967db96d56Sopenharmony_ci    return (PyObject *)self;
10977db96d56Sopenharmony_ci}
10987db96d56Sopenharmony_ci
10997db96d56Sopenharmony_cistatic PyObject *
11007db96d56Sopenharmony_cinew_time_ex(int hour, int minute, int second, int usecond,
11017db96d56Sopenharmony_ci            PyObject *tzinfo, PyTypeObject *type)
11027db96d56Sopenharmony_ci{
11037db96d56Sopenharmony_ci    return new_time_ex2(hour, minute, second, usecond, tzinfo, 0, type);
11047db96d56Sopenharmony_ci}
11057db96d56Sopenharmony_ci
11067db96d56Sopenharmony_ci#define new_time(hh, mm, ss, us, tzinfo, fold)                       \
11077db96d56Sopenharmony_ci    new_time_ex2(hh, mm, ss, us, tzinfo, fold, &PyDateTime_TimeType)
11087db96d56Sopenharmony_ci
11097db96d56Sopenharmony_ci/* Create a timedelta instance.  Normalize the members iff normalize is
11107db96d56Sopenharmony_ci * true.  Passing false is a speed optimization, if you know for sure
11117db96d56Sopenharmony_ci * that seconds and microseconds are already in their proper ranges.  In any
11127db96d56Sopenharmony_ci * case, raises OverflowError and returns NULL if the normalized days is out
11137db96d56Sopenharmony_ci * of range.
11147db96d56Sopenharmony_ci */
11157db96d56Sopenharmony_cistatic PyObject *
11167db96d56Sopenharmony_cinew_delta_ex(int days, int seconds, int microseconds, int normalize,
11177db96d56Sopenharmony_ci             PyTypeObject *type)
11187db96d56Sopenharmony_ci{
11197db96d56Sopenharmony_ci    PyDateTime_Delta *self;
11207db96d56Sopenharmony_ci
11217db96d56Sopenharmony_ci    if (normalize)
11227db96d56Sopenharmony_ci        normalize_d_s_us(&days, &seconds, &microseconds);
11237db96d56Sopenharmony_ci    assert(0 <= seconds && seconds < 24*3600);
11247db96d56Sopenharmony_ci    assert(0 <= microseconds && microseconds < 1000000);
11257db96d56Sopenharmony_ci
11267db96d56Sopenharmony_ci    if (check_delta_day_range(days) < 0)
11277db96d56Sopenharmony_ci        return NULL;
11287db96d56Sopenharmony_ci
11297db96d56Sopenharmony_ci    self = (PyDateTime_Delta *) (type->tp_alloc(type, 0));
11307db96d56Sopenharmony_ci    if (self != NULL) {
11317db96d56Sopenharmony_ci        self->hashcode = -1;
11327db96d56Sopenharmony_ci        SET_TD_DAYS(self, days);
11337db96d56Sopenharmony_ci        SET_TD_SECONDS(self, seconds);
11347db96d56Sopenharmony_ci        SET_TD_MICROSECONDS(self, microseconds);
11357db96d56Sopenharmony_ci    }
11367db96d56Sopenharmony_ci    return (PyObject *) self;
11377db96d56Sopenharmony_ci}
11387db96d56Sopenharmony_ci
11397db96d56Sopenharmony_ci#define new_delta(d, s, us, normalize)  \
11407db96d56Sopenharmony_ci    new_delta_ex(d, s, us, normalize, &PyDateTime_DeltaType)
11417db96d56Sopenharmony_ci
11427db96d56Sopenharmony_ci
11437db96d56Sopenharmony_citypedef struct
11447db96d56Sopenharmony_ci{
11457db96d56Sopenharmony_ci    PyObject_HEAD
11467db96d56Sopenharmony_ci    PyObject *offset;
11477db96d56Sopenharmony_ci    PyObject *name;
11487db96d56Sopenharmony_ci} PyDateTime_TimeZone;
11497db96d56Sopenharmony_ci
11507db96d56Sopenharmony_ci/* The interned UTC timezone instance */
11517db96d56Sopenharmony_cistatic PyObject *PyDateTime_TimeZone_UTC;
11527db96d56Sopenharmony_ci/* The interned Epoch datetime instance */
11537db96d56Sopenharmony_cistatic PyObject *PyDateTime_Epoch;
11547db96d56Sopenharmony_ci
11557db96d56Sopenharmony_ci/* Create new timezone instance checking offset range.  This
11567db96d56Sopenharmony_ci   function does not check the name argument.  Caller must assure
11577db96d56Sopenharmony_ci   that offset is a timedelta instance and name is either NULL
11587db96d56Sopenharmony_ci   or a unicode object. */
11597db96d56Sopenharmony_cistatic PyObject *
11607db96d56Sopenharmony_cicreate_timezone(PyObject *offset, PyObject *name)
11617db96d56Sopenharmony_ci{
11627db96d56Sopenharmony_ci    PyDateTime_TimeZone *self;
11637db96d56Sopenharmony_ci    PyTypeObject *type = &PyDateTime_TimeZoneType;
11647db96d56Sopenharmony_ci
11657db96d56Sopenharmony_ci    assert(offset != NULL);
11667db96d56Sopenharmony_ci    assert(PyDelta_Check(offset));
11677db96d56Sopenharmony_ci    assert(name == NULL || PyUnicode_Check(name));
11687db96d56Sopenharmony_ci
11697db96d56Sopenharmony_ci    self = (PyDateTime_TimeZone *)(type->tp_alloc(type, 0));
11707db96d56Sopenharmony_ci    if (self == NULL) {
11717db96d56Sopenharmony_ci        return NULL;
11727db96d56Sopenharmony_ci    }
11737db96d56Sopenharmony_ci    Py_INCREF(offset);
11747db96d56Sopenharmony_ci    self->offset = offset;
11757db96d56Sopenharmony_ci    Py_XINCREF(name);
11767db96d56Sopenharmony_ci    self->name = name;
11777db96d56Sopenharmony_ci    return (PyObject *)self;
11787db96d56Sopenharmony_ci}
11797db96d56Sopenharmony_ci
11807db96d56Sopenharmony_cistatic int delta_bool(PyDateTime_Delta *self);
11817db96d56Sopenharmony_ci
11827db96d56Sopenharmony_cistatic PyObject *
11837db96d56Sopenharmony_cinew_timezone(PyObject *offset, PyObject *name)
11847db96d56Sopenharmony_ci{
11857db96d56Sopenharmony_ci    assert(offset != NULL);
11867db96d56Sopenharmony_ci    assert(PyDelta_Check(offset));
11877db96d56Sopenharmony_ci    assert(name == NULL || PyUnicode_Check(name));
11887db96d56Sopenharmony_ci
11897db96d56Sopenharmony_ci    if (name == NULL && delta_bool((PyDateTime_Delta *)offset) == 0) {
11907db96d56Sopenharmony_ci        Py_INCREF(PyDateTime_TimeZone_UTC);
11917db96d56Sopenharmony_ci        return PyDateTime_TimeZone_UTC;
11927db96d56Sopenharmony_ci    }
11937db96d56Sopenharmony_ci    if ((GET_TD_DAYS(offset) == -1 &&
11947db96d56Sopenharmony_ci            GET_TD_SECONDS(offset) == 0 &&
11957db96d56Sopenharmony_ci            GET_TD_MICROSECONDS(offset) < 1) ||
11967db96d56Sopenharmony_ci        GET_TD_DAYS(offset) < -1 || GET_TD_DAYS(offset) >= 1) {
11977db96d56Sopenharmony_ci        PyErr_Format(PyExc_ValueError, "offset must be a timedelta"
11987db96d56Sopenharmony_ci                     " strictly between -timedelta(hours=24) and"
11997db96d56Sopenharmony_ci                     " timedelta(hours=24),"
12007db96d56Sopenharmony_ci                     " not %R.", offset);
12017db96d56Sopenharmony_ci        return NULL;
12027db96d56Sopenharmony_ci    }
12037db96d56Sopenharmony_ci
12047db96d56Sopenharmony_ci    return create_timezone(offset, name);
12057db96d56Sopenharmony_ci}
12067db96d56Sopenharmony_ci
12077db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
12087db96d56Sopenharmony_ci * tzinfo helpers.
12097db96d56Sopenharmony_ci */
12107db96d56Sopenharmony_ci
12117db96d56Sopenharmony_ci/* Ensure that p is None or of a tzinfo subclass.  Return 0 if OK; if not
12127db96d56Sopenharmony_ci * raise TypeError and return -1.
12137db96d56Sopenharmony_ci */
12147db96d56Sopenharmony_cistatic int
12157db96d56Sopenharmony_cicheck_tzinfo_subclass(PyObject *p)
12167db96d56Sopenharmony_ci{
12177db96d56Sopenharmony_ci    if (p == Py_None || PyTZInfo_Check(p))
12187db96d56Sopenharmony_ci        return 0;
12197db96d56Sopenharmony_ci    PyErr_Format(PyExc_TypeError,
12207db96d56Sopenharmony_ci                 "tzinfo argument must be None or of a tzinfo subclass, "
12217db96d56Sopenharmony_ci                 "not type '%s'",
12227db96d56Sopenharmony_ci                 Py_TYPE(p)->tp_name);
12237db96d56Sopenharmony_ci    return -1;
12247db96d56Sopenharmony_ci}
12257db96d56Sopenharmony_ci
12267db96d56Sopenharmony_ci/* If self has a tzinfo member, return a BORROWED reference to it.  Else
12277db96d56Sopenharmony_ci * return NULL, which is NOT AN ERROR.  There are no error returns here,
12287db96d56Sopenharmony_ci * and the caller must not decref the result.
12297db96d56Sopenharmony_ci */
12307db96d56Sopenharmony_cistatic PyObject *
12317db96d56Sopenharmony_ciget_tzinfo_member(PyObject *self)
12327db96d56Sopenharmony_ci{
12337db96d56Sopenharmony_ci    PyObject *tzinfo = NULL;
12347db96d56Sopenharmony_ci
12357db96d56Sopenharmony_ci    if (PyDateTime_Check(self) && HASTZINFO(self))
12367db96d56Sopenharmony_ci        tzinfo = ((PyDateTime_DateTime *)self)->tzinfo;
12377db96d56Sopenharmony_ci    else if (PyTime_Check(self) && HASTZINFO(self))
12387db96d56Sopenharmony_ci        tzinfo = ((PyDateTime_Time *)self)->tzinfo;
12397db96d56Sopenharmony_ci
12407db96d56Sopenharmony_ci    return tzinfo;
12417db96d56Sopenharmony_ci}
12427db96d56Sopenharmony_ci
12437db96d56Sopenharmony_ci/* Call getattr(tzinfo, name)(tzinfoarg), and check the result.  tzinfo must
12447db96d56Sopenharmony_ci * be an instance of the tzinfo class.  If the method returns None, this
12457db96d56Sopenharmony_ci * returns None.  If the method doesn't return None or timedelta, TypeError is
12467db96d56Sopenharmony_ci * raised and this returns NULL.  If it returns a timedelta and the value is
12477db96d56Sopenharmony_ci * out of range or isn't a whole number of minutes, ValueError is raised and
12487db96d56Sopenharmony_ci * this returns NULL.  Else result is returned.
12497db96d56Sopenharmony_ci */
12507db96d56Sopenharmony_cistatic PyObject *
12517db96d56Sopenharmony_cicall_tzinfo_method(PyObject *tzinfo, const char *name, PyObject *tzinfoarg)
12527db96d56Sopenharmony_ci{
12537db96d56Sopenharmony_ci    PyObject *offset;
12547db96d56Sopenharmony_ci
12557db96d56Sopenharmony_ci    assert(tzinfo != NULL);
12567db96d56Sopenharmony_ci    assert(PyTZInfo_Check(tzinfo) || tzinfo == Py_None);
12577db96d56Sopenharmony_ci    assert(tzinfoarg != NULL);
12587db96d56Sopenharmony_ci
12597db96d56Sopenharmony_ci    if (tzinfo == Py_None)
12607db96d56Sopenharmony_ci        Py_RETURN_NONE;
12617db96d56Sopenharmony_ci    offset = PyObject_CallMethod(tzinfo, name, "O", tzinfoarg);
12627db96d56Sopenharmony_ci    if (offset == Py_None || offset == NULL)
12637db96d56Sopenharmony_ci        return offset;
12647db96d56Sopenharmony_ci    if (PyDelta_Check(offset)) {
12657db96d56Sopenharmony_ci        if ((GET_TD_DAYS(offset) == -1 &&
12667db96d56Sopenharmony_ci                GET_TD_SECONDS(offset) == 0 &&
12677db96d56Sopenharmony_ci                GET_TD_MICROSECONDS(offset) < 1) ||
12687db96d56Sopenharmony_ci            GET_TD_DAYS(offset) < -1 || GET_TD_DAYS(offset) >= 1) {
12697db96d56Sopenharmony_ci            Py_DECREF(offset);
12707db96d56Sopenharmony_ci            PyErr_Format(PyExc_ValueError, "offset must be a timedelta"
12717db96d56Sopenharmony_ci                         " strictly between -timedelta(hours=24) and"
12727db96d56Sopenharmony_ci                         " timedelta(hours=24).");
12737db96d56Sopenharmony_ci            return NULL;
12747db96d56Sopenharmony_ci        }
12757db96d56Sopenharmony_ci    }
12767db96d56Sopenharmony_ci    else {
12777db96d56Sopenharmony_ci        PyErr_Format(PyExc_TypeError,
12787db96d56Sopenharmony_ci                     "tzinfo.%s() must return None or "
12797db96d56Sopenharmony_ci                     "timedelta, not '%.200s'",
12807db96d56Sopenharmony_ci                     name, Py_TYPE(offset)->tp_name);
12817db96d56Sopenharmony_ci        Py_DECREF(offset);
12827db96d56Sopenharmony_ci        return NULL;
12837db96d56Sopenharmony_ci    }
12847db96d56Sopenharmony_ci
12857db96d56Sopenharmony_ci    return offset;
12867db96d56Sopenharmony_ci}
12877db96d56Sopenharmony_ci
12887db96d56Sopenharmony_ci/* Call tzinfo.utcoffset(tzinfoarg), and extract an integer from the
12897db96d56Sopenharmony_ci * result.  tzinfo must be an instance of the tzinfo class.  If utcoffset()
12907db96d56Sopenharmony_ci * returns None, call_utcoffset returns 0 and sets *none to 1.  If uctoffset()
12917db96d56Sopenharmony_ci * doesn't return None or timedelta, TypeError is raised and this returns -1.
12927db96d56Sopenharmony_ci * If utcoffset() returns an out of range timedelta,
12937db96d56Sopenharmony_ci * ValueError is raised and this returns -1.  Else *none is
12947db96d56Sopenharmony_ci * set to 0 and the offset is returned (as timedelta, positive east of UTC).
12957db96d56Sopenharmony_ci */
12967db96d56Sopenharmony_cistatic PyObject *
12977db96d56Sopenharmony_cicall_utcoffset(PyObject *tzinfo, PyObject *tzinfoarg)
12987db96d56Sopenharmony_ci{
12997db96d56Sopenharmony_ci    return call_tzinfo_method(tzinfo, "utcoffset", tzinfoarg);
13007db96d56Sopenharmony_ci}
13017db96d56Sopenharmony_ci
13027db96d56Sopenharmony_ci/* Call tzinfo.dst(tzinfoarg), and extract an integer from the
13037db96d56Sopenharmony_ci * result.  tzinfo must be an instance of the tzinfo class.  If dst()
13047db96d56Sopenharmony_ci * returns None, call_dst returns 0 and sets *none to 1.  If dst()
13057db96d56Sopenharmony_ci * doesn't return None or timedelta, TypeError is raised and this
13067db96d56Sopenharmony_ci * returns -1.  If dst() returns an invalid timedelta for a UTC offset,
13077db96d56Sopenharmony_ci * ValueError is raised and this returns -1.  Else *none is set to 0 and
13087db96d56Sopenharmony_ci * the offset is returned (as timedelta, positive east of UTC).
13097db96d56Sopenharmony_ci */
13107db96d56Sopenharmony_cistatic PyObject *
13117db96d56Sopenharmony_cicall_dst(PyObject *tzinfo, PyObject *tzinfoarg)
13127db96d56Sopenharmony_ci{
13137db96d56Sopenharmony_ci    return call_tzinfo_method(tzinfo, "dst", tzinfoarg);
13147db96d56Sopenharmony_ci}
13157db96d56Sopenharmony_ci
13167db96d56Sopenharmony_ci/* Call tzinfo.tzname(tzinfoarg), and return the result.  tzinfo must be
13177db96d56Sopenharmony_ci * an instance of the tzinfo class or None.  If tzinfo isn't None, and
13187db96d56Sopenharmony_ci * tzname() doesn't return None or a string, TypeError is raised and this
13197db96d56Sopenharmony_ci * returns NULL.  If the result is a string, we ensure it is a Unicode
13207db96d56Sopenharmony_ci * string.
13217db96d56Sopenharmony_ci */
13227db96d56Sopenharmony_cistatic PyObject *
13237db96d56Sopenharmony_cicall_tzname(PyObject *tzinfo, PyObject *tzinfoarg)
13247db96d56Sopenharmony_ci{
13257db96d56Sopenharmony_ci    PyObject *result;
13267db96d56Sopenharmony_ci    _Py_IDENTIFIER(tzname);
13277db96d56Sopenharmony_ci
13287db96d56Sopenharmony_ci    assert(tzinfo != NULL);
13297db96d56Sopenharmony_ci    assert(check_tzinfo_subclass(tzinfo) >= 0);
13307db96d56Sopenharmony_ci    assert(tzinfoarg != NULL);
13317db96d56Sopenharmony_ci
13327db96d56Sopenharmony_ci    if (tzinfo == Py_None)
13337db96d56Sopenharmony_ci        Py_RETURN_NONE;
13347db96d56Sopenharmony_ci
13357db96d56Sopenharmony_ci    result = _PyObject_CallMethodIdOneArg(tzinfo, &PyId_tzname, tzinfoarg);
13367db96d56Sopenharmony_ci
13377db96d56Sopenharmony_ci    if (result == NULL || result == Py_None)
13387db96d56Sopenharmony_ci        return result;
13397db96d56Sopenharmony_ci
13407db96d56Sopenharmony_ci    if (!PyUnicode_Check(result)) {
13417db96d56Sopenharmony_ci        PyErr_Format(PyExc_TypeError, "tzinfo.tzname() must "
13427db96d56Sopenharmony_ci                     "return None or a string, not '%s'",
13437db96d56Sopenharmony_ci                     Py_TYPE(result)->tp_name);
13447db96d56Sopenharmony_ci        Py_DECREF(result);
13457db96d56Sopenharmony_ci        result = NULL;
13467db96d56Sopenharmony_ci    }
13477db96d56Sopenharmony_ci
13487db96d56Sopenharmony_ci    return result;
13497db96d56Sopenharmony_ci}
13507db96d56Sopenharmony_ci
13517db96d56Sopenharmony_ci/* repr is like "someclass(arg1, arg2)".  If tzinfo isn't None,
13527db96d56Sopenharmony_ci * stuff
13537db96d56Sopenharmony_ci *     ", tzinfo=" + repr(tzinfo)
13547db96d56Sopenharmony_ci * before the closing ")".
13557db96d56Sopenharmony_ci */
13567db96d56Sopenharmony_cistatic PyObject *
13577db96d56Sopenharmony_ciappend_keyword_tzinfo(PyObject *repr, PyObject *tzinfo)
13587db96d56Sopenharmony_ci{
13597db96d56Sopenharmony_ci    PyObject *temp;
13607db96d56Sopenharmony_ci
13617db96d56Sopenharmony_ci    assert(PyUnicode_Check(repr));
13627db96d56Sopenharmony_ci    assert(tzinfo);
13637db96d56Sopenharmony_ci    if (tzinfo == Py_None)
13647db96d56Sopenharmony_ci        return repr;
13657db96d56Sopenharmony_ci    /* Get rid of the trailing ')'. */
13667db96d56Sopenharmony_ci    assert(PyUnicode_READ_CHAR(repr, PyUnicode_GET_LENGTH(repr)-1) == ')');
13677db96d56Sopenharmony_ci    temp = PyUnicode_Substring(repr, 0, PyUnicode_GET_LENGTH(repr) - 1);
13687db96d56Sopenharmony_ci    Py_DECREF(repr);
13697db96d56Sopenharmony_ci    if (temp == NULL)
13707db96d56Sopenharmony_ci        return NULL;
13717db96d56Sopenharmony_ci    repr = PyUnicode_FromFormat("%U, tzinfo=%R)", temp, tzinfo);
13727db96d56Sopenharmony_ci    Py_DECREF(temp);
13737db96d56Sopenharmony_ci    return repr;
13747db96d56Sopenharmony_ci}
13757db96d56Sopenharmony_ci
13767db96d56Sopenharmony_ci/* repr is like "someclass(arg1, arg2)".  If fold isn't 0,
13777db96d56Sopenharmony_ci * stuff
13787db96d56Sopenharmony_ci *     ", fold=" + repr(tzinfo)
13797db96d56Sopenharmony_ci * before the closing ")".
13807db96d56Sopenharmony_ci */
13817db96d56Sopenharmony_cistatic PyObject *
13827db96d56Sopenharmony_ciappend_keyword_fold(PyObject *repr, int fold)
13837db96d56Sopenharmony_ci{
13847db96d56Sopenharmony_ci    PyObject *temp;
13857db96d56Sopenharmony_ci
13867db96d56Sopenharmony_ci    assert(PyUnicode_Check(repr));
13877db96d56Sopenharmony_ci    if (fold == 0)
13887db96d56Sopenharmony_ci        return repr;
13897db96d56Sopenharmony_ci    /* Get rid of the trailing ')'. */
13907db96d56Sopenharmony_ci    assert(PyUnicode_READ_CHAR(repr, PyUnicode_GET_LENGTH(repr)-1) == ')');
13917db96d56Sopenharmony_ci    temp = PyUnicode_Substring(repr, 0, PyUnicode_GET_LENGTH(repr) - 1);
13927db96d56Sopenharmony_ci    Py_DECREF(repr);
13937db96d56Sopenharmony_ci    if (temp == NULL)
13947db96d56Sopenharmony_ci        return NULL;
13957db96d56Sopenharmony_ci    repr = PyUnicode_FromFormat("%U, fold=%d)", temp, fold);
13967db96d56Sopenharmony_ci    Py_DECREF(temp);
13977db96d56Sopenharmony_ci    return repr;
13987db96d56Sopenharmony_ci}
13997db96d56Sopenharmony_ci
14007db96d56Sopenharmony_cistatic inline PyObject *
14017db96d56Sopenharmony_citzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds)
14027db96d56Sopenharmony_ci{
14037db96d56Sopenharmony_ci    PyObject *tzinfo;
14047db96d56Sopenharmony_ci    if (rv == 1) {
14057db96d56Sopenharmony_ci        // Create a timezone from offset in seconds (0 returns UTC)
14067db96d56Sopenharmony_ci        if (tzoffset == 0) {
14077db96d56Sopenharmony_ci            Py_INCREF(PyDateTime_TimeZone_UTC);
14087db96d56Sopenharmony_ci            return PyDateTime_TimeZone_UTC;
14097db96d56Sopenharmony_ci        }
14107db96d56Sopenharmony_ci
14117db96d56Sopenharmony_ci        PyObject *delta = new_delta(0, tzoffset, tz_useconds, 1);
14127db96d56Sopenharmony_ci        if (delta == NULL) {
14137db96d56Sopenharmony_ci            return NULL;
14147db96d56Sopenharmony_ci        }
14157db96d56Sopenharmony_ci        tzinfo = new_timezone(delta, NULL);
14167db96d56Sopenharmony_ci        Py_DECREF(delta);
14177db96d56Sopenharmony_ci    }
14187db96d56Sopenharmony_ci    else {
14197db96d56Sopenharmony_ci        tzinfo = Py_None;
14207db96d56Sopenharmony_ci        Py_INCREF(Py_None);
14217db96d56Sopenharmony_ci    }
14227db96d56Sopenharmony_ci
14237db96d56Sopenharmony_ci    return tzinfo;
14247db96d56Sopenharmony_ci}
14257db96d56Sopenharmony_ci
14267db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
14277db96d56Sopenharmony_ci * String format helpers.
14287db96d56Sopenharmony_ci */
14297db96d56Sopenharmony_ci
14307db96d56Sopenharmony_cistatic PyObject *
14317db96d56Sopenharmony_ciformat_ctime(PyDateTime_Date *date, int hours, int minutes, int seconds)
14327db96d56Sopenharmony_ci{
14337db96d56Sopenharmony_ci    static const char * const DayNames[] = {
14347db96d56Sopenharmony_ci        "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
14357db96d56Sopenharmony_ci    };
14367db96d56Sopenharmony_ci    static const char * const MonthNames[] = {
14377db96d56Sopenharmony_ci        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
14387db96d56Sopenharmony_ci        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
14397db96d56Sopenharmony_ci    };
14407db96d56Sopenharmony_ci
14417db96d56Sopenharmony_ci    int wday = weekday(GET_YEAR(date), GET_MONTH(date), GET_DAY(date));
14427db96d56Sopenharmony_ci
14437db96d56Sopenharmony_ci    return PyUnicode_FromFormat("%s %s %2d %02d:%02d:%02d %04d",
14447db96d56Sopenharmony_ci                                DayNames[wday], MonthNames[GET_MONTH(date)-1],
14457db96d56Sopenharmony_ci                                GET_DAY(date), hours, minutes, seconds,
14467db96d56Sopenharmony_ci                                GET_YEAR(date));
14477db96d56Sopenharmony_ci}
14487db96d56Sopenharmony_ci
14497db96d56Sopenharmony_cistatic PyObject *delta_negative(PyDateTime_Delta *self);
14507db96d56Sopenharmony_ci
14517db96d56Sopenharmony_ci/* Add formatted UTC offset string to buf.  buf has no more than
14527db96d56Sopenharmony_ci * buflen bytes remaining.  The UTC offset is gotten by calling
14537db96d56Sopenharmony_ci * tzinfo.uctoffset(tzinfoarg).  If that returns None, \0 is stored into
14547db96d56Sopenharmony_ci * *buf, and that's all.  Else the returned value is checked for sanity (an
14557db96d56Sopenharmony_ci * integer in range), and if that's OK it's converted to an hours & minutes
14567db96d56Sopenharmony_ci * string of the form
14577db96d56Sopenharmony_ci *   sign HH sep MM [sep SS [. UUUUUU]]
14587db96d56Sopenharmony_ci * Returns 0 if everything is OK.  If the return value from utcoffset() is
14597db96d56Sopenharmony_ci * bogus, an appropriate exception is set and -1 is returned.
14607db96d56Sopenharmony_ci */
14617db96d56Sopenharmony_cistatic int
14627db96d56Sopenharmony_ciformat_utcoffset(char *buf, size_t buflen, const char *sep,
14637db96d56Sopenharmony_ci                PyObject *tzinfo, PyObject *tzinfoarg)
14647db96d56Sopenharmony_ci{
14657db96d56Sopenharmony_ci    PyObject *offset;
14667db96d56Sopenharmony_ci    int hours, minutes, seconds, microseconds;
14677db96d56Sopenharmony_ci    char sign;
14687db96d56Sopenharmony_ci
14697db96d56Sopenharmony_ci    assert(buflen >= 1);
14707db96d56Sopenharmony_ci
14717db96d56Sopenharmony_ci    offset = call_utcoffset(tzinfo, tzinfoarg);
14727db96d56Sopenharmony_ci    if (offset == NULL)
14737db96d56Sopenharmony_ci        return -1;
14747db96d56Sopenharmony_ci    if (offset == Py_None) {
14757db96d56Sopenharmony_ci        Py_DECREF(offset);
14767db96d56Sopenharmony_ci        *buf = '\0';
14777db96d56Sopenharmony_ci        return 0;
14787db96d56Sopenharmony_ci    }
14797db96d56Sopenharmony_ci    /* Offset is normalized, so it is negative if days < 0 */
14807db96d56Sopenharmony_ci    if (GET_TD_DAYS(offset) < 0) {
14817db96d56Sopenharmony_ci        sign = '-';
14827db96d56Sopenharmony_ci        Py_SETREF(offset, delta_negative((PyDateTime_Delta *)offset));
14837db96d56Sopenharmony_ci        if (offset == NULL)
14847db96d56Sopenharmony_ci            return -1;
14857db96d56Sopenharmony_ci    }
14867db96d56Sopenharmony_ci    else {
14877db96d56Sopenharmony_ci        sign = '+';
14887db96d56Sopenharmony_ci    }
14897db96d56Sopenharmony_ci    /* Offset is not negative here. */
14907db96d56Sopenharmony_ci    microseconds = GET_TD_MICROSECONDS(offset);
14917db96d56Sopenharmony_ci    seconds = GET_TD_SECONDS(offset);
14927db96d56Sopenharmony_ci    Py_DECREF(offset);
14937db96d56Sopenharmony_ci    minutes = divmod(seconds, 60, &seconds);
14947db96d56Sopenharmony_ci    hours = divmod(minutes, 60, &minutes);
14957db96d56Sopenharmony_ci    if (microseconds) {
14967db96d56Sopenharmony_ci        PyOS_snprintf(buf, buflen, "%c%02d%s%02d%s%02d.%06d", sign,
14977db96d56Sopenharmony_ci                      hours, sep, minutes, sep, seconds, microseconds);
14987db96d56Sopenharmony_ci        return 0;
14997db96d56Sopenharmony_ci    }
15007db96d56Sopenharmony_ci    if (seconds) {
15017db96d56Sopenharmony_ci        PyOS_snprintf(buf, buflen, "%c%02d%s%02d%s%02d", sign, hours,
15027db96d56Sopenharmony_ci                      sep, minutes, sep, seconds);
15037db96d56Sopenharmony_ci        return 0;
15047db96d56Sopenharmony_ci    }
15057db96d56Sopenharmony_ci    PyOS_snprintf(buf, buflen, "%c%02d%s%02d", sign, hours, sep, minutes);
15067db96d56Sopenharmony_ci    return 0;
15077db96d56Sopenharmony_ci}
15087db96d56Sopenharmony_ci
15097db96d56Sopenharmony_cistatic PyObject *
15107db96d56Sopenharmony_cimake_Zreplacement(PyObject *object, PyObject *tzinfoarg)
15117db96d56Sopenharmony_ci{
15127db96d56Sopenharmony_ci    PyObject *temp;
15137db96d56Sopenharmony_ci    PyObject *tzinfo = get_tzinfo_member(object);
15147db96d56Sopenharmony_ci    PyObject *Zreplacement = PyUnicode_FromStringAndSize(NULL, 0);
15157db96d56Sopenharmony_ci    _Py_IDENTIFIER(replace);
15167db96d56Sopenharmony_ci
15177db96d56Sopenharmony_ci    if (Zreplacement == NULL)
15187db96d56Sopenharmony_ci        return NULL;
15197db96d56Sopenharmony_ci    if (tzinfo == Py_None || tzinfo == NULL)
15207db96d56Sopenharmony_ci        return Zreplacement;
15217db96d56Sopenharmony_ci
15227db96d56Sopenharmony_ci    assert(tzinfoarg != NULL);
15237db96d56Sopenharmony_ci    temp = call_tzname(tzinfo, tzinfoarg);
15247db96d56Sopenharmony_ci    if (temp == NULL)
15257db96d56Sopenharmony_ci        goto Error;
15267db96d56Sopenharmony_ci    if (temp == Py_None) {
15277db96d56Sopenharmony_ci        Py_DECREF(temp);
15287db96d56Sopenharmony_ci        return Zreplacement;
15297db96d56Sopenharmony_ci    }
15307db96d56Sopenharmony_ci
15317db96d56Sopenharmony_ci    assert(PyUnicode_Check(temp));
15327db96d56Sopenharmony_ci    /* Since the tzname is getting stuffed into the
15337db96d56Sopenharmony_ci     * format, we have to double any % signs so that
15347db96d56Sopenharmony_ci     * strftime doesn't treat them as format codes.
15357db96d56Sopenharmony_ci     */
15367db96d56Sopenharmony_ci    Py_DECREF(Zreplacement);
15377db96d56Sopenharmony_ci    Zreplacement = _PyObject_CallMethodId(temp, &PyId_replace, "ss", "%", "%%");
15387db96d56Sopenharmony_ci    Py_DECREF(temp);
15397db96d56Sopenharmony_ci    if (Zreplacement == NULL)
15407db96d56Sopenharmony_ci        return NULL;
15417db96d56Sopenharmony_ci    if (!PyUnicode_Check(Zreplacement)) {
15427db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
15437db96d56Sopenharmony_ci                        "tzname.replace() did not return a string");
15447db96d56Sopenharmony_ci        goto Error;
15457db96d56Sopenharmony_ci    }
15467db96d56Sopenharmony_ci    return Zreplacement;
15477db96d56Sopenharmony_ci
15487db96d56Sopenharmony_ci  Error:
15497db96d56Sopenharmony_ci    Py_DECREF(Zreplacement);
15507db96d56Sopenharmony_ci    return NULL;
15517db96d56Sopenharmony_ci}
15527db96d56Sopenharmony_ci
15537db96d56Sopenharmony_cistatic PyObject *
15547db96d56Sopenharmony_cimake_freplacement(PyObject *object)
15557db96d56Sopenharmony_ci{
15567db96d56Sopenharmony_ci    char freplacement[64];
15577db96d56Sopenharmony_ci    if (PyTime_Check(object))
15587db96d56Sopenharmony_ci        sprintf(freplacement, "%06d", TIME_GET_MICROSECOND(object));
15597db96d56Sopenharmony_ci    else if (PyDateTime_Check(object))
15607db96d56Sopenharmony_ci        sprintf(freplacement, "%06d", DATE_GET_MICROSECOND(object));
15617db96d56Sopenharmony_ci    else
15627db96d56Sopenharmony_ci        sprintf(freplacement, "%06d", 0);
15637db96d56Sopenharmony_ci
15647db96d56Sopenharmony_ci    return PyBytes_FromStringAndSize(freplacement, strlen(freplacement));
15657db96d56Sopenharmony_ci}
15667db96d56Sopenharmony_ci
15677db96d56Sopenharmony_ci/* I sure don't want to reproduce the strftime code from the time module,
15687db96d56Sopenharmony_ci * so this imports the module and calls it.  All the hair is due to
15697db96d56Sopenharmony_ci * giving special meanings to the %z, %Z and %f format codes via a
15707db96d56Sopenharmony_ci * preprocessing step on the format string.
15717db96d56Sopenharmony_ci * tzinfoarg is the argument to pass to the object's tzinfo method, if
15727db96d56Sopenharmony_ci * needed.
15737db96d56Sopenharmony_ci */
15747db96d56Sopenharmony_cistatic PyObject *
15757db96d56Sopenharmony_ciwrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
15767db96d56Sopenharmony_ci              PyObject *tzinfoarg)
15777db96d56Sopenharmony_ci{
15787db96d56Sopenharmony_ci    PyObject *result = NULL;            /* guilty until proved innocent */
15797db96d56Sopenharmony_ci
15807db96d56Sopenharmony_ci    PyObject *zreplacement = NULL;      /* py string, replacement for %z */
15817db96d56Sopenharmony_ci    PyObject *Zreplacement = NULL;      /* py string, replacement for %Z */
15827db96d56Sopenharmony_ci    PyObject *freplacement = NULL;      /* py string, replacement for %f */
15837db96d56Sopenharmony_ci
15847db96d56Sopenharmony_ci    const char *pin;            /* pointer to next char in input format */
15857db96d56Sopenharmony_ci    Py_ssize_t flen;            /* length of input format */
15867db96d56Sopenharmony_ci    char ch;                    /* next char in input format */
15877db96d56Sopenharmony_ci
15887db96d56Sopenharmony_ci    PyObject *newfmt = NULL;            /* py string, the output format */
15897db96d56Sopenharmony_ci    char *pnew;         /* pointer to available byte in output format */
15907db96d56Sopenharmony_ci    size_t totalnew;            /* number bytes total in output format buffer,
15917db96d56Sopenharmony_ci                               exclusive of trailing \0 */
15927db96d56Sopenharmony_ci    size_t usednew;     /* number bytes used so far in output format buffer */
15937db96d56Sopenharmony_ci
15947db96d56Sopenharmony_ci    const char *ptoappend;      /* ptr to string to append to output buffer */
15957db96d56Sopenharmony_ci    Py_ssize_t ntoappend;       /* # of bytes to append to output buffer */
15967db96d56Sopenharmony_ci
15977db96d56Sopenharmony_ci    assert(object && format && timetuple);
15987db96d56Sopenharmony_ci    assert(PyUnicode_Check(format));
15997db96d56Sopenharmony_ci    /* Convert the input format to a C string and size */
16007db96d56Sopenharmony_ci    pin = PyUnicode_AsUTF8AndSize(format, &flen);
16017db96d56Sopenharmony_ci    if (!pin)
16027db96d56Sopenharmony_ci        return NULL;
16037db96d56Sopenharmony_ci
16047db96d56Sopenharmony_ci    /* Scan the input format, looking for %z/%Z/%f escapes, building
16057db96d56Sopenharmony_ci     * a new format.  Since computing the replacements for those codes
16067db96d56Sopenharmony_ci     * is expensive, don't unless they're actually used.
16077db96d56Sopenharmony_ci     */
16087db96d56Sopenharmony_ci    if (flen > INT_MAX - 1) {
16097db96d56Sopenharmony_ci        PyErr_NoMemory();
16107db96d56Sopenharmony_ci        goto Done;
16117db96d56Sopenharmony_ci    }
16127db96d56Sopenharmony_ci
16137db96d56Sopenharmony_ci    totalnew = flen + 1;        /* realistic if no %z/%Z */
16147db96d56Sopenharmony_ci    newfmt = PyBytes_FromStringAndSize(NULL, totalnew);
16157db96d56Sopenharmony_ci    if (newfmt == NULL) goto Done;
16167db96d56Sopenharmony_ci    pnew = PyBytes_AsString(newfmt);
16177db96d56Sopenharmony_ci    usednew = 0;
16187db96d56Sopenharmony_ci
16197db96d56Sopenharmony_ci    while ((ch = *pin++) != '\0') {
16207db96d56Sopenharmony_ci        if (ch != '%') {
16217db96d56Sopenharmony_ci            ptoappend = pin - 1;
16227db96d56Sopenharmony_ci            ntoappend = 1;
16237db96d56Sopenharmony_ci        }
16247db96d56Sopenharmony_ci        else if ((ch = *pin++) == '\0') {
16257db96d56Sopenharmony_ci        /* Null byte follows %, copy only '%'.
16267db96d56Sopenharmony_ci         *
16277db96d56Sopenharmony_ci         * Back the pin up one char so that we catch the null check
16287db96d56Sopenharmony_ci         * the next time through the loop.*/
16297db96d56Sopenharmony_ci            pin--;
16307db96d56Sopenharmony_ci            ptoappend = pin - 1;
16317db96d56Sopenharmony_ci            ntoappend = 1;
16327db96d56Sopenharmony_ci        }
16337db96d56Sopenharmony_ci        /* A % has been seen and ch is the character after it. */
16347db96d56Sopenharmony_ci        else if (ch == 'z') {
16357db96d56Sopenharmony_ci            if (zreplacement == NULL) {
16367db96d56Sopenharmony_ci                /* format utcoffset */
16377db96d56Sopenharmony_ci                char buf[100];
16387db96d56Sopenharmony_ci                PyObject *tzinfo = get_tzinfo_member(object);
16397db96d56Sopenharmony_ci                zreplacement = PyBytes_FromStringAndSize("", 0);
16407db96d56Sopenharmony_ci                if (zreplacement == NULL) goto Done;
16417db96d56Sopenharmony_ci                if (tzinfo != Py_None && tzinfo != NULL) {
16427db96d56Sopenharmony_ci                    assert(tzinfoarg != NULL);
16437db96d56Sopenharmony_ci                    if (format_utcoffset(buf,
16447db96d56Sopenharmony_ci                                         sizeof(buf),
16457db96d56Sopenharmony_ci                                         "",
16467db96d56Sopenharmony_ci                                         tzinfo,
16477db96d56Sopenharmony_ci                                         tzinfoarg) < 0)
16487db96d56Sopenharmony_ci                        goto Done;
16497db96d56Sopenharmony_ci                    Py_DECREF(zreplacement);
16507db96d56Sopenharmony_ci                    zreplacement =
16517db96d56Sopenharmony_ci                      PyBytes_FromStringAndSize(buf,
16527db96d56Sopenharmony_ci                                               strlen(buf));
16537db96d56Sopenharmony_ci                    if (zreplacement == NULL)
16547db96d56Sopenharmony_ci                        goto Done;
16557db96d56Sopenharmony_ci                }
16567db96d56Sopenharmony_ci            }
16577db96d56Sopenharmony_ci            assert(zreplacement != NULL);
16587db96d56Sopenharmony_ci            ptoappend = PyBytes_AS_STRING(zreplacement);
16597db96d56Sopenharmony_ci            ntoappend = PyBytes_GET_SIZE(zreplacement);
16607db96d56Sopenharmony_ci        }
16617db96d56Sopenharmony_ci        else if (ch == 'Z') {
16627db96d56Sopenharmony_ci            /* format tzname */
16637db96d56Sopenharmony_ci            if (Zreplacement == NULL) {
16647db96d56Sopenharmony_ci                Zreplacement = make_Zreplacement(object,
16657db96d56Sopenharmony_ci                                                 tzinfoarg);
16667db96d56Sopenharmony_ci                if (Zreplacement == NULL)
16677db96d56Sopenharmony_ci                    goto Done;
16687db96d56Sopenharmony_ci            }
16697db96d56Sopenharmony_ci            assert(Zreplacement != NULL);
16707db96d56Sopenharmony_ci            assert(PyUnicode_Check(Zreplacement));
16717db96d56Sopenharmony_ci            ptoappend = PyUnicode_AsUTF8AndSize(Zreplacement,
16727db96d56Sopenharmony_ci                                                  &ntoappend);
16737db96d56Sopenharmony_ci            if (ptoappend == NULL)
16747db96d56Sopenharmony_ci                goto Done;
16757db96d56Sopenharmony_ci        }
16767db96d56Sopenharmony_ci        else if (ch == 'f') {
16777db96d56Sopenharmony_ci            /* format microseconds */
16787db96d56Sopenharmony_ci            if (freplacement == NULL) {
16797db96d56Sopenharmony_ci                freplacement = make_freplacement(object);
16807db96d56Sopenharmony_ci                if (freplacement == NULL)
16817db96d56Sopenharmony_ci                    goto Done;
16827db96d56Sopenharmony_ci            }
16837db96d56Sopenharmony_ci            assert(freplacement != NULL);
16847db96d56Sopenharmony_ci            assert(PyBytes_Check(freplacement));
16857db96d56Sopenharmony_ci            ptoappend = PyBytes_AS_STRING(freplacement);
16867db96d56Sopenharmony_ci            ntoappend = PyBytes_GET_SIZE(freplacement);
16877db96d56Sopenharmony_ci        }
16887db96d56Sopenharmony_ci        else {
16897db96d56Sopenharmony_ci            /* percent followed by neither z nor Z */
16907db96d56Sopenharmony_ci            ptoappend = pin - 2;
16917db96d56Sopenharmony_ci            ntoappend = 2;
16927db96d56Sopenharmony_ci        }
16937db96d56Sopenharmony_ci
16947db96d56Sopenharmony_ci        /* Append the ntoappend chars starting at ptoappend to
16957db96d56Sopenharmony_ci         * the new format.
16967db96d56Sopenharmony_ci         */
16977db96d56Sopenharmony_ci        if (ntoappend == 0)
16987db96d56Sopenharmony_ci            continue;
16997db96d56Sopenharmony_ci        assert(ptoappend != NULL);
17007db96d56Sopenharmony_ci        assert(ntoappend > 0);
17017db96d56Sopenharmony_ci        while (usednew + ntoappend > totalnew) {
17027db96d56Sopenharmony_ci            if (totalnew > (PY_SSIZE_T_MAX >> 1)) { /* overflow */
17037db96d56Sopenharmony_ci                PyErr_NoMemory();
17047db96d56Sopenharmony_ci                goto Done;
17057db96d56Sopenharmony_ci            }
17067db96d56Sopenharmony_ci            totalnew <<= 1;
17077db96d56Sopenharmony_ci            if (_PyBytes_Resize(&newfmt, totalnew) < 0)
17087db96d56Sopenharmony_ci                goto Done;
17097db96d56Sopenharmony_ci            pnew = PyBytes_AsString(newfmt) + usednew;
17107db96d56Sopenharmony_ci        }
17117db96d56Sopenharmony_ci        memcpy(pnew, ptoappend, ntoappend);
17127db96d56Sopenharmony_ci        pnew += ntoappend;
17137db96d56Sopenharmony_ci        usednew += ntoappend;
17147db96d56Sopenharmony_ci        assert(usednew <= totalnew);
17157db96d56Sopenharmony_ci    }  /* end while() */
17167db96d56Sopenharmony_ci
17177db96d56Sopenharmony_ci    if (_PyBytes_Resize(&newfmt, usednew) < 0)
17187db96d56Sopenharmony_ci        goto Done;
17197db96d56Sopenharmony_ci    {
17207db96d56Sopenharmony_ci        PyObject *format;
17217db96d56Sopenharmony_ci        PyObject *time = PyImport_ImportModule("time");
17227db96d56Sopenharmony_ci
17237db96d56Sopenharmony_ci        if (time == NULL)
17247db96d56Sopenharmony_ci            goto Done;
17257db96d56Sopenharmony_ci        format = PyUnicode_FromString(PyBytes_AS_STRING(newfmt));
17267db96d56Sopenharmony_ci        if (format != NULL) {
17277db96d56Sopenharmony_ci            result = _PyObject_CallMethodIdObjArgs(time, &PyId_strftime,
17287db96d56Sopenharmony_ci                                                   format, timetuple, NULL);
17297db96d56Sopenharmony_ci            Py_DECREF(format);
17307db96d56Sopenharmony_ci        }
17317db96d56Sopenharmony_ci        Py_DECREF(time);
17327db96d56Sopenharmony_ci    }
17337db96d56Sopenharmony_ci Done:
17347db96d56Sopenharmony_ci    Py_XDECREF(freplacement);
17357db96d56Sopenharmony_ci    Py_XDECREF(zreplacement);
17367db96d56Sopenharmony_ci    Py_XDECREF(Zreplacement);
17377db96d56Sopenharmony_ci    Py_XDECREF(newfmt);
17387db96d56Sopenharmony_ci    return result;
17397db96d56Sopenharmony_ci}
17407db96d56Sopenharmony_ci
17417db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
17427db96d56Sopenharmony_ci * Wrap functions from the time module.  These aren't directly available
17437db96d56Sopenharmony_ci * from C.  Perhaps they should be.
17447db96d56Sopenharmony_ci */
17457db96d56Sopenharmony_ci
17467db96d56Sopenharmony_ci/* Call time.time() and return its result (a Python float). */
17477db96d56Sopenharmony_cistatic PyObject *
17487db96d56Sopenharmony_citime_time(void)
17497db96d56Sopenharmony_ci{
17507db96d56Sopenharmony_ci    PyObject *result = NULL;
17517db96d56Sopenharmony_ci    PyObject *time = PyImport_ImportModule("time");
17527db96d56Sopenharmony_ci
17537db96d56Sopenharmony_ci    if (time != NULL) {
17547db96d56Sopenharmony_ci        _Py_IDENTIFIER(time);
17557db96d56Sopenharmony_ci
17567db96d56Sopenharmony_ci        result = _PyObject_CallMethodIdNoArgs(time, &PyId_time);
17577db96d56Sopenharmony_ci        Py_DECREF(time);
17587db96d56Sopenharmony_ci    }
17597db96d56Sopenharmony_ci    return result;
17607db96d56Sopenharmony_ci}
17617db96d56Sopenharmony_ci
17627db96d56Sopenharmony_ci/* Build a time.struct_time.  The weekday and day number are automatically
17637db96d56Sopenharmony_ci * computed from the y,m,d args.
17647db96d56Sopenharmony_ci */
17657db96d56Sopenharmony_cistatic PyObject *
17667db96d56Sopenharmony_cibuild_struct_time(int y, int m, int d, int hh, int mm, int ss, int dstflag)
17677db96d56Sopenharmony_ci{
17687db96d56Sopenharmony_ci    PyObject *time;
17697db96d56Sopenharmony_ci    PyObject *result;
17707db96d56Sopenharmony_ci    _Py_IDENTIFIER(struct_time);
17717db96d56Sopenharmony_ci    PyObject *args;
17727db96d56Sopenharmony_ci
17737db96d56Sopenharmony_ci
17747db96d56Sopenharmony_ci    time = PyImport_ImportModule("time");
17757db96d56Sopenharmony_ci    if (time == NULL) {
17767db96d56Sopenharmony_ci        return NULL;
17777db96d56Sopenharmony_ci    }
17787db96d56Sopenharmony_ci
17797db96d56Sopenharmony_ci    args = Py_BuildValue("iiiiiiiii",
17807db96d56Sopenharmony_ci                         y, m, d,
17817db96d56Sopenharmony_ci                         hh, mm, ss,
17827db96d56Sopenharmony_ci                         weekday(y, m, d),
17837db96d56Sopenharmony_ci                         days_before_month(y, m) + d,
17847db96d56Sopenharmony_ci                         dstflag);
17857db96d56Sopenharmony_ci    if (args == NULL) {
17867db96d56Sopenharmony_ci        Py_DECREF(time);
17877db96d56Sopenharmony_ci        return NULL;
17887db96d56Sopenharmony_ci    }
17897db96d56Sopenharmony_ci
17907db96d56Sopenharmony_ci    result = _PyObject_CallMethodIdOneArg(time, &PyId_struct_time, args);
17917db96d56Sopenharmony_ci    Py_DECREF(time);
17927db96d56Sopenharmony_ci    Py_DECREF(args);
17937db96d56Sopenharmony_ci    return result;
17947db96d56Sopenharmony_ci}
17957db96d56Sopenharmony_ci
17967db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
17977db96d56Sopenharmony_ci * Miscellaneous helpers.
17987db96d56Sopenharmony_ci */
17997db96d56Sopenharmony_ci
18007db96d56Sopenharmony_ci/* The comparisons here all most naturally compute a cmp()-like result.
18017db96d56Sopenharmony_ci * This little helper turns that into a bool result for rich comparisons.
18027db96d56Sopenharmony_ci */
18037db96d56Sopenharmony_cistatic PyObject *
18047db96d56Sopenharmony_cidiff_to_bool(int diff, int op)
18057db96d56Sopenharmony_ci{
18067db96d56Sopenharmony_ci    Py_RETURN_RICHCOMPARE(diff, 0, op);
18077db96d56Sopenharmony_ci}
18087db96d56Sopenharmony_ci
18097db96d56Sopenharmony_ci/* Raises a "can't compare" TypeError and returns NULL. */
18107db96d56Sopenharmony_cistatic PyObject *
18117db96d56Sopenharmony_cicmperror(PyObject *a, PyObject *b)
18127db96d56Sopenharmony_ci{
18137db96d56Sopenharmony_ci    PyErr_Format(PyExc_TypeError,
18147db96d56Sopenharmony_ci                 "can't compare %s to %s",
18157db96d56Sopenharmony_ci                 Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name);
18167db96d56Sopenharmony_ci    return NULL;
18177db96d56Sopenharmony_ci}
18187db96d56Sopenharmony_ci
18197db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
18207db96d56Sopenharmony_ci * Cached Python objects; these are set by the module init function.
18217db96d56Sopenharmony_ci */
18227db96d56Sopenharmony_ci
18237db96d56Sopenharmony_ci/* Conversion factors. */
18247db96d56Sopenharmony_cistatic PyObject *us_per_ms = NULL;      /* 1000 */
18257db96d56Sopenharmony_cistatic PyObject *us_per_second = NULL;  /* 1000000 */
18267db96d56Sopenharmony_cistatic PyObject *us_per_minute = NULL;  /* 1e6 * 60 as Python int */
18277db96d56Sopenharmony_cistatic PyObject *us_per_hour = NULL;    /* 1e6 * 3600 as Python int */
18287db96d56Sopenharmony_cistatic PyObject *us_per_day = NULL;     /* 1e6 * 3600 * 24 as Python int */
18297db96d56Sopenharmony_cistatic PyObject *us_per_week = NULL;    /* 1e6*3600*24*7 as Python int */
18307db96d56Sopenharmony_cistatic PyObject *seconds_per_day = NULL; /* 3600*24 as Python int */
18317db96d56Sopenharmony_ci
18327db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
18337db96d56Sopenharmony_ci * Class implementations.
18347db96d56Sopenharmony_ci */
18357db96d56Sopenharmony_ci
18367db96d56Sopenharmony_ci/*
18377db96d56Sopenharmony_ci * PyDateTime_Delta implementation.
18387db96d56Sopenharmony_ci */
18397db96d56Sopenharmony_ci
18407db96d56Sopenharmony_ci/* Convert a timedelta to a number of us,
18417db96d56Sopenharmony_ci *      (24*3600*self.days + self.seconds)*1000000 + self.microseconds
18427db96d56Sopenharmony_ci * as a Python int.
18437db96d56Sopenharmony_ci * Doing mixed-radix arithmetic by hand instead is excruciating in C,
18447db96d56Sopenharmony_ci * due to ubiquitous overflow possibilities.
18457db96d56Sopenharmony_ci */
18467db96d56Sopenharmony_cistatic PyObject *
18477db96d56Sopenharmony_cidelta_to_microseconds(PyDateTime_Delta *self)
18487db96d56Sopenharmony_ci{
18497db96d56Sopenharmony_ci    PyObject *x1 = NULL;
18507db96d56Sopenharmony_ci    PyObject *x2 = NULL;
18517db96d56Sopenharmony_ci    PyObject *x3 = NULL;
18527db96d56Sopenharmony_ci    PyObject *result = NULL;
18537db96d56Sopenharmony_ci
18547db96d56Sopenharmony_ci    x1 = PyLong_FromLong(GET_TD_DAYS(self));
18557db96d56Sopenharmony_ci    if (x1 == NULL)
18567db96d56Sopenharmony_ci        goto Done;
18577db96d56Sopenharmony_ci    x2 = PyNumber_Multiply(x1, seconds_per_day);        /* days in seconds */
18587db96d56Sopenharmony_ci    if (x2 == NULL)
18597db96d56Sopenharmony_ci        goto Done;
18607db96d56Sopenharmony_ci    Py_DECREF(x1);
18617db96d56Sopenharmony_ci    x1 = NULL;
18627db96d56Sopenharmony_ci
18637db96d56Sopenharmony_ci    /* x2 has days in seconds */
18647db96d56Sopenharmony_ci    x1 = PyLong_FromLong(GET_TD_SECONDS(self));         /* seconds */
18657db96d56Sopenharmony_ci    if (x1 == NULL)
18667db96d56Sopenharmony_ci        goto Done;
18677db96d56Sopenharmony_ci    x3 = PyNumber_Add(x1, x2);          /* days and seconds in seconds */
18687db96d56Sopenharmony_ci    if (x3 == NULL)
18697db96d56Sopenharmony_ci        goto Done;
18707db96d56Sopenharmony_ci    Py_DECREF(x1);
18717db96d56Sopenharmony_ci    Py_DECREF(x2);
18727db96d56Sopenharmony_ci    /* x1 = */ x2 = NULL;
18737db96d56Sopenharmony_ci
18747db96d56Sopenharmony_ci    /* x3 has days+seconds in seconds */
18757db96d56Sopenharmony_ci    x1 = PyNumber_Multiply(x3, us_per_second);          /* us */
18767db96d56Sopenharmony_ci    if (x1 == NULL)
18777db96d56Sopenharmony_ci        goto Done;
18787db96d56Sopenharmony_ci    Py_DECREF(x3);
18797db96d56Sopenharmony_ci    x3 = NULL;
18807db96d56Sopenharmony_ci
18817db96d56Sopenharmony_ci    /* x1 has days+seconds in us */
18827db96d56Sopenharmony_ci    x2 = PyLong_FromLong(GET_TD_MICROSECONDS(self));
18837db96d56Sopenharmony_ci    if (x2 == NULL)
18847db96d56Sopenharmony_ci        goto Done;
18857db96d56Sopenharmony_ci    result = PyNumber_Add(x1, x2);
18867db96d56Sopenharmony_ci    assert(result == NULL || PyLong_CheckExact(result));
18877db96d56Sopenharmony_ci
18887db96d56Sopenharmony_ciDone:
18897db96d56Sopenharmony_ci    Py_XDECREF(x1);
18907db96d56Sopenharmony_ci    Py_XDECREF(x2);
18917db96d56Sopenharmony_ci    Py_XDECREF(x3);
18927db96d56Sopenharmony_ci    return result;
18937db96d56Sopenharmony_ci}
18947db96d56Sopenharmony_ci
18957db96d56Sopenharmony_cistatic PyObject *
18967db96d56Sopenharmony_cichecked_divmod(PyObject *a, PyObject *b)
18977db96d56Sopenharmony_ci{
18987db96d56Sopenharmony_ci    PyObject *result = PyNumber_Divmod(a, b);
18997db96d56Sopenharmony_ci    if (result != NULL) {
19007db96d56Sopenharmony_ci        if (!PyTuple_Check(result)) {
19017db96d56Sopenharmony_ci            PyErr_Format(PyExc_TypeError,
19027db96d56Sopenharmony_ci                         "divmod() returned non-tuple (type %.200s)",
19037db96d56Sopenharmony_ci                         Py_TYPE(result)->tp_name);
19047db96d56Sopenharmony_ci            Py_DECREF(result);
19057db96d56Sopenharmony_ci            return NULL;
19067db96d56Sopenharmony_ci        }
19077db96d56Sopenharmony_ci        if (PyTuple_GET_SIZE(result) != 2) {
19087db96d56Sopenharmony_ci            PyErr_Format(PyExc_TypeError,
19097db96d56Sopenharmony_ci                         "divmod() returned a tuple of size %zd",
19107db96d56Sopenharmony_ci                         PyTuple_GET_SIZE(result));
19117db96d56Sopenharmony_ci            Py_DECREF(result);
19127db96d56Sopenharmony_ci            return NULL;
19137db96d56Sopenharmony_ci        }
19147db96d56Sopenharmony_ci    }
19157db96d56Sopenharmony_ci    return result;
19167db96d56Sopenharmony_ci}
19177db96d56Sopenharmony_ci
19187db96d56Sopenharmony_ci/* Convert a number of us (as a Python int) to a timedelta.
19197db96d56Sopenharmony_ci */
19207db96d56Sopenharmony_cistatic PyObject *
19217db96d56Sopenharmony_cimicroseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type)
19227db96d56Sopenharmony_ci{
19237db96d56Sopenharmony_ci    int us;
19247db96d56Sopenharmony_ci    int s;
19257db96d56Sopenharmony_ci    int d;
19267db96d56Sopenharmony_ci
19277db96d56Sopenharmony_ci    PyObject *tuple = NULL;
19287db96d56Sopenharmony_ci    PyObject *num = NULL;
19297db96d56Sopenharmony_ci    PyObject *result = NULL;
19307db96d56Sopenharmony_ci
19317db96d56Sopenharmony_ci    tuple = checked_divmod(pyus, us_per_second);
19327db96d56Sopenharmony_ci    if (tuple == NULL) {
19337db96d56Sopenharmony_ci        goto Done;
19347db96d56Sopenharmony_ci    }
19357db96d56Sopenharmony_ci
19367db96d56Sopenharmony_ci    num = PyTuple_GET_ITEM(tuple, 1);           /* us */
19377db96d56Sopenharmony_ci    us = _PyLong_AsInt(num);
19387db96d56Sopenharmony_ci    num = NULL;
19397db96d56Sopenharmony_ci    if (us == -1 && PyErr_Occurred()) {
19407db96d56Sopenharmony_ci        goto Done;
19417db96d56Sopenharmony_ci    }
19427db96d56Sopenharmony_ci    if (!(0 <= us && us < 1000000)) {
19437db96d56Sopenharmony_ci        goto BadDivmod;
19447db96d56Sopenharmony_ci    }
19457db96d56Sopenharmony_ci
19467db96d56Sopenharmony_ci    num = PyTuple_GET_ITEM(tuple, 0);           /* leftover seconds */
19477db96d56Sopenharmony_ci    Py_INCREF(num);
19487db96d56Sopenharmony_ci    Py_DECREF(tuple);
19497db96d56Sopenharmony_ci
19507db96d56Sopenharmony_ci    tuple = checked_divmod(num, seconds_per_day);
19517db96d56Sopenharmony_ci    if (tuple == NULL)
19527db96d56Sopenharmony_ci        goto Done;
19537db96d56Sopenharmony_ci    Py_DECREF(num);
19547db96d56Sopenharmony_ci
19557db96d56Sopenharmony_ci    num = PyTuple_GET_ITEM(tuple, 1);           /* seconds */
19567db96d56Sopenharmony_ci    s = _PyLong_AsInt(num);
19577db96d56Sopenharmony_ci    num = NULL;
19587db96d56Sopenharmony_ci    if (s == -1 && PyErr_Occurred()) {
19597db96d56Sopenharmony_ci        goto Done;
19607db96d56Sopenharmony_ci    }
19617db96d56Sopenharmony_ci    if (!(0 <= s && s < 24*3600)) {
19627db96d56Sopenharmony_ci        goto BadDivmod;
19637db96d56Sopenharmony_ci    }
19647db96d56Sopenharmony_ci
19657db96d56Sopenharmony_ci    num = PyTuple_GET_ITEM(tuple, 0);           /* leftover days */
19667db96d56Sopenharmony_ci    Py_INCREF(num);
19677db96d56Sopenharmony_ci    d = _PyLong_AsInt(num);
19687db96d56Sopenharmony_ci    if (d == -1 && PyErr_Occurred()) {
19697db96d56Sopenharmony_ci        goto Done;
19707db96d56Sopenharmony_ci    }
19717db96d56Sopenharmony_ci    result = new_delta_ex(d, s, us, 0, type);
19727db96d56Sopenharmony_ci
19737db96d56Sopenharmony_ciDone:
19747db96d56Sopenharmony_ci    Py_XDECREF(tuple);
19757db96d56Sopenharmony_ci    Py_XDECREF(num);
19767db96d56Sopenharmony_ci    return result;
19777db96d56Sopenharmony_ci
19787db96d56Sopenharmony_ciBadDivmod:
19797db96d56Sopenharmony_ci    PyErr_SetString(PyExc_TypeError,
19807db96d56Sopenharmony_ci                    "divmod() returned a value out of range");
19817db96d56Sopenharmony_ci    goto Done;
19827db96d56Sopenharmony_ci}
19837db96d56Sopenharmony_ci
19847db96d56Sopenharmony_ci#define microseconds_to_delta(pymicros) \
19857db96d56Sopenharmony_ci    microseconds_to_delta_ex(pymicros, &PyDateTime_DeltaType)
19867db96d56Sopenharmony_ci
19877db96d56Sopenharmony_cistatic PyObject *
19887db96d56Sopenharmony_cimultiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta)
19897db96d56Sopenharmony_ci{
19907db96d56Sopenharmony_ci    PyObject *pyus_in;
19917db96d56Sopenharmony_ci    PyObject *pyus_out;
19927db96d56Sopenharmony_ci    PyObject *result;
19937db96d56Sopenharmony_ci
19947db96d56Sopenharmony_ci    pyus_in = delta_to_microseconds(delta);
19957db96d56Sopenharmony_ci    if (pyus_in == NULL)
19967db96d56Sopenharmony_ci        return NULL;
19977db96d56Sopenharmony_ci
19987db96d56Sopenharmony_ci    pyus_out = PyNumber_Multiply(intobj, pyus_in);
19997db96d56Sopenharmony_ci    Py_DECREF(pyus_in);
20007db96d56Sopenharmony_ci    if (pyus_out == NULL)
20017db96d56Sopenharmony_ci        return NULL;
20027db96d56Sopenharmony_ci
20037db96d56Sopenharmony_ci    result = microseconds_to_delta(pyus_out);
20047db96d56Sopenharmony_ci    Py_DECREF(pyus_out);
20057db96d56Sopenharmony_ci    return result;
20067db96d56Sopenharmony_ci}
20077db96d56Sopenharmony_ci
20087db96d56Sopenharmony_cistatic PyObject *
20097db96d56Sopenharmony_ciget_float_as_integer_ratio(PyObject *floatobj)
20107db96d56Sopenharmony_ci{
20117db96d56Sopenharmony_ci    PyObject *ratio;
20127db96d56Sopenharmony_ci
20137db96d56Sopenharmony_ci    assert(floatobj && PyFloat_Check(floatobj));
20147db96d56Sopenharmony_ci    ratio = _PyObject_CallMethodIdNoArgs(floatobj, &PyId_as_integer_ratio);
20157db96d56Sopenharmony_ci    if (ratio == NULL) {
20167db96d56Sopenharmony_ci        return NULL;
20177db96d56Sopenharmony_ci    }
20187db96d56Sopenharmony_ci    if (!PyTuple_Check(ratio)) {
20197db96d56Sopenharmony_ci        PyErr_Format(PyExc_TypeError,
20207db96d56Sopenharmony_ci                     "unexpected return type from as_integer_ratio(): "
20217db96d56Sopenharmony_ci                     "expected tuple, got '%.200s'",
20227db96d56Sopenharmony_ci                     Py_TYPE(ratio)->tp_name);
20237db96d56Sopenharmony_ci        Py_DECREF(ratio);
20247db96d56Sopenharmony_ci        return NULL;
20257db96d56Sopenharmony_ci    }
20267db96d56Sopenharmony_ci    if (PyTuple_Size(ratio) != 2) {
20277db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
20287db96d56Sopenharmony_ci                        "as_integer_ratio() must return a 2-tuple");
20297db96d56Sopenharmony_ci        Py_DECREF(ratio);
20307db96d56Sopenharmony_ci        return NULL;
20317db96d56Sopenharmony_ci    }
20327db96d56Sopenharmony_ci    return ratio;
20337db96d56Sopenharmony_ci}
20347db96d56Sopenharmony_ci
20357db96d56Sopenharmony_ci/* op is 0 for multiplication, 1 for division */
20367db96d56Sopenharmony_cistatic PyObject *
20377db96d56Sopenharmony_cimultiply_truedivide_timedelta_float(PyDateTime_Delta *delta, PyObject *floatobj, int op)
20387db96d56Sopenharmony_ci{
20397db96d56Sopenharmony_ci    PyObject *result = NULL;
20407db96d56Sopenharmony_ci    PyObject *pyus_in = NULL, *temp, *pyus_out;
20417db96d56Sopenharmony_ci    PyObject *ratio = NULL;
20427db96d56Sopenharmony_ci
20437db96d56Sopenharmony_ci    pyus_in = delta_to_microseconds(delta);
20447db96d56Sopenharmony_ci    if (pyus_in == NULL)
20457db96d56Sopenharmony_ci        return NULL;
20467db96d56Sopenharmony_ci    ratio = get_float_as_integer_ratio(floatobj);
20477db96d56Sopenharmony_ci    if (ratio == NULL) {
20487db96d56Sopenharmony_ci        goto error;
20497db96d56Sopenharmony_ci    }
20507db96d56Sopenharmony_ci    temp = PyNumber_Multiply(pyus_in, PyTuple_GET_ITEM(ratio, op));
20517db96d56Sopenharmony_ci    Py_DECREF(pyus_in);
20527db96d56Sopenharmony_ci    pyus_in = NULL;
20537db96d56Sopenharmony_ci    if (temp == NULL)
20547db96d56Sopenharmony_ci        goto error;
20557db96d56Sopenharmony_ci    pyus_out = divide_nearest(temp, PyTuple_GET_ITEM(ratio, !op));
20567db96d56Sopenharmony_ci    Py_DECREF(temp);
20577db96d56Sopenharmony_ci    if (pyus_out == NULL)
20587db96d56Sopenharmony_ci        goto error;
20597db96d56Sopenharmony_ci    result = microseconds_to_delta(pyus_out);
20607db96d56Sopenharmony_ci    Py_DECREF(pyus_out);
20617db96d56Sopenharmony_ci error:
20627db96d56Sopenharmony_ci    Py_XDECREF(pyus_in);
20637db96d56Sopenharmony_ci    Py_XDECREF(ratio);
20647db96d56Sopenharmony_ci
20657db96d56Sopenharmony_ci    return result;
20667db96d56Sopenharmony_ci}
20677db96d56Sopenharmony_ci
20687db96d56Sopenharmony_cistatic PyObject *
20697db96d56Sopenharmony_cidivide_timedelta_int(PyDateTime_Delta *delta, PyObject *intobj)
20707db96d56Sopenharmony_ci{
20717db96d56Sopenharmony_ci    PyObject *pyus_in;
20727db96d56Sopenharmony_ci    PyObject *pyus_out;
20737db96d56Sopenharmony_ci    PyObject *result;
20747db96d56Sopenharmony_ci
20757db96d56Sopenharmony_ci    pyus_in = delta_to_microseconds(delta);
20767db96d56Sopenharmony_ci    if (pyus_in == NULL)
20777db96d56Sopenharmony_ci        return NULL;
20787db96d56Sopenharmony_ci
20797db96d56Sopenharmony_ci    pyus_out = PyNumber_FloorDivide(pyus_in, intobj);
20807db96d56Sopenharmony_ci    Py_DECREF(pyus_in);
20817db96d56Sopenharmony_ci    if (pyus_out == NULL)
20827db96d56Sopenharmony_ci        return NULL;
20837db96d56Sopenharmony_ci
20847db96d56Sopenharmony_ci    result = microseconds_to_delta(pyus_out);
20857db96d56Sopenharmony_ci    Py_DECREF(pyus_out);
20867db96d56Sopenharmony_ci    return result;
20877db96d56Sopenharmony_ci}
20887db96d56Sopenharmony_ci
20897db96d56Sopenharmony_cistatic PyObject *
20907db96d56Sopenharmony_cidivide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right)
20917db96d56Sopenharmony_ci{
20927db96d56Sopenharmony_ci    PyObject *pyus_left;
20937db96d56Sopenharmony_ci    PyObject *pyus_right;
20947db96d56Sopenharmony_ci    PyObject *result;
20957db96d56Sopenharmony_ci
20967db96d56Sopenharmony_ci    pyus_left = delta_to_microseconds(left);
20977db96d56Sopenharmony_ci    if (pyus_left == NULL)
20987db96d56Sopenharmony_ci        return NULL;
20997db96d56Sopenharmony_ci
21007db96d56Sopenharmony_ci    pyus_right = delta_to_microseconds(right);
21017db96d56Sopenharmony_ci    if (pyus_right == NULL)     {
21027db96d56Sopenharmony_ci        Py_DECREF(pyus_left);
21037db96d56Sopenharmony_ci        return NULL;
21047db96d56Sopenharmony_ci    }
21057db96d56Sopenharmony_ci
21067db96d56Sopenharmony_ci    result = PyNumber_FloorDivide(pyus_left, pyus_right);
21077db96d56Sopenharmony_ci    Py_DECREF(pyus_left);
21087db96d56Sopenharmony_ci    Py_DECREF(pyus_right);
21097db96d56Sopenharmony_ci    return result;
21107db96d56Sopenharmony_ci}
21117db96d56Sopenharmony_ci
21127db96d56Sopenharmony_cistatic PyObject *
21137db96d56Sopenharmony_citruedivide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right)
21147db96d56Sopenharmony_ci{
21157db96d56Sopenharmony_ci    PyObject *pyus_left;
21167db96d56Sopenharmony_ci    PyObject *pyus_right;
21177db96d56Sopenharmony_ci    PyObject *result;
21187db96d56Sopenharmony_ci
21197db96d56Sopenharmony_ci    pyus_left = delta_to_microseconds(left);
21207db96d56Sopenharmony_ci    if (pyus_left == NULL)
21217db96d56Sopenharmony_ci        return NULL;
21227db96d56Sopenharmony_ci
21237db96d56Sopenharmony_ci    pyus_right = delta_to_microseconds(right);
21247db96d56Sopenharmony_ci    if (pyus_right == NULL)     {
21257db96d56Sopenharmony_ci        Py_DECREF(pyus_left);
21267db96d56Sopenharmony_ci        return NULL;
21277db96d56Sopenharmony_ci    }
21287db96d56Sopenharmony_ci
21297db96d56Sopenharmony_ci    result = PyNumber_TrueDivide(pyus_left, pyus_right);
21307db96d56Sopenharmony_ci    Py_DECREF(pyus_left);
21317db96d56Sopenharmony_ci    Py_DECREF(pyus_right);
21327db96d56Sopenharmony_ci    return result;
21337db96d56Sopenharmony_ci}
21347db96d56Sopenharmony_ci
21357db96d56Sopenharmony_cistatic PyObject *
21367db96d56Sopenharmony_citruedivide_timedelta_int(PyDateTime_Delta *delta, PyObject *i)
21377db96d56Sopenharmony_ci{
21387db96d56Sopenharmony_ci    PyObject *result;
21397db96d56Sopenharmony_ci    PyObject *pyus_in, *pyus_out;
21407db96d56Sopenharmony_ci    pyus_in = delta_to_microseconds(delta);
21417db96d56Sopenharmony_ci    if (pyus_in == NULL)
21427db96d56Sopenharmony_ci        return NULL;
21437db96d56Sopenharmony_ci    pyus_out = divide_nearest(pyus_in, i);
21447db96d56Sopenharmony_ci    Py_DECREF(pyus_in);
21457db96d56Sopenharmony_ci    if (pyus_out == NULL)
21467db96d56Sopenharmony_ci        return NULL;
21477db96d56Sopenharmony_ci    result = microseconds_to_delta(pyus_out);
21487db96d56Sopenharmony_ci    Py_DECREF(pyus_out);
21497db96d56Sopenharmony_ci
21507db96d56Sopenharmony_ci    return result;
21517db96d56Sopenharmony_ci}
21527db96d56Sopenharmony_ci
21537db96d56Sopenharmony_cistatic PyObject *
21547db96d56Sopenharmony_cidelta_add(PyObject *left, PyObject *right)
21557db96d56Sopenharmony_ci{
21567db96d56Sopenharmony_ci    PyObject *result = Py_NotImplemented;
21577db96d56Sopenharmony_ci
21587db96d56Sopenharmony_ci    if (PyDelta_Check(left) && PyDelta_Check(right)) {
21597db96d56Sopenharmony_ci        /* delta + delta */
21607db96d56Sopenharmony_ci        /* The C-level additions can't overflow because of the
21617db96d56Sopenharmony_ci         * invariant bounds.
21627db96d56Sopenharmony_ci         */
21637db96d56Sopenharmony_ci        int days = GET_TD_DAYS(left) + GET_TD_DAYS(right);
21647db96d56Sopenharmony_ci        int seconds = GET_TD_SECONDS(left) + GET_TD_SECONDS(right);
21657db96d56Sopenharmony_ci        int microseconds = GET_TD_MICROSECONDS(left) +
21667db96d56Sopenharmony_ci                           GET_TD_MICROSECONDS(right);
21677db96d56Sopenharmony_ci        result = new_delta(days, seconds, microseconds, 1);
21687db96d56Sopenharmony_ci    }
21697db96d56Sopenharmony_ci
21707db96d56Sopenharmony_ci    if (result == Py_NotImplemented)
21717db96d56Sopenharmony_ci        Py_INCREF(result);
21727db96d56Sopenharmony_ci    return result;
21737db96d56Sopenharmony_ci}
21747db96d56Sopenharmony_ci
21757db96d56Sopenharmony_cistatic PyObject *
21767db96d56Sopenharmony_cidelta_negative(PyDateTime_Delta *self)
21777db96d56Sopenharmony_ci{
21787db96d56Sopenharmony_ci    return new_delta(-GET_TD_DAYS(self),
21797db96d56Sopenharmony_ci                     -GET_TD_SECONDS(self),
21807db96d56Sopenharmony_ci                     -GET_TD_MICROSECONDS(self),
21817db96d56Sopenharmony_ci                     1);
21827db96d56Sopenharmony_ci}
21837db96d56Sopenharmony_ci
21847db96d56Sopenharmony_cistatic PyObject *
21857db96d56Sopenharmony_cidelta_positive(PyDateTime_Delta *self)
21867db96d56Sopenharmony_ci{
21877db96d56Sopenharmony_ci    /* Could optimize this (by returning self) if this isn't a
21887db96d56Sopenharmony_ci     * subclass -- but who uses unary + ?  Approximately nobody.
21897db96d56Sopenharmony_ci     */
21907db96d56Sopenharmony_ci    return new_delta(GET_TD_DAYS(self),
21917db96d56Sopenharmony_ci                     GET_TD_SECONDS(self),
21927db96d56Sopenharmony_ci                     GET_TD_MICROSECONDS(self),
21937db96d56Sopenharmony_ci                     0);
21947db96d56Sopenharmony_ci}
21957db96d56Sopenharmony_ci
21967db96d56Sopenharmony_cistatic PyObject *
21977db96d56Sopenharmony_cidelta_abs(PyDateTime_Delta *self)
21987db96d56Sopenharmony_ci{
21997db96d56Sopenharmony_ci    PyObject *result;
22007db96d56Sopenharmony_ci
22017db96d56Sopenharmony_ci    assert(GET_TD_MICROSECONDS(self) >= 0);
22027db96d56Sopenharmony_ci    assert(GET_TD_SECONDS(self) >= 0);
22037db96d56Sopenharmony_ci
22047db96d56Sopenharmony_ci    if (GET_TD_DAYS(self) < 0)
22057db96d56Sopenharmony_ci        result = delta_negative(self);
22067db96d56Sopenharmony_ci    else
22077db96d56Sopenharmony_ci        result = delta_positive(self);
22087db96d56Sopenharmony_ci
22097db96d56Sopenharmony_ci    return result;
22107db96d56Sopenharmony_ci}
22117db96d56Sopenharmony_ci
22127db96d56Sopenharmony_cistatic PyObject *
22137db96d56Sopenharmony_cidelta_subtract(PyObject *left, PyObject *right)
22147db96d56Sopenharmony_ci{
22157db96d56Sopenharmony_ci    PyObject *result = Py_NotImplemented;
22167db96d56Sopenharmony_ci
22177db96d56Sopenharmony_ci    if (PyDelta_Check(left) && PyDelta_Check(right)) {
22187db96d56Sopenharmony_ci        /* delta - delta */
22197db96d56Sopenharmony_ci        /* The C-level additions can't overflow because of the
22207db96d56Sopenharmony_ci         * invariant bounds.
22217db96d56Sopenharmony_ci         */
22227db96d56Sopenharmony_ci        int days = GET_TD_DAYS(left) - GET_TD_DAYS(right);
22237db96d56Sopenharmony_ci        int seconds = GET_TD_SECONDS(left) - GET_TD_SECONDS(right);
22247db96d56Sopenharmony_ci        int microseconds = GET_TD_MICROSECONDS(left) -
22257db96d56Sopenharmony_ci                           GET_TD_MICROSECONDS(right);
22267db96d56Sopenharmony_ci        result = new_delta(days, seconds, microseconds, 1);
22277db96d56Sopenharmony_ci    }
22287db96d56Sopenharmony_ci
22297db96d56Sopenharmony_ci    if (result == Py_NotImplemented)
22307db96d56Sopenharmony_ci        Py_INCREF(result);
22317db96d56Sopenharmony_ci    return result;
22327db96d56Sopenharmony_ci}
22337db96d56Sopenharmony_ci
22347db96d56Sopenharmony_cistatic int
22357db96d56Sopenharmony_cidelta_cmp(PyObject *self, PyObject *other)
22367db96d56Sopenharmony_ci{
22377db96d56Sopenharmony_ci    int diff = GET_TD_DAYS(self) - GET_TD_DAYS(other);
22387db96d56Sopenharmony_ci    if (diff == 0) {
22397db96d56Sopenharmony_ci        diff = GET_TD_SECONDS(self) - GET_TD_SECONDS(other);
22407db96d56Sopenharmony_ci        if (diff == 0)
22417db96d56Sopenharmony_ci            diff = GET_TD_MICROSECONDS(self) -
22427db96d56Sopenharmony_ci                GET_TD_MICROSECONDS(other);
22437db96d56Sopenharmony_ci    }
22447db96d56Sopenharmony_ci    return diff;
22457db96d56Sopenharmony_ci}
22467db96d56Sopenharmony_ci
22477db96d56Sopenharmony_cistatic PyObject *
22487db96d56Sopenharmony_cidelta_richcompare(PyObject *self, PyObject *other, int op)
22497db96d56Sopenharmony_ci{
22507db96d56Sopenharmony_ci    if (PyDelta_Check(other)) {
22517db96d56Sopenharmony_ci        int diff = delta_cmp(self, other);
22527db96d56Sopenharmony_ci        return diff_to_bool(diff, op);
22537db96d56Sopenharmony_ci    }
22547db96d56Sopenharmony_ci    else {
22557db96d56Sopenharmony_ci        Py_RETURN_NOTIMPLEMENTED;
22567db96d56Sopenharmony_ci    }
22577db96d56Sopenharmony_ci}
22587db96d56Sopenharmony_ci
22597db96d56Sopenharmony_cistatic PyObject *delta_getstate(PyDateTime_Delta *self);
22607db96d56Sopenharmony_ci
22617db96d56Sopenharmony_cistatic Py_hash_t
22627db96d56Sopenharmony_cidelta_hash(PyDateTime_Delta *self)
22637db96d56Sopenharmony_ci{
22647db96d56Sopenharmony_ci    if (self->hashcode == -1) {
22657db96d56Sopenharmony_ci        PyObject *temp = delta_getstate(self);
22667db96d56Sopenharmony_ci        if (temp != NULL) {
22677db96d56Sopenharmony_ci            self->hashcode = PyObject_Hash(temp);
22687db96d56Sopenharmony_ci            Py_DECREF(temp);
22697db96d56Sopenharmony_ci        }
22707db96d56Sopenharmony_ci    }
22717db96d56Sopenharmony_ci    return self->hashcode;
22727db96d56Sopenharmony_ci}
22737db96d56Sopenharmony_ci
22747db96d56Sopenharmony_cistatic PyObject *
22757db96d56Sopenharmony_cidelta_multiply(PyObject *left, PyObject *right)
22767db96d56Sopenharmony_ci{
22777db96d56Sopenharmony_ci    PyObject *result = Py_NotImplemented;
22787db96d56Sopenharmony_ci
22797db96d56Sopenharmony_ci    if (PyDelta_Check(left)) {
22807db96d56Sopenharmony_ci        /* delta * ??? */
22817db96d56Sopenharmony_ci        if (PyLong_Check(right))
22827db96d56Sopenharmony_ci            result = multiply_int_timedelta(right,
22837db96d56Sopenharmony_ci                            (PyDateTime_Delta *) left);
22847db96d56Sopenharmony_ci        else if (PyFloat_Check(right))
22857db96d56Sopenharmony_ci            result = multiply_truedivide_timedelta_float(
22867db96d56Sopenharmony_ci                            (PyDateTime_Delta *) left, right, 0);
22877db96d56Sopenharmony_ci    }
22887db96d56Sopenharmony_ci    else if (PyLong_Check(left))
22897db96d56Sopenharmony_ci        result = multiply_int_timedelta(left,
22907db96d56Sopenharmony_ci                        (PyDateTime_Delta *) right);
22917db96d56Sopenharmony_ci    else if (PyFloat_Check(left))
22927db96d56Sopenharmony_ci        result = multiply_truedivide_timedelta_float(
22937db96d56Sopenharmony_ci                        (PyDateTime_Delta *) right, left, 0);
22947db96d56Sopenharmony_ci
22957db96d56Sopenharmony_ci    if (result == Py_NotImplemented)
22967db96d56Sopenharmony_ci        Py_INCREF(result);
22977db96d56Sopenharmony_ci    return result;
22987db96d56Sopenharmony_ci}
22997db96d56Sopenharmony_ci
23007db96d56Sopenharmony_cistatic PyObject *
23017db96d56Sopenharmony_cidelta_divide(PyObject *left, PyObject *right)
23027db96d56Sopenharmony_ci{
23037db96d56Sopenharmony_ci    PyObject *result = Py_NotImplemented;
23047db96d56Sopenharmony_ci
23057db96d56Sopenharmony_ci    if (PyDelta_Check(left)) {
23067db96d56Sopenharmony_ci        /* delta * ??? */
23077db96d56Sopenharmony_ci        if (PyLong_Check(right))
23087db96d56Sopenharmony_ci            result = divide_timedelta_int(
23097db96d56Sopenharmony_ci                            (PyDateTime_Delta *)left,
23107db96d56Sopenharmony_ci                            right);
23117db96d56Sopenharmony_ci        else if (PyDelta_Check(right))
23127db96d56Sopenharmony_ci            result = divide_timedelta_timedelta(
23137db96d56Sopenharmony_ci                            (PyDateTime_Delta *)left,
23147db96d56Sopenharmony_ci                            (PyDateTime_Delta *)right);
23157db96d56Sopenharmony_ci    }
23167db96d56Sopenharmony_ci
23177db96d56Sopenharmony_ci    if (result == Py_NotImplemented)
23187db96d56Sopenharmony_ci        Py_INCREF(result);
23197db96d56Sopenharmony_ci    return result;
23207db96d56Sopenharmony_ci}
23217db96d56Sopenharmony_ci
23227db96d56Sopenharmony_cistatic PyObject *
23237db96d56Sopenharmony_cidelta_truedivide(PyObject *left, PyObject *right)
23247db96d56Sopenharmony_ci{
23257db96d56Sopenharmony_ci    PyObject *result = Py_NotImplemented;
23267db96d56Sopenharmony_ci
23277db96d56Sopenharmony_ci    if (PyDelta_Check(left)) {
23287db96d56Sopenharmony_ci        if (PyDelta_Check(right))
23297db96d56Sopenharmony_ci            result = truedivide_timedelta_timedelta(
23307db96d56Sopenharmony_ci                            (PyDateTime_Delta *)left,
23317db96d56Sopenharmony_ci                            (PyDateTime_Delta *)right);
23327db96d56Sopenharmony_ci        else if (PyFloat_Check(right))
23337db96d56Sopenharmony_ci            result = multiply_truedivide_timedelta_float(
23347db96d56Sopenharmony_ci                            (PyDateTime_Delta *)left, right, 1);
23357db96d56Sopenharmony_ci        else if (PyLong_Check(right))
23367db96d56Sopenharmony_ci            result = truedivide_timedelta_int(
23377db96d56Sopenharmony_ci                            (PyDateTime_Delta *)left, right);
23387db96d56Sopenharmony_ci    }
23397db96d56Sopenharmony_ci
23407db96d56Sopenharmony_ci    if (result == Py_NotImplemented)
23417db96d56Sopenharmony_ci        Py_INCREF(result);
23427db96d56Sopenharmony_ci    return result;
23437db96d56Sopenharmony_ci}
23447db96d56Sopenharmony_ci
23457db96d56Sopenharmony_cistatic PyObject *
23467db96d56Sopenharmony_cidelta_remainder(PyObject *left, PyObject *right)
23477db96d56Sopenharmony_ci{
23487db96d56Sopenharmony_ci    PyObject *pyus_left;
23497db96d56Sopenharmony_ci    PyObject *pyus_right;
23507db96d56Sopenharmony_ci    PyObject *pyus_remainder;
23517db96d56Sopenharmony_ci    PyObject *remainder;
23527db96d56Sopenharmony_ci
23537db96d56Sopenharmony_ci    if (!PyDelta_Check(left) || !PyDelta_Check(right))
23547db96d56Sopenharmony_ci        Py_RETURN_NOTIMPLEMENTED;
23557db96d56Sopenharmony_ci
23567db96d56Sopenharmony_ci    pyus_left = delta_to_microseconds((PyDateTime_Delta *)left);
23577db96d56Sopenharmony_ci    if (pyus_left == NULL)
23587db96d56Sopenharmony_ci        return NULL;
23597db96d56Sopenharmony_ci
23607db96d56Sopenharmony_ci    pyus_right = delta_to_microseconds((PyDateTime_Delta *)right);
23617db96d56Sopenharmony_ci    if (pyus_right == NULL) {
23627db96d56Sopenharmony_ci        Py_DECREF(pyus_left);
23637db96d56Sopenharmony_ci        return NULL;
23647db96d56Sopenharmony_ci    }
23657db96d56Sopenharmony_ci
23667db96d56Sopenharmony_ci    pyus_remainder = PyNumber_Remainder(pyus_left, pyus_right);
23677db96d56Sopenharmony_ci    Py_DECREF(pyus_left);
23687db96d56Sopenharmony_ci    Py_DECREF(pyus_right);
23697db96d56Sopenharmony_ci    if (pyus_remainder == NULL)
23707db96d56Sopenharmony_ci        return NULL;
23717db96d56Sopenharmony_ci
23727db96d56Sopenharmony_ci    remainder = microseconds_to_delta(pyus_remainder);
23737db96d56Sopenharmony_ci    Py_DECREF(pyus_remainder);
23747db96d56Sopenharmony_ci    if (remainder == NULL)
23757db96d56Sopenharmony_ci        return NULL;
23767db96d56Sopenharmony_ci
23777db96d56Sopenharmony_ci    return remainder;
23787db96d56Sopenharmony_ci}
23797db96d56Sopenharmony_ci
23807db96d56Sopenharmony_cistatic PyObject *
23817db96d56Sopenharmony_cidelta_divmod(PyObject *left, PyObject *right)
23827db96d56Sopenharmony_ci{
23837db96d56Sopenharmony_ci    PyObject *pyus_left;
23847db96d56Sopenharmony_ci    PyObject *pyus_right;
23857db96d56Sopenharmony_ci    PyObject *divmod;
23867db96d56Sopenharmony_ci    PyObject *delta;
23877db96d56Sopenharmony_ci    PyObject *result;
23887db96d56Sopenharmony_ci
23897db96d56Sopenharmony_ci    if (!PyDelta_Check(left) || !PyDelta_Check(right))
23907db96d56Sopenharmony_ci        Py_RETURN_NOTIMPLEMENTED;
23917db96d56Sopenharmony_ci
23927db96d56Sopenharmony_ci    pyus_left = delta_to_microseconds((PyDateTime_Delta *)left);
23937db96d56Sopenharmony_ci    if (pyus_left == NULL)
23947db96d56Sopenharmony_ci        return NULL;
23957db96d56Sopenharmony_ci
23967db96d56Sopenharmony_ci    pyus_right = delta_to_microseconds((PyDateTime_Delta *)right);
23977db96d56Sopenharmony_ci    if (pyus_right == NULL) {
23987db96d56Sopenharmony_ci        Py_DECREF(pyus_left);
23997db96d56Sopenharmony_ci        return NULL;
24007db96d56Sopenharmony_ci    }
24017db96d56Sopenharmony_ci
24027db96d56Sopenharmony_ci    divmod = checked_divmod(pyus_left, pyus_right);
24037db96d56Sopenharmony_ci    Py_DECREF(pyus_left);
24047db96d56Sopenharmony_ci    Py_DECREF(pyus_right);
24057db96d56Sopenharmony_ci    if (divmod == NULL)
24067db96d56Sopenharmony_ci        return NULL;
24077db96d56Sopenharmony_ci
24087db96d56Sopenharmony_ci    delta = microseconds_to_delta(PyTuple_GET_ITEM(divmod, 1));
24097db96d56Sopenharmony_ci    if (delta == NULL) {
24107db96d56Sopenharmony_ci        Py_DECREF(divmod);
24117db96d56Sopenharmony_ci        return NULL;
24127db96d56Sopenharmony_ci    }
24137db96d56Sopenharmony_ci    result = PyTuple_Pack(2, PyTuple_GET_ITEM(divmod, 0), delta);
24147db96d56Sopenharmony_ci    Py_DECREF(delta);
24157db96d56Sopenharmony_ci    Py_DECREF(divmod);
24167db96d56Sopenharmony_ci    return result;
24177db96d56Sopenharmony_ci}
24187db96d56Sopenharmony_ci
24197db96d56Sopenharmony_ci/* Fold in the value of the tag ("seconds", "weeks", etc) component of a
24207db96d56Sopenharmony_ci * timedelta constructor.  sofar is the # of microseconds accounted for
24217db96d56Sopenharmony_ci * so far, and there are factor microseconds per current unit, the number
24227db96d56Sopenharmony_ci * of which is given by num.  num * factor is added to sofar in a
24237db96d56Sopenharmony_ci * numerically careful way, and that's the result.  Any fractional
24247db96d56Sopenharmony_ci * microseconds left over (this can happen if num is a float type) are
24257db96d56Sopenharmony_ci * added into *leftover.
24267db96d56Sopenharmony_ci * Note that there are many ways this can give an error (NULL) return.
24277db96d56Sopenharmony_ci */
24287db96d56Sopenharmony_cistatic PyObject *
24297db96d56Sopenharmony_ciaccum(const char* tag, PyObject *sofar, PyObject *num, PyObject *factor,
24307db96d56Sopenharmony_ci      double *leftover)
24317db96d56Sopenharmony_ci{
24327db96d56Sopenharmony_ci    PyObject *prod;
24337db96d56Sopenharmony_ci    PyObject *sum;
24347db96d56Sopenharmony_ci
24357db96d56Sopenharmony_ci    assert(num != NULL);
24367db96d56Sopenharmony_ci
24377db96d56Sopenharmony_ci    if (PyLong_Check(num)) {
24387db96d56Sopenharmony_ci        prod = PyNumber_Multiply(num, factor);
24397db96d56Sopenharmony_ci        if (prod == NULL)
24407db96d56Sopenharmony_ci            return NULL;
24417db96d56Sopenharmony_ci        sum = PyNumber_Add(sofar, prod);
24427db96d56Sopenharmony_ci        Py_DECREF(prod);
24437db96d56Sopenharmony_ci        return sum;
24447db96d56Sopenharmony_ci    }
24457db96d56Sopenharmony_ci
24467db96d56Sopenharmony_ci    if (PyFloat_Check(num)) {
24477db96d56Sopenharmony_ci        double dnum;
24487db96d56Sopenharmony_ci        double fracpart;
24497db96d56Sopenharmony_ci        double intpart;
24507db96d56Sopenharmony_ci        PyObject *x;
24517db96d56Sopenharmony_ci        PyObject *y;
24527db96d56Sopenharmony_ci
24537db96d56Sopenharmony_ci        /* The Plan:  decompose num into an integer part and a
24547db96d56Sopenharmony_ci         * fractional part, num = intpart + fracpart.
24557db96d56Sopenharmony_ci         * Then num * factor ==
24567db96d56Sopenharmony_ci         *      intpart * factor + fracpart * factor
24577db96d56Sopenharmony_ci         * and the LHS can be computed exactly in long arithmetic.
24587db96d56Sopenharmony_ci         * The RHS is again broken into an int part and frac part.
24597db96d56Sopenharmony_ci         * and the frac part is added into *leftover.
24607db96d56Sopenharmony_ci         */
24617db96d56Sopenharmony_ci        dnum = PyFloat_AsDouble(num);
24627db96d56Sopenharmony_ci        if (dnum == -1.0 && PyErr_Occurred())
24637db96d56Sopenharmony_ci            return NULL;
24647db96d56Sopenharmony_ci        fracpart = modf(dnum, &intpart);
24657db96d56Sopenharmony_ci        x = PyLong_FromDouble(intpart);
24667db96d56Sopenharmony_ci        if (x == NULL)
24677db96d56Sopenharmony_ci            return NULL;
24687db96d56Sopenharmony_ci
24697db96d56Sopenharmony_ci        prod = PyNumber_Multiply(x, factor);
24707db96d56Sopenharmony_ci        Py_DECREF(x);
24717db96d56Sopenharmony_ci        if (prod == NULL)
24727db96d56Sopenharmony_ci            return NULL;
24737db96d56Sopenharmony_ci
24747db96d56Sopenharmony_ci        sum = PyNumber_Add(sofar, prod);
24757db96d56Sopenharmony_ci        Py_DECREF(prod);
24767db96d56Sopenharmony_ci        if (sum == NULL)
24777db96d56Sopenharmony_ci            return NULL;
24787db96d56Sopenharmony_ci
24797db96d56Sopenharmony_ci        if (fracpart == 0.0)
24807db96d56Sopenharmony_ci            return sum;
24817db96d56Sopenharmony_ci        /* So far we've lost no information.  Dealing with the
24827db96d56Sopenharmony_ci         * fractional part requires float arithmetic, and may
24837db96d56Sopenharmony_ci         * lose a little info.
24847db96d56Sopenharmony_ci         */
24857db96d56Sopenharmony_ci        assert(PyLong_CheckExact(factor));
24867db96d56Sopenharmony_ci        dnum = PyLong_AsDouble(factor);
24877db96d56Sopenharmony_ci
24887db96d56Sopenharmony_ci        dnum *= fracpart;
24897db96d56Sopenharmony_ci        fracpart = modf(dnum, &intpart);
24907db96d56Sopenharmony_ci        x = PyLong_FromDouble(intpart);
24917db96d56Sopenharmony_ci        if (x == NULL) {
24927db96d56Sopenharmony_ci            Py_DECREF(sum);
24937db96d56Sopenharmony_ci            return NULL;
24947db96d56Sopenharmony_ci        }
24957db96d56Sopenharmony_ci
24967db96d56Sopenharmony_ci        y = PyNumber_Add(sum, x);
24977db96d56Sopenharmony_ci        Py_DECREF(sum);
24987db96d56Sopenharmony_ci        Py_DECREF(x);
24997db96d56Sopenharmony_ci        *leftover += fracpart;
25007db96d56Sopenharmony_ci        return y;
25017db96d56Sopenharmony_ci    }
25027db96d56Sopenharmony_ci
25037db96d56Sopenharmony_ci    PyErr_Format(PyExc_TypeError,
25047db96d56Sopenharmony_ci                 "unsupported type for timedelta %s component: %s",
25057db96d56Sopenharmony_ci                 tag, Py_TYPE(num)->tp_name);
25067db96d56Sopenharmony_ci    return NULL;
25077db96d56Sopenharmony_ci}
25087db96d56Sopenharmony_ci
25097db96d56Sopenharmony_cistatic PyObject *
25107db96d56Sopenharmony_cidelta_new(PyTypeObject *type, PyObject *args, PyObject *kw)
25117db96d56Sopenharmony_ci{
25127db96d56Sopenharmony_ci    PyObject *self = NULL;
25137db96d56Sopenharmony_ci
25147db96d56Sopenharmony_ci    /* Argument objects. */
25157db96d56Sopenharmony_ci    PyObject *day = NULL;
25167db96d56Sopenharmony_ci    PyObject *second = NULL;
25177db96d56Sopenharmony_ci    PyObject *us = NULL;
25187db96d56Sopenharmony_ci    PyObject *ms = NULL;
25197db96d56Sopenharmony_ci    PyObject *minute = NULL;
25207db96d56Sopenharmony_ci    PyObject *hour = NULL;
25217db96d56Sopenharmony_ci    PyObject *week = NULL;
25227db96d56Sopenharmony_ci
25237db96d56Sopenharmony_ci    PyObject *x = NULL;         /* running sum of microseconds */
25247db96d56Sopenharmony_ci    PyObject *y = NULL;         /* temp sum of microseconds */
25257db96d56Sopenharmony_ci    double leftover_us = 0.0;
25267db96d56Sopenharmony_ci
25277db96d56Sopenharmony_ci    static char *keywords[] = {
25287db96d56Sopenharmony_ci        "days", "seconds", "microseconds", "milliseconds",
25297db96d56Sopenharmony_ci        "minutes", "hours", "weeks", NULL
25307db96d56Sopenharmony_ci    };
25317db96d56Sopenharmony_ci
25327db96d56Sopenharmony_ci    if (PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOO:__new__",
25337db96d56Sopenharmony_ci                                    keywords,
25347db96d56Sopenharmony_ci                                    &day, &second, &us,
25357db96d56Sopenharmony_ci                                    &ms, &minute, &hour, &week) == 0)
25367db96d56Sopenharmony_ci        goto Done;
25377db96d56Sopenharmony_ci
25387db96d56Sopenharmony_ci    x = PyLong_FromLong(0);
25397db96d56Sopenharmony_ci    if (x == NULL)
25407db96d56Sopenharmony_ci        goto Done;
25417db96d56Sopenharmony_ci
25427db96d56Sopenharmony_ci#define CLEANUP         \
25437db96d56Sopenharmony_ci    Py_DECREF(x);       \
25447db96d56Sopenharmony_ci    x = y;              \
25457db96d56Sopenharmony_ci    if (x == NULL)      \
25467db96d56Sopenharmony_ci        goto Done
25477db96d56Sopenharmony_ci
25487db96d56Sopenharmony_ci    if (us) {
25497db96d56Sopenharmony_ci        y = accum("microseconds", x, us, _PyLong_GetOne(), &leftover_us);
25507db96d56Sopenharmony_ci        CLEANUP;
25517db96d56Sopenharmony_ci    }
25527db96d56Sopenharmony_ci    if (ms) {
25537db96d56Sopenharmony_ci        y = accum("milliseconds", x, ms, us_per_ms, &leftover_us);
25547db96d56Sopenharmony_ci        CLEANUP;
25557db96d56Sopenharmony_ci    }
25567db96d56Sopenharmony_ci    if (second) {
25577db96d56Sopenharmony_ci        y = accum("seconds", x, second, us_per_second, &leftover_us);
25587db96d56Sopenharmony_ci        CLEANUP;
25597db96d56Sopenharmony_ci    }
25607db96d56Sopenharmony_ci    if (minute) {
25617db96d56Sopenharmony_ci        y = accum("minutes", x, minute, us_per_minute, &leftover_us);
25627db96d56Sopenharmony_ci        CLEANUP;
25637db96d56Sopenharmony_ci    }
25647db96d56Sopenharmony_ci    if (hour) {
25657db96d56Sopenharmony_ci        y = accum("hours", x, hour, us_per_hour, &leftover_us);
25667db96d56Sopenharmony_ci        CLEANUP;
25677db96d56Sopenharmony_ci    }
25687db96d56Sopenharmony_ci    if (day) {
25697db96d56Sopenharmony_ci        y = accum("days", x, day, us_per_day, &leftover_us);
25707db96d56Sopenharmony_ci        CLEANUP;
25717db96d56Sopenharmony_ci    }
25727db96d56Sopenharmony_ci    if (week) {
25737db96d56Sopenharmony_ci        y = accum("weeks", x, week, us_per_week, &leftover_us);
25747db96d56Sopenharmony_ci        CLEANUP;
25757db96d56Sopenharmony_ci    }
25767db96d56Sopenharmony_ci    if (leftover_us) {
25777db96d56Sopenharmony_ci        /* Round to nearest whole # of us, and add into x. */
25787db96d56Sopenharmony_ci        double whole_us = round(leftover_us);
25797db96d56Sopenharmony_ci        int x_is_odd;
25807db96d56Sopenharmony_ci        PyObject *temp;
25817db96d56Sopenharmony_ci
25827db96d56Sopenharmony_ci        if (fabs(whole_us - leftover_us) == 0.5) {
25837db96d56Sopenharmony_ci            /* We're exactly halfway between two integers.  In order
25847db96d56Sopenharmony_ci             * to do round-half-to-even, we must determine whether x
25857db96d56Sopenharmony_ci             * is odd. Note that x is odd when it's last bit is 1. The
25867db96d56Sopenharmony_ci             * code below uses bitwise and operation to check the last
25877db96d56Sopenharmony_ci             * bit. */
25887db96d56Sopenharmony_ci            temp = PyNumber_And(x, _PyLong_GetOne());  /* temp <- x & 1 */
25897db96d56Sopenharmony_ci            if (temp == NULL) {
25907db96d56Sopenharmony_ci                Py_DECREF(x);
25917db96d56Sopenharmony_ci                goto Done;
25927db96d56Sopenharmony_ci            }
25937db96d56Sopenharmony_ci            x_is_odd = PyObject_IsTrue(temp);
25947db96d56Sopenharmony_ci            Py_DECREF(temp);
25957db96d56Sopenharmony_ci            if (x_is_odd == -1) {
25967db96d56Sopenharmony_ci                Py_DECREF(x);
25977db96d56Sopenharmony_ci                goto Done;
25987db96d56Sopenharmony_ci            }
25997db96d56Sopenharmony_ci            whole_us = 2.0 * round((leftover_us + x_is_odd) * 0.5) - x_is_odd;
26007db96d56Sopenharmony_ci        }
26017db96d56Sopenharmony_ci
26027db96d56Sopenharmony_ci        temp = PyLong_FromLong((long)whole_us);
26037db96d56Sopenharmony_ci
26047db96d56Sopenharmony_ci        if (temp == NULL) {
26057db96d56Sopenharmony_ci            Py_DECREF(x);
26067db96d56Sopenharmony_ci            goto Done;
26077db96d56Sopenharmony_ci        }
26087db96d56Sopenharmony_ci        y = PyNumber_Add(x, temp);
26097db96d56Sopenharmony_ci        Py_DECREF(temp);
26107db96d56Sopenharmony_ci        CLEANUP;
26117db96d56Sopenharmony_ci    }
26127db96d56Sopenharmony_ci
26137db96d56Sopenharmony_ci    self = microseconds_to_delta_ex(x, type);
26147db96d56Sopenharmony_ci    Py_DECREF(x);
26157db96d56Sopenharmony_ciDone:
26167db96d56Sopenharmony_ci    return self;
26177db96d56Sopenharmony_ci
26187db96d56Sopenharmony_ci#undef CLEANUP
26197db96d56Sopenharmony_ci}
26207db96d56Sopenharmony_ci
26217db96d56Sopenharmony_cistatic int
26227db96d56Sopenharmony_cidelta_bool(PyDateTime_Delta *self)
26237db96d56Sopenharmony_ci{
26247db96d56Sopenharmony_ci    return (GET_TD_DAYS(self) != 0
26257db96d56Sopenharmony_ci        || GET_TD_SECONDS(self) != 0
26267db96d56Sopenharmony_ci        || GET_TD_MICROSECONDS(self) != 0);
26277db96d56Sopenharmony_ci}
26287db96d56Sopenharmony_ci
26297db96d56Sopenharmony_cistatic PyObject *
26307db96d56Sopenharmony_cidelta_repr(PyDateTime_Delta *self)
26317db96d56Sopenharmony_ci{
26327db96d56Sopenharmony_ci    PyObject *args = PyUnicode_FromString("");
26337db96d56Sopenharmony_ci
26347db96d56Sopenharmony_ci    if (args == NULL) {
26357db96d56Sopenharmony_ci        return NULL;
26367db96d56Sopenharmony_ci    }
26377db96d56Sopenharmony_ci
26387db96d56Sopenharmony_ci    const char *sep = "";
26397db96d56Sopenharmony_ci
26407db96d56Sopenharmony_ci    if (GET_TD_DAYS(self) != 0) {
26417db96d56Sopenharmony_ci        Py_SETREF(args, PyUnicode_FromFormat("days=%d", GET_TD_DAYS(self)));
26427db96d56Sopenharmony_ci        if (args == NULL) {
26437db96d56Sopenharmony_ci            return NULL;
26447db96d56Sopenharmony_ci        }
26457db96d56Sopenharmony_ci        sep = ", ";
26467db96d56Sopenharmony_ci    }
26477db96d56Sopenharmony_ci
26487db96d56Sopenharmony_ci    if (GET_TD_SECONDS(self) != 0) {
26497db96d56Sopenharmony_ci        Py_SETREF(args, PyUnicode_FromFormat("%U%sseconds=%d", args, sep,
26507db96d56Sopenharmony_ci                                             GET_TD_SECONDS(self)));
26517db96d56Sopenharmony_ci        if (args == NULL) {
26527db96d56Sopenharmony_ci            return NULL;
26537db96d56Sopenharmony_ci        }
26547db96d56Sopenharmony_ci        sep = ", ";
26557db96d56Sopenharmony_ci    }
26567db96d56Sopenharmony_ci
26577db96d56Sopenharmony_ci    if (GET_TD_MICROSECONDS(self) != 0) {
26587db96d56Sopenharmony_ci        Py_SETREF(args, PyUnicode_FromFormat("%U%smicroseconds=%d", args, sep,
26597db96d56Sopenharmony_ci                                             GET_TD_MICROSECONDS(self)));
26607db96d56Sopenharmony_ci        if (args == NULL) {
26617db96d56Sopenharmony_ci            return NULL;
26627db96d56Sopenharmony_ci        }
26637db96d56Sopenharmony_ci    }
26647db96d56Sopenharmony_ci
26657db96d56Sopenharmony_ci    if (PyUnicode_GET_LENGTH(args) == 0) {
26667db96d56Sopenharmony_ci        Py_SETREF(args, PyUnicode_FromString("0"));
26677db96d56Sopenharmony_ci        if (args == NULL) {
26687db96d56Sopenharmony_ci            return NULL;
26697db96d56Sopenharmony_ci        }
26707db96d56Sopenharmony_ci    }
26717db96d56Sopenharmony_ci
26727db96d56Sopenharmony_ci    PyObject *repr = PyUnicode_FromFormat("%s(%S)", Py_TYPE(self)->tp_name,
26737db96d56Sopenharmony_ci                                          args);
26747db96d56Sopenharmony_ci    Py_DECREF(args);
26757db96d56Sopenharmony_ci    return repr;
26767db96d56Sopenharmony_ci}
26777db96d56Sopenharmony_ci
26787db96d56Sopenharmony_cistatic PyObject *
26797db96d56Sopenharmony_cidelta_str(PyDateTime_Delta *self)
26807db96d56Sopenharmony_ci{
26817db96d56Sopenharmony_ci    int us = GET_TD_MICROSECONDS(self);
26827db96d56Sopenharmony_ci    int seconds = GET_TD_SECONDS(self);
26837db96d56Sopenharmony_ci    int minutes = divmod(seconds, 60, &seconds);
26847db96d56Sopenharmony_ci    int hours = divmod(minutes, 60, &minutes);
26857db96d56Sopenharmony_ci    int days = GET_TD_DAYS(self);
26867db96d56Sopenharmony_ci
26877db96d56Sopenharmony_ci    if (days) {
26887db96d56Sopenharmony_ci        if (us)
26897db96d56Sopenharmony_ci            return PyUnicode_FromFormat("%d day%s, %d:%02d:%02d.%06d",
26907db96d56Sopenharmony_ci                                        days, (days == 1 || days == -1) ? "" : "s",
26917db96d56Sopenharmony_ci                                        hours, minutes, seconds, us);
26927db96d56Sopenharmony_ci        else
26937db96d56Sopenharmony_ci            return PyUnicode_FromFormat("%d day%s, %d:%02d:%02d",
26947db96d56Sopenharmony_ci                                        days, (days == 1 || days == -1) ? "" : "s",
26957db96d56Sopenharmony_ci                                        hours, minutes, seconds);
26967db96d56Sopenharmony_ci    } else {
26977db96d56Sopenharmony_ci        if (us)
26987db96d56Sopenharmony_ci            return PyUnicode_FromFormat("%d:%02d:%02d.%06d",
26997db96d56Sopenharmony_ci                                        hours, minutes, seconds, us);
27007db96d56Sopenharmony_ci        else
27017db96d56Sopenharmony_ci            return PyUnicode_FromFormat("%d:%02d:%02d",
27027db96d56Sopenharmony_ci                                        hours, minutes, seconds);
27037db96d56Sopenharmony_ci    }
27047db96d56Sopenharmony_ci
27057db96d56Sopenharmony_ci}
27067db96d56Sopenharmony_ci
27077db96d56Sopenharmony_ci/* Pickle support, a simple use of __reduce__. */
27087db96d56Sopenharmony_ci
27097db96d56Sopenharmony_ci/* __getstate__ isn't exposed */
27107db96d56Sopenharmony_cistatic PyObject *
27117db96d56Sopenharmony_cidelta_getstate(PyDateTime_Delta *self)
27127db96d56Sopenharmony_ci{
27137db96d56Sopenharmony_ci    return Py_BuildValue("iii", GET_TD_DAYS(self),
27147db96d56Sopenharmony_ci                                GET_TD_SECONDS(self),
27157db96d56Sopenharmony_ci                                GET_TD_MICROSECONDS(self));
27167db96d56Sopenharmony_ci}
27177db96d56Sopenharmony_ci
27187db96d56Sopenharmony_cistatic PyObject *
27197db96d56Sopenharmony_cidelta_total_seconds(PyObject *self, PyObject *Py_UNUSED(ignored))
27207db96d56Sopenharmony_ci{
27217db96d56Sopenharmony_ci    PyObject *total_seconds;
27227db96d56Sopenharmony_ci    PyObject *total_microseconds;
27237db96d56Sopenharmony_ci
27247db96d56Sopenharmony_ci    total_microseconds = delta_to_microseconds((PyDateTime_Delta *)self);
27257db96d56Sopenharmony_ci    if (total_microseconds == NULL)
27267db96d56Sopenharmony_ci        return NULL;
27277db96d56Sopenharmony_ci
27287db96d56Sopenharmony_ci    total_seconds = PyNumber_TrueDivide(total_microseconds, us_per_second);
27297db96d56Sopenharmony_ci
27307db96d56Sopenharmony_ci    Py_DECREF(total_microseconds);
27317db96d56Sopenharmony_ci    return total_seconds;
27327db96d56Sopenharmony_ci}
27337db96d56Sopenharmony_ci
27347db96d56Sopenharmony_cistatic PyObject *
27357db96d56Sopenharmony_cidelta_reduce(PyDateTime_Delta* self, PyObject *Py_UNUSED(ignored))
27367db96d56Sopenharmony_ci{
27377db96d56Sopenharmony_ci    return Py_BuildValue("ON", Py_TYPE(self), delta_getstate(self));
27387db96d56Sopenharmony_ci}
27397db96d56Sopenharmony_ci
27407db96d56Sopenharmony_ci#define OFFSET(field)  offsetof(PyDateTime_Delta, field)
27417db96d56Sopenharmony_ci
27427db96d56Sopenharmony_cistatic PyMemberDef delta_members[] = {
27437db96d56Sopenharmony_ci
27447db96d56Sopenharmony_ci    {"days",         T_INT, OFFSET(days),         READONLY,
27457db96d56Sopenharmony_ci     PyDoc_STR("Number of days.")},
27467db96d56Sopenharmony_ci
27477db96d56Sopenharmony_ci    {"seconds",      T_INT, OFFSET(seconds),      READONLY,
27487db96d56Sopenharmony_ci     PyDoc_STR("Number of seconds (>= 0 and less than 1 day).")},
27497db96d56Sopenharmony_ci
27507db96d56Sopenharmony_ci    {"microseconds", T_INT, OFFSET(microseconds), READONLY,
27517db96d56Sopenharmony_ci     PyDoc_STR("Number of microseconds (>= 0 and less than 1 second).")},
27527db96d56Sopenharmony_ci    {NULL}
27537db96d56Sopenharmony_ci};
27547db96d56Sopenharmony_ci
27557db96d56Sopenharmony_cistatic PyMethodDef delta_methods[] = {
27567db96d56Sopenharmony_ci    {"total_seconds", delta_total_seconds, METH_NOARGS,
27577db96d56Sopenharmony_ci     PyDoc_STR("Total seconds in the duration.")},
27587db96d56Sopenharmony_ci
27597db96d56Sopenharmony_ci    {"__reduce__", (PyCFunction)delta_reduce, METH_NOARGS,
27607db96d56Sopenharmony_ci     PyDoc_STR("__reduce__() -> (cls, state)")},
27617db96d56Sopenharmony_ci
27627db96d56Sopenharmony_ci    {NULL,      NULL},
27637db96d56Sopenharmony_ci};
27647db96d56Sopenharmony_ci
27657db96d56Sopenharmony_cistatic const char delta_doc[] =
27667db96d56Sopenharmony_ciPyDoc_STR("Difference between two datetime values.\n\n"
27677db96d56Sopenharmony_ci          "timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, "
27687db96d56Sopenharmony_ci          "minutes=0, hours=0, weeks=0)\n\n"
27697db96d56Sopenharmony_ci          "All arguments are optional and default to 0.\n"
27707db96d56Sopenharmony_ci          "Arguments may be integers or floats, and may be positive or negative.");
27717db96d56Sopenharmony_ci
27727db96d56Sopenharmony_cistatic PyNumberMethods delta_as_number = {
27737db96d56Sopenharmony_ci    delta_add,                                  /* nb_add */
27747db96d56Sopenharmony_ci    delta_subtract,                             /* nb_subtract */
27757db96d56Sopenharmony_ci    delta_multiply,                             /* nb_multiply */
27767db96d56Sopenharmony_ci    delta_remainder,                            /* nb_remainder */
27777db96d56Sopenharmony_ci    delta_divmod,                               /* nb_divmod */
27787db96d56Sopenharmony_ci    0,                                          /* nb_power */
27797db96d56Sopenharmony_ci    (unaryfunc)delta_negative,                  /* nb_negative */
27807db96d56Sopenharmony_ci    (unaryfunc)delta_positive,                  /* nb_positive */
27817db96d56Sopenharmony_ci    (unaryfunc)delta_abs,                       /* nb_absolute */
27827db96d56Sopenharmony_ci    (inquiry)delta_bool,                        /* nb_bool */
27837db96d56Sopenharmony_ci    0,                                          /*nb_invert*/
27847db96d56Sopenharmony_ci    0,                                          /*nb_lshift*/
27857db96d56Sopenharmony_ci    0,                                          /*nb_rshift*/
27867db96d56Sopenharmony_ci    0,                                          /*nb_and*/
27877db96d56Sopenharmony_ci    0,                                          /*nb_xor*/
27887db96d56Sopenharmony_ci    0,                                          /*nb_or*/
27897db96d56Sopenharmony_ci    0,                                          /*nb_int*/
27907db96d56Sopenharmony_ci    0,                                          /*nb_reserved*/
27917db96d56Sopenharmony_ci    0,                                          /*nb_float*/
27927db96d56Sopenharmony_ci    0,                                          /*nb_inplace_add*/
27937db96d56Sopenharmony_ci    0,                                          /*nb_inplace_subtract*/
27947db96d56Sopenharmony_ci    0,                                          /*nb_inplace_multiply*/
27957db96d56Sopenharmony_ci    0,                                          /*nb_inplace_remainder*/
27967db96d56Sopenharmony_ci    0,                                          /*nb_inplace_power*/
27977db96d56Sopenharmony_ci    0,                                          /*nb_inplace_lshift*/
27987db96d56Sopenharmony_ci    0,                                          /*nb_inplace_rshift*/
27997db96d56Sopenharmony_ci    0,                                          /*nb_inplace_and*/
28007db96d56Sopenharmony_ci    0,                                          /*nb_inplace_xor*/
28017db96d56Sopenharmony_ci    0,                                          /*nb_inplace_or*/
28027db96d56Sopenharmony_ci    delta_divide,                               /* nb_floor_divide */
28037db96d56Sopenharmony_ci    delta_truedivide,                           /* nb_true_divide */
28047db96d56Sopenharmony_ci    0,                                          /* nb_inplace_floor_divide */
28057db96d56Sopenharmony_ci    0,                                          /* nb_inplace_true_divide */
28067db96d56Sopenharmony_ci};
28077db96d56Sopenharmony_ci
28087db96d56Sopenharmony_cistatic PyTypeObject PyDateTime_DeltaType = {
28097db96d56Sopenharmony_ci    PyVarObject_HEAD_INIT(NULL, 0)
28107db96d56Sopenharmony_ci    "datetime.timedelta",                               /* tp_name */
28117db96d56Sopenharmony_ci    sizeof(PyDateTime_Delta),                           /* tp_basicsize */
28127db96d56Sopenharmony_ci    0,                                                  /* tp_itemsize */
28137db96d56Sopenharmony_ci    0,                                                  /* tp_dealloc */
28147db96d56Sopenharmony_ci    0,                                                  /* tp_vectorcall_offset */
28157db96d56Sopenharmony_ci    0,                                                  /* tp_getattr */
28167db96d56Sopenharmony_ci    0,                                                  /* tp_setattr */
28177db96d56Sopenharmony_ci    0,                                                  /* tp_as_async */
28187db96d56Sopenharmony_ci    (reprfunc)delta_repr,                               /* tp_repr */
28197db96d56Sopenharmony_ci    &delta_as_number,                                   /* tp_as_number */
28207db96d56Sopenharmony_ci    0,                                                  /* tp_as_sequence */
28217db96d56Sopenharmony_ci    0,                                                  /* tp_as_mapping */
28227db96d56Sopenharmony_ci    (hashfunc)delta_hash,                               /* tp_hash */
28237db96d56Sopenharmony_ci    0,                                                  /* tp_call */
28247db96d56Sopenharmony_ci    (reprfunc)delta_str,                                /* tp_str */
28257db96d56Sopenharmony_ci    PyObject_GenericGetAttr,                            /* tp_getattro */
28267db96d56Sopenharmony_ci    0,                                                  /* tp_setattro */
28277db96d56Sopenharmony_ci    0,                                                  /* tp_as_buffer */
28287db96d56Sopenharmony_ci    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,           /* tp_flags */
28297db96d56Sopenharmony_ci    delta_doc,                                          /* tp_doc */
28307db96d56Sopenharmony_ci    0,                                                  /* tp_traverse */
28317db96d56Sopenharmony_ci    0,                                                  /* tp_clear */
28327db96d56Sopenharmony_ci    delta_richcompare,                                  /* tp_richcompare */
28337db96d56Sopenharmony_ci    0,                                                  /* tp_weaklistoffset */
28347db96d56Sopenharmony_ci    0,                                                  /* tp_iter */
28357db96d56Sopenharmony_ci    0,                                                  /* tp_iternext */
28367db96d56Sopenharmony_ci    delta_methods,                                      /* tp_methods */
28377db96d56Sopenharmony_ci    delta_members,                                      /* tp_members */
28387db96d56Sopenharmony_ci    0,                                                  /* tp_getset */
28397db96d56Sopenharmony_ci    0,                                                  /* tp_base */
28407db96d56Sopenharmony_ci    0,                                                  /* tp_dict */
28417db96d56Sopenharmony_ci    0,                                                  /* tp_descr_get */
28427db96d56Sopenharmony_ci    0,                                                  /* tp_descr_set */
28437db96d56Sopenharmony_ci    0,                                                  /* tp_dictoffset */
28447db96d56Sopenharmony_ci    0,                                                  /* tp_init */
28457db96d56Sopenharmony_ci    0,                                                  /* tp_alloc */
28467db96d56Sopenharmony_ci    delta_new,                                          /* tp_new */
28477db96d56Sopenharmony_ci    0,                                                  /* tp_free */
28487db96d56Sopenharmony_ci};
28497db96d56Sopenharmony_ci
28507db96d56Sopenharmony_ci/*
28517db96d56Sopenharmony_ci * PyDateTime_Date implementation.
28527db96d56Sopenharmony_ci */
28537db96d56Sopenharmony_ci
28547db96d56Sopenharmony_ci/* Accessor properties. */
28557db96d56Sopenharmony_ci
28567db96d56Sopenharmony_cistatic PyObject *
28577db96d56Sopenharmony_cidate_year(PyDateTime_Date *self, void *unused)
28587db96d56Sopenharmony_ci{
28597db96d56Sopenharmony_ci    return PyLong_FromLong(GET_YEAR(self));
28607db96d56Sopenharmony_ci}
28617db96d56Sopenharmony_ci
28627db96d56Sopenharmony_cistatic PyObject *
28637db96d56Sopenharmony_cidate_month(PyDateTime_Date *self, void *unused)
28647db96d56Sopenharmony_ci{
28657db96d56Sopenharmony_ci    return PyLong_FromLong(GET_MONTH(self));
28667db96d56Sopenharmony_ci}
28677db96d56Sopenharmony_ci
28687db96d56Sopenharmony_cistatic PyObject *
28697db96d56Sopenharmony_cidate_day(PyDateTime_Date *self, void *unused)
28707db96d56Sopenharmony_ci{
28717db96d56Sopenharmony_ci    return PyLong_FromLong(GET_DAY(self));
28727db96d56Sopenharmony_ci}
28737db96d56Sopenharmony_ci
28747db96d56Sopenharmony_cistatic PyGetSetDef date_getset[] = {
28757db96d56Sopenharmony_ci    {"year",        (getter)date_year},
28767db96d56Sopenharmony_ci    {"month",       (getter)date_month},
28777db96d56Sopenharmony_ci    {"day",         (getter)date_day},
28787db96d56Sopenharmony_ci    {NULL}
28797db96d56Sopenharmony_ci};
28807db96d56Sopenharmony_ci
28817db96d56Sopenharmony_ci/* Constructors. */
28827db96d56Sopenharmony_ci
28837db96d56Sopenharmony_cistatic char *date_kws[] = {"year", "month", "day", NULL};
28847db96d56Sopenharmony_ci
28857db96d56Sopenharmony_cistatic PyObject *
28867db96d56Sopenharmony_cidate_from_pickle(PyTypeObject *type, PyObject *state)
28877db96d56Sopenharmony_ci{
28887db96d56Sopenharmony_ci    PyDateTime_Date *me;
28897db96d56Sopenharmony_ci
28907db96d56Sopenharmony_ci    me = (PyDateTime_Date *) (type->tp_alloc(type, 0));
28917db96d56Sopenharmony_ci    if (me != NULL) {
28927db96d56Sopenharmony_ci        const char *pdata = PyBytes_AS_STRING(state);
28937db96d56Sopenharmony_ci        memcpy(me->data, pdata, _PyDateTime_DATE_DATASIZE);
28947db96d56Sopenharmony_ci        me->hashcode = -1;
28957db96d56Sopenharmony_ci    }
28967db96d56Sopenharmony_ci    return (PyObject *)me;
28977db96d56Sopenharmony_ci}
28987db96d56Sopenharmony_ci
28997db96d56Sopenharmony_cistatic PyObject *
29007db96d56Sopenharmony_cidate_new(PyTypeObject *type, PyObject *args, PyObject *kw)
29017db96d56Sopenharmony_ci{
29027db96d56Sopenharmony_ci    PyObject *self = NULL;
29037db96d56Sopenharmony_ci    int year;
29047db96d56Sopenharmony_ci    int month;
29057db96d56Sopenharmony_ci    int day;
29067db96d56Sopenharmony_ci
29077db96d56Sopenharmony_ci    /* Check for invocation from pickle with __getstate__ state */
29087db96d56Sopenharmony_ci    if (PyTuple_GET_SIZE(args) == 1) {
29097db96d56Sopenharmony_ci        PyObject *state = PyTuple_GET_ITEM(args, 0);
29107db96d56Sopenharmony_ci        if (PyBytes_Check(state)) {
29117db96d56Sopenharmony_ci            if (PyBytes_GET_SIZE(state) == _PyDateTime_DATE_DATASIZE &&
29127db96d56Sopenharmony_ci                MONTH_IS_SANE(PyBytes_AS_STRING(state)[2]))
29137db96d56Sopenharmony_ci            {
29147db96d56Sopenharmony_ci                return date_from_pickle(type, state);
29157db96d56Sopenharmony_ci            }
29167db96d56Sopenharmony_ci        }
29177db96d56Sopenharmony_ci        else if (PyUnicode_Check(state)) {
29187db96d56Sopenharmony_ci            if (PyUnicode_READY(state)) {
29197db96d56Sopenharmony_ci                return NULL;
29207db96d56Sopenharmony_ci            }
29217db96d56Sopenharmony_ci            if (PyUnicode_GET_LENGTH(state) == _PyDateTime_DATE_DATASIZE &&
29227db96d56Sopenharmony_ci                MONTH_IS_SANE(PyUnicode_READ_CHAR(state, 2)))
29237db96d56Sopenharmony_ci            {
29247db96d56Sopenharmony_ci                state = PyUnicode_AsLatin1String(state);
29257db96d56Sopenharmony_ci                if (state == NULL) {
29267db96d56Sopenharmony_ci                    if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
29277db96d56Sopenharmony_ci                        /* More informative error message. */
29287db96d56Sopenharmony_ci                        PyErr_SetString(PyExc_ValueError,
29297db96d56Sopenharmony_ci                            "Failed to encode latin1 string when unpickling "
29307db96d56Sopenharmony_ci                            "a date object. "
29317db96d56Sopenharmony_ci                            "pickle.load(data, encoding='latin1') is assumed.");
29327db96d56Sopenharmony_ci                    }
29337db96d56Sopenharmony_ci                    return NULL;
29347db96d56Sopenharmony_ci                }
29357db96d56Sopenharmony_ci                self = date_from_pickle(type, state);
29367db96d56Sopenharmony_ci                Py_DECREF(state);
29377db96d56Sopenharmony_ci                return self;
29387db96d56Sopenharmony_ci            }
29397db96d56Sopenharmony_ci        }
29407db96d56Sopenharmony_ci    }
29417db96d56Sopenharmony_ci
29427db96d56Sopenharmony_ci    if (PyArg_ParseTupleAndKeywords(args, kw, "iii", date_kws,
29437db96d56Sopenharmony_ci                                    &year, &month, &day)) {
29447db96d56Sopenharmony_ci        self = new_date_ex(year, month, day, type);
29457db96d56Sopenharmony_ci    }
29467db96d56Sopenharmony_ci    return self;
29477db96d56Sopenharmony_ci}
29487db96d56Sopenharmony_ci
29497db96d56Sopenharmony_cistatic PyObject *
29507db96d56Sopenharmony_cidate_fromtimestamp(PyObject *cls, PyObject *obj)
29517db96d56Sopenharmony_ci{
29527db96d56Sopenharmony_ci    struct tm tm;
29537db96d56Sopenharmony_ci    time_t t;
29547db96d56Sopenharmony_ci
29557db96d56Sopenharmony_ci    if (_PyTime_ObjectToTime_t(obj, &t, _PyTime_ROUND_FLOOR) == -1)
29567db96d56Sopenharmony_ci        return NULL;
29577db96d56Sopenharmony_ci
29587db96d56Sopenharmony_ci    if (_PyTime_localtime(t, &tm) != 0)
29597db96d56Sopenharmony_ci        return NULL;
29607db96d56Sopenharmony_ci
29617db96d56Sopenharmony_ci    return new_date_subclass_ex(tm.tm_year + 1900,
29627db96d56Sopenharmony_ci                                tm.tm_mon + 1,
29637db96d56Sopenharmony_ci                                tm.tm_mday,
29647db96d56Sopenharmony_ci                                cls);
29657db96d56Sopenharmony_ci}
29667db96d56Sopenharmony_ci
29677db96d56Sopenharmony_ci/* Return new date from current time.
29687db96d56Sopenharmony_ci * We say this is equivalent to fromtimestamp(time.time()), and the
29697db96d56Sopenharmony_ci * only way to be sure of that is to *call* time.time().  That's not
29707db96d56Sopenharmony_ci * generally the same as calling C's time.
29717db96d56Sopenharmony_ci */
29727db96d56Sopenharmony_cistatic PyObject *
29737db96d56Sopenharmony_cidate_today(PyObject *cls, PyObject *dummy)
29747db96d56Sopenharmony_ci{
29757db96d56Sopenharmony_ci    PyObject *time;
29767db96d56Sopenharmony_ci    PyObject *result;
29777db96d56Sopenharmony_ci    _Py_IDENTIFIER(fromtimestamp);
29787db96d56Sopenharmony_ci
29797db96d56Sopenharmony_ci    time = time_time();
29807db96d56Sopenharmony_ci    if (time == NULL)
29817db96d56Sopenharmony_ci        return NULL;
29827db96d56Sopenharmony_ci
29837db96d56Sopenharmony_ci    /* Note well:  today() is a class method, so this may not call
29847db96d56Sopenharmony_ci     * date.fromtimestamp.  For example, it may call
29857db96d56Sopenharmony_ci     * datetime.fromtimestamp.  That's why we need all the accuracy
29867db96d56Sopenharmony_ci     * time.time() delivers; if someone were gonzo about optimization,
29877db96d56Sopenharmony_ci     * date.today() could get away with plain C time().
29887db96d56Sopenharmony_ci     */
29897db96d56Sopenharmony_ci    result = _PyObject_CallMethodIdOneArg(cls, &PyId_fromtimestamp, time);
29907db96d56Sopenharmony_ci    Py_DECREF(time);
29917db96d56Sopenharmony_ci    return result;
29927db96d56Sopenharmony_ci}
29937db96d56Sopenharmony_ci
29947db96d56Sopenharmony_ci/*[clinic input]
29957db96d56Sopenharmony_ci@classmethod
29967db96d56Sopenharmony_cidatetime.date.fromtimestamp
29977db96d56Sopenharmony_ci
29987db96d56Sopenharmony_ci    timestamp: object
29997db96d56Sopenharmony_ci    /
30007db96d56Sopenharmony_ci
30017db96d56Sopenharmony_ciCreate a date from a POSIX timestamp.
30027db96d56Sopenharmony_ci
30037db96d56Sopenharmony_ciThe timestamp is a number, e.g. created via time.time(), that is interpreted
30047db96d56Sopenharmony_cias local time.
30057db96d56Sopenharmony_ci[clinic start generated code]*/
30067db96d56Sopenharmony_ci
30077db96d56Sopenharmony_cistatic PyObject *
30087db96d56Sopenharmony_cidatetime_date_fromtimestamp(PyTypeObject *type, PyObject *timestamp)
30097db96d56Sopenharmony_ci/*[clinic end generated code: output=fd045fda58168869 input=eabb3fe7f40491fe]*/
30107db96d56Sopenharmony_ci{
30117db96d56Sopenharmony_ci    return date_fromtimestamp((PyObject *) type, timestamp);
30127db96d56Sopenharmony_ci}
30137db96d56Sopenharmony_ci
30147db96d56Sopenharmony_ci/* bpo-36025: This is a wrapper for API compatibility with the public C API,
30157db96d56Sopenharmony_ci * which expects a function that takes an *args tuple, whereas the argument
30167db96d56Sopenharmony_ci * clinic generates code that takes METH_O.
30177db96d56Sopenharmony_ci */
30187db96d56Sopenharmony_cistatic PyObject *
30197db96d56Sopenharmony_cidatetime_date_fromtimestamp_capi(PyObject *cls, PyObject *args)
30207db96d56Sopenharmony_ci{
30217db96d56Sopenharmony_ci    PyObject *timestamp;
30227db96d56Sopenharmony_ci    PyObject *result = NULL;
30237db96d56Sopenharmony_ci
30247db96d56Sopenharmony_ci    if (PyArg_UnpackTuple(args, "fromtimestamp", 1, 1, &timestamp)) {
30257db96d56Sopenharmony_ci        result = date_fromtimestamp(cls, timestamp);
30267db96d56Sopenharmony_ci    }
30277db96d56Sopenharmony_ci
30287db96d56Sopenharmony_ci    return result;
30297db96d56Sopenharmony_ci}
30307db96d56Sopenharmony_ci
30317db96d56Sopenharmony_ci/* Return new date from proleptic Gregorian ordinal.  Raises ValueError if
30327db96d56Sopenharmony_ci * the ordinal is out of range.
30337db96d56Sopenharmony_ci */
30347db96d56Sopenharmony_cistatic PyObject *
30357db96d56Sopenharmony_cidate_fromordinal(PyObject *cls, PyObject *args)
30367db96d56Sopenharmony_ci{
30377db96d56Sopenharmony_ci    PyObject *result = NULL;
30387db96d56Sopenharmony_ci    int ordinal;
30397db96d56Sopenharmony_ci
30407db96d56Sopenharmony_ci    if (PyArg_ParseTuple(args, "i:fromordinal", &ordinal)) {
30417db96d56Sopenharmony_ci        int year;
30427db96d56Sopenharmony_ci        int month;
30437db96d56Sopenharmony_ci        int day;
30447db96d56Sopenharmony_ci
30457db96d56Sopenharmony_ci        if (ordinal < 1)
30467db96d56Sopenharmony_ci            PyErr_SetString(PyExc_ValueError, "ordinal must be "
30477db96d56Sopenharmony_ci                                              ">= 1");
30487db96d56Sopenharmony_ci        else {
30497db96d56Sopenharmony_ci            ord_to_ymd(ordinal, &year, &month, &day);
30507db96d56Sopenharmony_ci            result = new_date_subclass_ex(year, month, day, cls);
30517db96d56Sopenharmony_ci        }
30527db96d56Sopenharmony_ci    }
30537db96d56Sopenharmony_ci    return result;
30547db96d56Sopenharmony_ci}
30557db96d56Sopenharmony_ci
30567db96d56Sopenharmony_ci/* Return the new date from a string as generated by date.isoformat() */
30577db96d56Sopenharmony_cistatic PyObject *
30587db96d56Sopenharmony_cidate_fromisoformat(PyObject *cls, PyObject *dtstr)
30597db96d56Sopenharmony_ci{
30607db96d56Sopenharmony_ci    assert(dtstr != NULL);
30617db96d56Sopenharmony_ci
30627db96d56Sopenharmony_ci    if (!PyUnicode_Check(dtstr)) {
30637db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
30647db96d56Sopenharmony_ci                        "fromisoformat: argument must be str");
30657db96d56Sopenharmony_ci        return NULL;
30667db96d56Sopenharmony_ci    }
30677db96d56Sopenharmony_ci
30687db96d56Sopenharmony_ci    Py_ssize_t len;
30697db96d56Sopenharmony_ci
30707db96d56Sopenharmony_ci    const char *dt_ptr = PyUnicode_AsUTF8AndSize(dtstr, &len);
30717db96d56Sopenharmony_ci    if (dt_ptr == NULL) {
30727db96d56Sopenharmony_ci        goto invalid_string_error;
30737db96d56Sopenharmony_ci    }
30747db96d56Sopenharmony_ci
30757db96d56Sopenharmony_ci    int year = 0, month = 0, day = 0;
30767db96d56Sopenharmony_ci
30777db96d56Sopenharmony_ci    int rv;
30787db96d56Sopenharmony_ci    if (len == 7 || len == 8 || len == 10) {
30797db96d56Sopenharmony_ci        rv = parse_isoformat_date(dt_ptr, len, &year, &month, &day);
30807db96d56Sopenharmony_ci    }
30817db96d56Sopenharmony_ci    else {
30827db96d56Sopenharmony_ci        rv = -1;
30837db96d56Sopenharmony_ci    }
30847db96d56Sopenharmony_ci
30857db96d56Sopenharmony_ci    if (rv < 0) {
30867db96d56Sopenharmony_ci        goto invalid_string_error;
30877db96d56Sopenharmony_ci    }
30887db96d56Sopenharmony_ci
30897db96d56Sopenharmony_ci    return new_date_subclass_ex(year, month, day, cls);
30907db96d56Sopenharmony_ci
30917db96d56Sopenharmony_ciinvalid_string_error:
30927db96d56Sopenharmony_ci    PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", dtstr);
30937db96d56Sopenharmony_ci    return NULL;
30947db96d56Sopenharmony_ci}
30957db96d56Sopenharmony_ci
30967db96d56Sopenharmony_ci
30977db96d56Sopenharmony_cistatic PyObject *
30987db96d56Sopenharmony_cidate_fromisocalendar(PyObject *cls, PyObject *args, PyObject *kw)
30997db96d56Sopenharmony_ci{
31007db96d56Sopenharmony_ci    static char *keywords[] = {
31017db96d56Sopenharmony_ci        "year", "week", "day", NULL
31027db96d56Sopenharmony_ci    };
31037db96d56Sopenharmony_ci
31047db96d56Sopenharmony_ci    int year, week, day;
31057db96d56Sopenharmony_ci    if (PyArg_ParseTupleAndKeywords(args, kw, "iii:fromisocalendar",
31067db96d56Sopenharmony_ci                keywords,
31077db96d56Sopenharmony_ci                &year, &week, &day) == 0) {
31087db96d56Sopenharmony_ci        if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
31097db96d56Sopenharmony_ci            PyErr_Format(PyExc_ValueError,
31107db96d56Sopenharmony_ci                    "ISO calendar component out of range");
31117db96d56Sopenharmony_ci
31127db96d56Sopenharmony_ci        }
31137db96d56Sopenharmony_ci        return NULL;
31147db96d56Sopenharmony_ci    }
31157db96d56Sopenharmony_ci
31167db96d56Sopenharmony_ci    // Year is bounded to 0 < year < 10000 because 9999-12-31 is (9999, 52, 5)
31177db96d56Sopenharmony_ci    if (year < MINYEAR || year > MAXYEAR) {
31187db96d56Sopenharmony_ci        PyErr_Format(PyExc_ValueError, "Year is out of range: %d", year);
31197db96d56Sopenharmony_ci        return NULL;
31207db96d56Sopenharmony_ci    }
31217db96d56Sopenharmony_ci
31227db96d56Sopenharmony_ci    int month;
31237db96d56Sopenharmony_ci    int rv = iso_to_ymd(year, week, day, &year, &month, &day);
31247db96d56Sopenharmony_ci
31257db96d56Sopenharmony_ci
31267db96d56Sopenharmony_ci    if (rv == -2) {
31277db96d56Sopenharmony_ci        PyErr_Format(PyExc_ValueError, "Invalid week: %d", week);
31287db96d56Sopenharmony_ci        return NULL;
31297db96d56Sopenharmony_ci    }
31307db96d56Sopenharmony_ci
31317db96d56Sopenharmony_ci    if (rv == -3) {
31327db96d56Sopenharmony_ci        PyErr_Format(PyExc_ValueError, "Invalid day: %d (range is [1, 7])",
31337db96d56Sopenharmony_ci                     day);
31347db96d56Sopenharmony_ci        return NULL;
31357db96d56Sopenharmony_ci    }
31367db96d56Sopenharmony_ci
31377db96d56Sopenharmony_ci    return new_date_subclass_ex(year, month, day, cls);
31387db96d56Sopenharmony_ci}
31397db96d56Sopenharmony_ci
31407db96d56Sopenharmony_ci
31417db96d56Sopenharmony_ci/*
31427db96d56Sopenharmony_ci * Date arithmetic.
31437db96d56Sopenharmony_ci */
31447db96d56Sopenharmony_ci
31457db96d56Sopenharmony_ci/* date + timedelta -> date.  If arg negate is true, subtract the timedelta
31467db96d56Sopenharmony_ci * instead.
31477db96d56Sopenharmony_ci */
31487db96d56Sopenharmony_cistatic PyObject *
31497db96d56Sopenharmony_ciadd_date_timedelta(PyDateTime_Date *date, PyDateTime_Delta *delta, int negate)
31507db96d56Sopenharmony_ci{
31517db96d56Sopenharmony_ci    PyObject *result = NULL;
31527db96d56Sopenharmony_ci    int year = GET_YEAR(date);
31537db96d56Sopenharmony_ci    int month = GET_MONTH(date);
31547db96d56Sopenharmony_ci    int deltadays = GET_TD_DAYS(delta);
31557db96d56Sopenharmony_ci    /* C-level overflow is impossible because |deltadays| < 1e9. */
31567db96d56Sopenharmony_ci    int day = GET_DAY(date) + (negate ? -deltadays : deltadays);
31577db96d56Sopenharmony_ci
31587db96d56Sopenharmony_ci    if (normalize_date(&year, &month, &day) >= 0)
31597db96d56Sopenharmony_ci        result = new_date_subclass_ex(year, month, day,
31607db96d56Sopenharmony_ci                                      (PyObject* )Py_TYPE(date));
31617db96d56Sopenharmony_ci    return result;
31627db96d56Sopenharmony_ci}
31637db96d56Sopenharmony_ci
31647db96d56Sopenharmony_cistatic PyObject *
31657db96d56Sopenharmony_cidate_add(PyObject *left, PyObject *right)
31667db96d56Sopenharmony_ci{
31677db96d56Sopenharmony_ci    if (PyDateTime_Check(left) || PyDateTime_Check(right))
31687db96d56Sopenharmony_ci        Py_RETURN_NOTIMPLEMENTED;
31697db96d56Sopenharmony_ci
31707db96d56Sopenharmony_ci    if (PyDate_Check(left)) {
31717db96d56Sopenharmony_ci        /* date + ??? */
31727db96d56Sopenharmony_ci        if (PyDelta_Check(right))
31737db96d56Sopenharmony_ci            /* date + delta */
31747db96d56Sopenharmony_ci            return add_date_timedelta((PyDateTime_Date *) left,
31757db96d56Sopenharmony_ci                                      (PyDateTime_Delta *) right,
31767db96d56Sopenharmony_ci                                      0);
31777db96d56Sopenharmony_ci    }
31787db96d56Sopenharmony_ci    else {
31797db96d56Sopenharmony_ci        /* ??? + date
31807db96d56Sopenharmony_ci         * 'right' must be one of us, or we wouldn't have been called
31817db96d56Sopenharmony_ci         */
31827db96d56Sopenharmony_ci        if (PyDelta_Check(left))
31837db96d56Sopenharmony_ci            /* delta + date */
31847db96d56Sopenharmony_ci            return add_date_timedelta((PyDateTime_Date *) right,
31857db96d56Sopenharmony_ci                                      (PyDateTime_Delta *) left,
31867db96d56Sopenharmony_ci                                      0);
31877db96d56Sopenharmony_ci    }
31887db96d56Sopenharmony_ci    Py_RETURN_NOTIMPLEMENTED;
31897db96d56Sopenharmony_ci}
31907db96d56Sopenharmony_ci
31917db96d56Sopenharmony_cistatic PyObject *
31927db96d56Sopenharmony_cidate_subtract(PyObject *left, PyObject *right)
31937db96d56Sopenharmony_ci{
31947db96d56Sopenharmony_ci    if (PyDateTime_Check(left) || PyDateTime_Check(right))
31957db96d56Sopenharmony_ci        Py_RETURN_NOTIMPLEMENTED;
31967db96d56Sopenharmony_ci
31977db96d56Sopenharmony_ci    if (PyDate_Check(left)) {
31987db96d56Sopenharmony_ci        if (PyDate_Check(right)) {
31997db96d56Sopenharmony_ci            /* date - date */
32007db96d56Sopenharmony_ci            int left_ord = ymd_to_ord(GET_YEAR(left),
32017db96d56Sopenharmony_ci                                      GET_MONTH(left),
32027db96d56Sopenharmony_ci                                      GET_DAY(left));
32037db96d56Sopenharmony_ci            int right_ord = ymd_to_ord(GET_YEAR(right),
32047db96d56Sopenharmony_ci                                       GET_MONTH(right),
32057db96d56Sopenharmony_ci                                       GET_DAY(right));
32067db96d56Sopenharmony_ci            return new_delta(left_ord - right_ord, 0, 0, 0);
32077db96d56Sopenharmony_ci        }
32087db96d56Sopenharmony_ci        if (PyDelta_Check(right)) {
32097db96d56Sopenharmony_ci            /* date - delta */
32107db96d56Sopenharmony_ci            return add_date_timedelta((PyDateTime_Date *) left,
32117db96d56Sopenharmony_ci                                      (PyDateTime_Delta *) right,
32127db96d56Sopenharmony_ci                                      1);
32137db96d56Sopenharmony_ci        }
32147db96d56Sopenharmony_ci    }
32157db96d56Sopenharmony_ci    Py_RETURN_NOTIMPLEMENTED;
32167db96d56Sopenharmony_ci}
32177db96d56Sopenharmony_ci
32187db96d56Sopenharmony_ci
32197db96d56Sopenharmony_ci/* Various ways to turn a date into a string. */
32207db96d56Sopenharmony_ci
32217db96d56Sopenharmony_cistatic PyObject *
32227db96d56Sopenharmony_cidate_repr(PyDateTime_Date *self)
32237db96d56Sopenharmony_ci{
32247db96d56Sopenharmony_ci    return PyUnicode_FromFormat("%s(%d, %d, %d)",
32257db96d56Sopenharmony_ci                                Py_TYPE(self)->tp_name,
32267db96d56Sopenharmony_ci                                GET_YEAR(self), GET_MONTH(self), GET_DAY(self));
32277db96d56Sopenharmony_ci}
32287db96d56Sopenharmony_ci
32297db96d56Sopenharmony_cistatic PyObject *
32307db96d56Sopenharmony_cidate_isoformat(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
32317db96d56Sopenharmony_ci{
32327db96d56Sopenharmony_ci    return PyUnicode_FromFormat("%04d-%02d-%02d",
32337db96d56Sopenharmony_ci                                GET_YEAR(self), GET_MONTH(self), GET_DAY(self));
32347db96d56Sopenharmony_ci}
32357db96d56Sopenharmony_ci
32367db96d56Sopenharmony_ci/* str() calls the appropriate isoformat() method. */
32377db96d56Sopenharmony_cistatic PyObject *
32387db96d56Sopenharmony_cidate_str(PyDateTime_Date *self)
32397db96d56Sopenharmony_ci{
32407db96d56Sopenharmony_ci    return _PyObject_CallMethodIdNoArgs((PyObject *)self, &PyId_isoformat);
32417db96d56Sopenharmony_ci}
32427db96d56Sopenharmony_ci
32437db96d56Sopenharmony_ci
32447db96d56Sopenharmony_cistatic PyObject *
32457db96d56Sopenharmony_cidate_ctime(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
32467db96d56Sopenharmony_ci{
32477db96d56Sopenharmony_ci    return format_ctime(self, 0, 0, 0);
32487db96d56Sopenharmony_ci}
32497db96d56Sopenharmony_ci
32507db96d56Sopenharmony_cistatic PyObject *
32517db96d56Sopenharmony_cidate_strftime(PyDateTime_Date *self, PyObject *args, PyObject *kw)
32527db96d56Sopenharmony_ci{
32537db96d56Sopenharmony_ci    /* This method can be inherited, and needs to call the
32547db96d56Sopenharmony_ci     * timetuple() method appropriate to self's class.
32557db96d56Sopenharmony_ci     */
32567db96d56Sopenharmony_ci    PyObject *result;
32577db96d56Sopenharmony_ci    PyObject *tuple;
32587db96d56Sopenharmony_ci    PyObject *format;
32597db96d56Sopenharmony_ci    _Py_IDENTIFIER(timetuple);
32607db96d56Sopenharmony_ci    static char *keywords[] = {"format", NULL};
32617db96d56Sopenharmony_ci
32627db96d56Sopenharmony_ci    if (! PyArg_ParseTupleAndKeywords(args, kw, "U:strftime", keywords,
32637db96d56Sopenharmony_ci                                      &format))
32647db96d56Sopenharmony_ci        return NULL;
32657db96d56Sopenharmony_ci
32667db96d56Sopenharmony_ci    tuple = _PyObject_CallMethodIdNoArgs((PyObject *)self, &PyId_timetuple);
32677db96d56Sopenharmony_ci    if (tuple == NULL)
32687db96d56Sopenharmony_ci        return NULL;
32697db96d56Sopenharmony_ci    result = wrap_strftime((PyObject *)self, format, tuple,
32707db96d56Sopenharmony_ci                           (PyObject *)self);
32717db96d56Sopenharmony_ci    Py_DECREF(tuple);
32727db96d56Sopenharmony_ci    return result;
32737db96d56Sopenharmony_ci}
32747db96d56Sopenharmony_ci
32757db96d56Sopenharmony_cistatic PyObject *
32767db96d56Sopenharmony_cidate_format(PyDateTime_Date *self, PyObject *args)
32777db96d56Sopenharmony_ci{
32787db96d56Sopenharmony_ci    PyObject *format;
32797db96d56Sopenharmony_ci
32807db96d56Sopenharmony_ci    if (!PyArg_ParseTuple(args, "U:__format__", &format))
32817db96d56Sopenharmony_ci        return NULL;
32827db96d56Sopenharmony_ci
32837db96d56Sopenharmony_ci    /* if the format is zero length, return str(self) */
32847db96d56Sopenharmony_ci    if (PyUnicode_GetLength(format) == 0)
32857db96d56Sopenharmony_ci        return PyObject_Str((PyObject *)self);
32867db96d56Sopenharmony_ci
32877db96d56Sopenharmony_ci    return _PyObject_CallMethodIdOneArg((PyObject *)self, &PyId_strftime,
32887db96d56Sopenharmony_ci                                        format);
32897db96d56Sopenharmony_ci}
32907db96d56Sopenharmony_ci
32917db96d56Sopenharmony_ci/* ISO methods. */
32927db96d56Sopenharmony_ci
32937db96d56Sopenharmony_cistatic PyObject *
32947db96d56Sopenharmony_cidate_isoweekday(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
32957db96d56Sopenharmony_ci{
32967db96d56Sopenharmony_ci    int dow = weekday(GET_YEAR(self), GET_MONTH(self), GET_DAY(self));
32977db96d56Sopenharmony_ci
32987db96d56Sopenharmony_ci    return PyLong_FromLong(dow + 1);
32997db96d56Sopenharmony_ci}
33007db96d56Sopenharmony_ci
33017db96d56Sopenharmony_ciPyDoc_STRVAR(iso_calendar_date__doc__,
33027db96d56Sopenharmony_ci"The result of date.isocalendar() or datetime.isocalendar()\n\n\
33037db96d56Sopenharmony_ciThis object may be accessed either as a tuple of\n\
33047db96d56Sopenharmony_ci  ((year, week, weekday)\n\
33057db96d56Sopenharmony_cior via the object attributes as named in the above tuple.");
33067db96d56Sopenharmony_ci
33077db96d56Sopenharmony_citypedef struct {
33087db96d56Sopenharmony_ci    PyTupleObject tuple;
33097db96d56Sopenharmony_ci} PyDateTime_IsoCalendarDate;
33107db96d56Sopenharmony_ci
33117db96d56Sopenharmony_cistatic PyObject *
33127db96d56Sopenharmony_ciiso_calendar_date_repr(PyDateTime_IsoCalendarDate *self)
33137db96d56Sopenharmony_ci{
33147db96d56Sopenharmony_ci    PyObject* year = PyTuple_GetItem((PyObject *)self, 0);
33157db96d56Sopenharmony_ci    if (year == NULL) {
33167db96d56Sopenharmony_ci        return NULL;
33177db96d56Sopenharmony_ci    }
33187db96d56Sopenharmony_ci    PyObject* week = PyTuple_GetItem((PyObject *)self, 1);
33197db96d56Sopenharmony_ci    if (week == NULL) {
33207db96d56Sopenharmony_ci        return NULL;
33217db96d56Sopenharmony_ci    }
33227db96d56Sopenharmony_ci    PyObject* weekday = PyTuple_GetItem((PyObject *)self, 2);
33237db96d56Sopenharmony_ci    if (weekday == NULL) {
33247db96d56Sopenharmony_ci        return NULL;
33257db96d56Sopenharmony_ci    }
33267db96d56Sopenharmony_ci
33277db96d56Sopenharmony_ci    return PyUnicode_FromFormat("%.200s(year=%S, week=%S, weekday=%S)",
33287db96d56Sopenharmony_ci                               Py_TYPE(self)->tp_name, year, week, weekday);
33297db96d56Sopenharmony_ci}
33307db96d56Sopenharmony_ci
33317db96d56Sopenharmony_cistatic PyObject *
33327db96d56Sopenharmony_ciiso_calendar_date_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
33337db96d56Sopenharmony_ci{
33347db96d56Sopenharmony_ci    // Construct the tuple that this reduces to
33357db96d56Sopenharmony_ci    PyObject * reduce_tuple = Py_BuildValue(
33367db96d56Sopenharmony_ci        "O((OOO))", &PyTuple_Type,
33377db96d56Sopenharmony_ci        PyTuple_GET_ITEM(self, 0),
33387db96d56Sopenharmony_ci        PyTuple_GET_ITEM(self, 1),
33397db96d56Sopenharmony_ci        PyTuple_GET_ITEM(self, 2)
33407db96d56Sopenharmony_ci    );
33417db96d56Sopenharmony_ci
33427db96d56Sopenharmony_ci    return reduce_tuple;
33437db96d56Sopenharmony_ci}
33447db96d56Sopenharmony_ci
33457db96d56Sopenharmony_cistatic PyObject *
33467db96d56Sopenharmony_ciiso_calendar_date_year(PyDateTime_IsoCalendarDate *self, void *unused)
33477db96d56Sopenharmony_ci{
33487db96d56Sopenharmony_ci    PyObject *year = PyTuple_GetItem((PyObject *)self, 0);
33497db96d56Sopenharmony_ci    if (year == NULL) {
33507db96d56Sopenharmony_ci        return NULL;
33517db96d56Sopenharmony_ci    }
33527db96d56Sopenharmony_ci    Py_INCREF(year);
33537db96d56Sopenharmony_ci    return year;
33547db96d56Sopenharmony_ci}
33557db96d56Sopenharmony_ci
33567db96d56Sopenharmony_cistatic PyObject *
33577db96d56Sopenharmony_ciiso_calendar_date_week(PyDateTime_IsoCalendarDate *self, void *unused)
33587db96d56Sopenharmony_ci{
33597db96d56Sopenharmony_ci    PyObject *week = PyTuple_GetItem((PyObject *)self, 1);
33607db96d56Sopenharmony_ci    if (week == NULL) {
33617db96d56Sopenharmony_ci        return NULL;
33627db96d56Sopenharmony_ci    }
33637db96d56Sopenharmony_ci    Py_INCREF(week);
33647db96d56Sopenharmony_ci    return week;
33657db96d56Sopenharmony_ci}
33667db96d56Sopenharmony_ci
33677db96d56Sopenharmony_cistatic PyObject *
33687db96d56Sopenharmony_ciiso_calendar_date_weekday(PyDateTime_IsoCalendarDate *self, void *unused)
33697db96d56Sopenharmony_ci{
33707db96d56Sopenharmony_ci    PyObject *weekday = PyTuple_GetItem((PyObject *)self, 2);
33717db96d56Sopenharmony_ci    if (weekday == NULL) {
33727db96d56Sopenharmony_ci        return NULL;
33737db96d56Sopenharmony_ci    }
33747db96d56Sopenharmony_ci    Py_INCREF(weekday);
33757db96d56Sopenharmony_ci    return weekday;
33767db96d56Sopenharmony_ci}
33777db96d56Sopenharmony_ci
33787db96d56Sopenharmony_cistatic PyGetSetDef iso_calendar_date_getset[] = {
33797db96d56Sopenharmony_ci    {"year",        (getter)iso_calendar_date_year},
33807db96d56Sopenharmony_ci    {"week",      (getter)iso_calendar_date_week},
33817db96d56Sopenharmony_ci    {"weekday",      (getter)iso_calendar_date_weekday},
33827db96d56Sopenharmony_ci    {NULL}
33837db96d56Sopenharmony_ci};
33847db96d56Sopenharmony_ci
33857db96d56Sopenharmony_cistatic PyMethodDef iso_calendar_date_methods[] = {
33867db96d56Sopenharmony_ci    {"__reduce__", (PyCFunction)iso_calendar_date_reduce, METH_NOARGS,
33877db96d56Sopenharmony_ci     PyDoc_STR("__reduce__() -> (cls, state)")},
33887db96d56Sopenharmony_ci    {NULL, NULL},
33897db96d56Sopenharmony_ci};
33907db96d56Sopenharmony_ci
33917db96d56Sopenharmony_cistatic PyTypeObject PyDateTime_IsoCalendarDateType = {
33927db96d56Sopenharmony_ci    PyVarObject_HEAD_INIT(NULL, 0)
33937db96d56Sopenharmony_ci    .tp_name = "datetime.IsoCalendarDate",
33947db96d56Sopenharmony_ci    .tp_basicsize = sizeof(PyDateTime_IsoCalendarDate),
33957db96d56Sopenharmony_ci    .tp_repr = (reprfunc) iso_calendar_date_repr,
33967db96d56Sopenharmony_ci    .tp_flags = Py_TPFLAGS_DEFAULT,
33977db96d56Sopenharmony_ci    .tp_doc = iso_calendar_date__doc__,
33987db96d56Sopenharmony_ci    .tp_methods = iso_calendar_date_methods,
33997db96d56Sopenharmony_ci    .tp_getset = iso_calendar_date_getset,
34007db96d56Sopenharmony_ci    // .tp_base = &PyTuple_Type,  // filled in PyInit__datetime
34017db96d56Sopenharmony_ci    .tp_new = iso_calendar_date_new,
34027db96d56Sopenharmony_ci};
34037db96d56Sopenharmony_ci
34047db96d56Sopenharmony_ci/*[clinic input]
34057db96d56Sopenharmony_ci@classmethod
34067db96d56Sopenharmony_cidatetime.IsoCalendarDate.__new__ as iso_calendar_date_new
34077db96d56Sopenharmony_ci    year: int
34087db96d56Sopenharmony_ci    week: int
34097db96d56Sopenharmony_ci    weekday: int
34107db96d56Sopenharmony_ci[clinic start generated code]*/
34117db96d56Sopenharmony_ci
34127db96d56Sopenharmony_cistatic PyObject *
34137db96d56Sopenharmony_ciiso_calendar_date_new_impl(PyTypeObject *type, int year, int week,
34147db96d56Sopenharmony_ci                           int weekday)
34157db96d56Sopenharmony_ci/*[clinic end generated code: output=383d33d8dc7183a2 input=4f2c663c9d19c4ee]*/
34167db96d56Sopenharmony_ci
34177db96d56Sopenharmony_ci{
34187db96d56Sopenharmony_ci    PyDateTime_IsoCalendarDate *self;
34197db96d56Sopenharmony_ci    self = (PyDateTime_IsoCalendarDate *) type->tp_alloc(type, 3);
34207db96d56Sopenharmony_ci    if (self == NULL) {
34217db96d56Sopenharmony_ci        return NULL;
34227db96d56Sopenharmony_ci    }
34237db96d56Sopenharmony_ci
34247db96d56Sopenharmony_ci    PyTuple_SET_ITEM(self, 0, PyLong_FromLong(year));
34257db96d56Sopenharmony_ci    PyTuple_SET_ITEM(self, 1, PyLong_FromLong(week));
34267db96d56Sopenharmony_ci    PyTuple_SET_ITEM(self, 2, PyLong_FromLong(weekday));
34277db96d56Sopenharmony_ci
34287db96d56Sopenharmony_ci    return (PyObject *)self;
34297db96d56Sopenharmony_ci}
34307db96d56Sopenharmony_ci
34317db96d56Sopenharmony_cistatic PyObject *
34327db96d56Sopenharmony_cidate_isocalendar(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
34337db96d56Sopenharmony_ci{
34347db96d56Sopenharmony_ci    int  year         = GET_YEAR(self);
34357db96d56Sopenharmony_ci    int  week1_monday = iso_week1_monday(year);
34367db96d56Sopenharmony_ci    int today         = ymd_to_ord(year, GET_MONTH(self), GET_DAY(self));
34377db96d56Sopenharmony_ci    int  week;
34387db96d56Sopenharmony_ci    int  day;
34397db96d56Sopenharmony_ci
34407db96d56Sopenharmony_ci    week = divmod(today - week1_monday, 7, &day);
34417db96d56Sopenharmony_ci    if (week < 0) {
34427db96d56Sopenharmony_ci        --year;
34437db96d56Sopenharmony_ci        week1_monday = iso_week1_monday(year);
34447db96d56Sopenharmony_ci        week = divmod(today - week1_monday, 7, &day);
34457db96d56Sopenharmony_ci    }
34467db96d56Sopenharmony_ci    else if (week >= 52 && today >= iso_week1_monday(year + 1)) {
34477db96d56Sopenharmony_ci        ++year;
34487db96d56Sopenharmony_ci        week = 0;
34497db96d56Sopenharmony_ci    }
34507db96d56Sopenharmony_ci
34517db96d56Sopenharmony_ci    PyObject* v = iso_calendar_date_new_impl(&PyDateTime_IsoCalendarDateType,
34527db96d56Sopenharmony_ci                    year, week + 1, day + 1);
34537db96d56Sopenharmony_ci    if (v == NULL) {
34547db96d56Sopenharmony_ci        return NULL;
34557db96d56Sopenharmony_ci    }
34567db96d56Sopenharmony_ci    return v;
34577db96d56Sopenharmony_ci}
34587db96d56Sopenharmony_ci
34597db96d56Sopenharmony_ci/* Miscellaneous methods. */
34607db96d56Sopenharmony_ci
34617db96d56Sopenharmony_cistatic PyObject *
34627db96d56Sopenharmony_cidate_richcompare(PyObject *self, PyObject *other, int op)
34637db96d56Sopenharmony_ci{
34647db96d56Sopenharmony_ci    if (PyDate_Check(other)) {
34657db96d56Sopenharmony_ci        int diff = memcmp(((PyDateTime_Date *)self)->data,
34667db96d56Sopenharmony_ci                          ((PyDateTime_Date *)other)->data,
34677db96d56Sopenharmony_ci                          _PyDateTime_DATE_DATASIZE);
34687db96d56Sopenharmony_ci        return diff_to_bool(diff, op);
34697db96d56Sopenharmony_ci    }
34707db96d56Sopenharmony_ci    else
34717db96d56Sopenharmony_ci        Py_RETURN_NOTIMPLEMENTED;
34727db96d56Sopenharmony_ci}
34737db96d56Sopenharmony_ci
34747db96d56Sopenharmony_cistatic PyObject *
34757db96d56Sopenharmony_cidate_timetuple(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
34767db96d56Sopenharmony_ci{
34777db96d56Sopenharmony_ci    return build_struct_time(GET_YEAR(self),
34787db96d56Sopenharmony_ci                             GET_MONTH(self),
34797db96d56Sopenharmony_ci                             GET_DAY(self),
34807db96d56Sopenharmony_ci                             0, 0, 0, -1);
34817db96d56Sopenharmony_ci}
34827db96d56Sopenharmony_ci
34837db96d56Sopenharmony_cistatic PyObject *
34847db96d56Sopenharmony_cidate_replace(PyDateTime_Date *self, PyObject *args, PyObject *kw)
34857db96d56Sopenharmony_ci{
34867db96d56Sopenharmony_ci    PyObject *clone;
34877db96d56Sopenharmony_ci    PyObject *tuple;
34887db96d56Sopenharmony_ci    int year = GET_YEAR(self);
34897db96d56Sopenharmony_ci    int month = GET_MONTH(self);
34907db96d56Sopenharmony_ci    int day = GET_DAY(self);
34917db96d56Sopenharmony_ci
34927db96d56Sopenharmony_ci    if (! PyArg_ParseTupleAndKeywords(args, kw, "|iii:replace", date_kws,
34937db96d56Sopenharmony_ci                                      &year, &month, &day))
34947db96d56Sopenharmony_ci        return NULL;
34957db96d56Sopenharmony_ci    tuple = Py_BuildValue("iii", year, month, day);
34967db96d56Sopenharmony_ci    if (tuple == NULL)
34977db96d56Sopenharmony_ci        return NULL;
34987db96d56Sopenharmony_ci    clone = date_new(Py_TYPE(self), tuple, NULL);
34997db96d56Sopenharmony_ci    Py_DECREF(tuple);
35007db96d56Sopenharmony_ci    return clone;
35017db96d56Sopenharmony_ci}
35027db96d56Sopenharmony_ci
35037db96d56Sopenharmony_cistatic Py_hash_t
35047db96d56Sopenharmony_cigeneric_hash(unsigned char *data, int len)
35057db96d56Sopenharmony_ci{
35067db96d56Sopenharmony_ci    return _Py_HashBytes(data, len);
35077db96d56Sopenharmony_ci}
35087db96d56Sopenharmony_ci
35097db96d56Sopenharmony_ci
35107db96d56Sopenharmony_cistatic PyObject *date_getstate(PyDateTime_Date *self);
35117db96d56Sopenharmony_ci
35127db96d56Sopenharmony_cistatic Py_hash_t
35137db96d56Sopenharmony_cidate_hash(PyDateTime_Date *self)
35147db96d56Sopenharmony_ci{
35157db96d56Sopenharmony_ci    if (self->hashcode == -1) {
35167db96d56Sopenharmony_ci        self->hashcode = generic_hash(
35177db96d56Sopenharmony_ci            (unsigned char *)self->data, _PyDateTime_DATE_DATASIZE);
35187db96d56Sopenharmony_ci    }
35197db96d56Sopenharmony_ci
35207db96d56Sopenharmony_ci    return self->hashcode;
35217db96d56Sopenharmony_ci}
35227db96d56Sopenharmony_ci
35237db96d56Sopenharmony_cistatic PyObject *
35247db96d56Sopenharmony_cidate_toordinal(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
35257db96d56Sopenharmony_ci{
35267db96d56Sopenharmony_ci    return PyLong_FromLong(ymd_to_ord(GET_YEAR(self), GET_MONTH(self),
35277db96d56Sopenharmony_ci                                     GET_DAY(self)));
35287db96d56Sopenharmony_ci}
35297db96d56Sopenharmony_ci
35307db96d56Sopenharmony_cistatic PyObject *
35317db96d56Sopenharmony_cidate_weekday(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
35327db96d56Sopenharmony_ci{
35337db96d56Sopenharmony_ci    int dow = weekday(GET_YEAR(self), GET_MONTH(self), GET_DAY(self));
35347db96d56Sopenharmony_ci
35357db96d56Sopenharmony_ci    return PyLong_FromLong(dow);
35367db96d56Sopenharmony_ci}
35377db96d56Sopenharmony_ci
35387db96d56Sopenharmony_ci/* Pickle support, a simple use of __reduce__. */
35397db96d56Sopenharmony_ci
35407db96d56Sopenharmony_ci/* __getstate__ isn't exposed */
35417db96d56Sopenharmony_cistatic PyObject *
35427db96d56Sopenharmony_cidate_getstate(PyDateTime_Date *self)
35437db96d56Sopenharmony_ci{
35447db96d56Sopenharmony_ci    PyObject* field;
35457db96d56Sopenharmony_ci    field = PyBytes_FromStringAndSize((char*)self->data,
35467db96d56Sopenharmony_ci                                       _PyDateTime_DATE_DATASIZE);
35477db96d56Sopenharmony_ci    return Py_BuildValue("(N)", field);
35487db96d56Sopenharmony_ci}
35497db96d56Sopenharmony_ci
35507db96d56Sopenharmony_cistatic PyObject *
35517db96d56Sopenharmony_cidate_reduce(PyDateTime_Date *self, PyObject *arg)
35527db96d56Sopenharmony_ci{
35537db96d56Sopenharmony_ci    return Py_BuildValue("(ON)", Py_TYPE(self), date_getstate(self));
35547db96d56Sopenharmony_ci}
35557db96d56Sopenharmony_ci
35567db96d56Sopenharmony_cistatic PyMethodDef date_methods[] = {
35577db96d56Sopenharmony_ci
35587db96d56Sopenharmony_ci    /* Class methods: */
35597db96d56Sopenharmony_ci    DATETIME_DATE_FROMTIMESTAMP_METHODDEF
35607db96d56Sopenharmony_ci
35617db96d56Sopenharmony_ci    {"fromordinal", (PyCFunction)date_fromordinal,      METH_VARARGS |
35627db96d56Sopenharmony_ci                                                    METH_CLASS,
35637db96d56Sopenharmony_ci     PyDoc_STR("int -> date corresponding to a proleptic Gregorian "
35647db96d56Sopenharmony_ci               "ordinal.")},
35657db96d56Sopenharmony_ci
35667db96d56Sopenharmony_ci     {"fromisoformat", (PyCFunction)date_fromisoformat,  METH_O |
35677db96d56Sopenharmony_ci                                                         METH_CLASS,
35687db96d56Sopenharmony_ci      PyDoc_STR("str -> Construct a date from a string in ISO 8601 format.")},
35697db96d56Sopenharmony_ci
35707db96d56Sopenharmony_ci     {"fromisocalendar", _PyCFunction_CAST(date_fromisocalendar),
35717db96d56Sopenharmony_ci      METH_VARARGS | METH_KEYWORDS | METH_CLASS,
35727db96d56Sopenharmony_ci      PyDoc_STR("int, int, int -> Construct a date from the ISO year, week "
35737db96d56Sopenharmony_ci                "number and weekday.\n\n"
35747db96d56Sopenharmony_ci                "This is the inverse of the date.isocalendar() function")},
35757db96d56Sopenharmony_ci
35767db96d56Sopenharmony_ci    {"today",         (PyCFunction)date_today,   METH_NOARGS | METH_CLASS,
35777db96d56Sopenharmony_ci     PyDoc_STR("Current date or datetime:  same as "
35787db96d56Sopenharmony_ci               "self.__class__.fromtimestamp(time.time()).")},
35797db96d56Sopenharmony_ci
35807db96d56Sopenharmony_ci    /* Instance methods: */
35817db96d56Sopenharmony_ci
35827db96d56Sopenharmony_ci    {"ctime",       (PyCFunction)date_ctime,        METH_NOARGS,
35837db96d56Sopenharmony_ci     PyDoc_STR("Return ctime() style string.")},
35847db96d56Sopenharmony_ci
35857db96d56Sopenharmony_ci    {"strftime",        _PyCFunction_CAST(date_strftime),     METH_VARARGS | METH_KEYWORDS,
35867db96d56Sopenharmony_ci     PyDoc_STR("format -> strftime() style string.")},
35877db96d56Sopenharmony_ci
35887db96d56Sopenharmony_ci    {"__format__",      (PyCFunction)date_format,       METH_VARARGS,
35897db96d56Sopenharmony_ci     PyDoc_STR("Formats self with strftime.")},
35907db96d56Sopenharmony_ci
35917db96d56Sopenharmony_ci    {"timetuple",   (PyCFunction)date_timetuple,    METH_NOARGS,
35927db96d56Sopenharmony_ci     PyDoc_STR("Return time tuple, compatible with time.localtime().")},
35937db96d56Sopenharmony_ci
35947db96d56Sopenharmony_ci    {"isocalendar", (PyCFunction)date_isocalendar,  METH_NOARGS,
35957db96d56Sopenharmony_ci     PyDoc_STR("Return a named tuple containing ISO year, week number, and "
35967db96d56Sopenharmony_ci               "weekday.")},
35977db96d56Sopenharmony_ci
35987db96d56Sopenharmony_ci    {"isoformat",   (PyCFunction)date_isoformat,        METH_NOARGS,
35997db96d56Sopenharmony_ci     PyDoc_STR("Return string in ISO 8601 format, YYYY-MM-DD.")},
36007db96d56Sopenharmony_ci
36017db96d56Sopenharmony_ci    {"isoweekday",  (PyCFunction)date_isoweekday,   METH_NOARGS,
36027db96d56Sopenharmony_ci     PyDoc_STR("Return the day of the week represented by the date.\n"
36037db96d56Sopenharmony_ci               "Monday == 1 ... Sunday == 7")},
36047db96d56Sopenharmony_ci
36057db96d56Sopenharmony_ci    {"toordinal",   (PyCFunction)date_toordinal,    METH_NOARGS,
36067db96d56Sopenharmony_ci     PyDoc_STR("Return proleptic Gregorian ordinal.  January 1 of year "
36077db96d56Sopenharmony_ci               "1 is day 1.")},
36087db96d56Sopenharmony_ci
36097db96d56Sopenharmony_ci    {"weekday",     (PyCFunction)date_weekday,      METH_NOARGS,
36107db96d56Sopenharmony_ci     PyDoc_STR("Return the day of the week represented by the date.\n"
36117db96d56Sopenharmony_ci               "Monday == 0 ... Sunday == 6")},
36127db96d56Sopenharmony_ci
36137db96d56Sopenharmony_ci    {"replace",     _PyCFunction_CAST(date_replace),      METH_VARARGS | METH_KEYWORDS,
36147db96d56Sopenharmony_ci     PyDoc_STR("Return date with new specified fields.")},
36157db96d56Sopenharmony_ci
36167db96d56Sopenharmony_ci    {"__reduce__", (PyCFunction)date_reduce,        METH_NOARGS,
36177db96d56Sopenharmony_ci     PyDoc_STR("__reduce__() -> (cls, state)")},
36187db96d56Sopenharmony_ci
36197db96d56Sopenharmony_ci    {NULL,      NULL}
36207db96d56Sopenharmony_ci};
36217db96d56Sopenharmony_ci
36227db96d56Sopenharmony_cistatic const char date_doc[] =
36237db96d56Sopenharmony_ciPyDoc_STR("date(year, month, day) --> date object");
36247db96d56Sopenharmony_ci
36257db96d56Sopenharmony_cistatic PyNumberMethods date_as_number = {
36267db96d56Sopenharmony_ci    date_add,                                           /* nb_add */
36277db96d56Sopenharmony_ci    date_subtract,                                      /* nb_subtract */
36287db96d56Sopenharmony_ci    0,                                                  /* nb_multiply */
36297db96d56Sopenharmony_ci    0,                                                  /* nb_remainder */
36307db96d56Sopenharmony_ci    0,                                                  /* nb_divmod */
36317db96d56Sopenharmony_ci    0,                                                  /* nb_power */
36327db96d56Sopenharmony_ci    0,                                                  /* nb_negative */
36337db96d56Sopenharmony_ci    0,                                                  /* nb_positive */
36347db96d56Sopenharmony_ci    0,                                                  /* nb_absolute */
36357db96d56Sopenharmony_ci    0,                                                  /* nb_bool */
36367db96d56Sopenharmony_ci};
36377db96d56Sopenharmony_ci
36387db96d56Sopenharmony_cistatic PyTypeObject PyDateTime_DateType = {
36397db96d56Sopenharmony_ci    PyVarObject_HEAD_INIT(NULL, 0)
36407db96d56Sopenharmony_ci    "datetime.date",                                    /* tp_name */
36417db96d56Sopenharmony_ci    sizeof(PyDateTime_Date),                            /* tp_basicsize */
36427db96d56Sopenharmony_ci    0,                                                  /* tp_itemsize */
36437db96d56Sopenharmony_ci    0,                                                  /* tp_dealloc */
36447db96d56Sopenharmony_ci    0,                                                  /* tp_vectorcall_offset */
36457db96d56Sopenharmony_ci    0,                                                  /* tp_getattr */
36467db96d56Sopenharmony_ci    0,                                                  /* tp_setattr */
36477db96d56Sopenharmony_ci    0,                                                  /* tp_as_async */
36487db96d56Sopenharmony_ci    (reprfunc)date_repr,                                /* tp_repr */
36497db96d56Sopenharmony_ci    &date_as_number,                                    /* tp_as_number */
36507db96d56Sopenharmony_ci    0,                                                  /* tp_as_sequence */
36517db96d56Sopenharmony_ci    0,                                                  /* tp_as_mapping */
36527db96d56Sopenharmony_ci    (hashfunc)date_hash,                                /* tp_hash */
36537db96d56Sopenharmony_ci    0,                                                  /* tp_call */
36547db96d56Sopenharmony_ci    (reprfunc)date_str,                                 /* tp_str */
36557db96d56Sopenharmony_ci    PyObject_GenericGetAttr,                            /* tp_getattro */
36567db96d56Sopenharmony_ci    0,                                                  /* tp_setattro */
36577db96d56Sopenharmony_ci    0,                                                  /* tp_as_buffer */
36587db96d56Sopenharmony_ci    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,           /* tp_flags */
36597db96d56Sopenharmony_ci    date_doc,                                           /* tp_doc */
36607db96d56Sopenharmony_ci    0,                                                  /* tp_traverse */
36617db96d56Sopenharmony_ci    0,                                                  /* tp_clear */
36627db96d56Sopenharmony_ci    date_richcompare,                                   /* tp_richcompare */
36637db96d56Sopenharmony_ci    0,                                                  /* tp_weaklistoffset */
36647db96d56Sopenharmony_ci    0,                                                  /* tp_iter */
36657db96d56Sopenharmony_ci    0,                                                  /* tp_iternext */
36667db96d56Sopenharmony_ci    date_methods,                                       /* tp_methods */
36677db96d56Sopenharmony_ci    0,                                                  /* tp_members */
36687db96d56Sopenharmony_ci    date_getset,                                        /* tp_getset */
36697db96d56Sopenharmony_ci    0,                                                  /* tp_base */
36707db96d56Sopenharmony_ci    0,                                                  /* tp_dict */
36717db96d56Sopenharmony_ci    0,                                                  /* tp_descr_get */
36727db96d56Sopenharmony_ci    0,                                                  /* tp_descr_set */
36737db96d56Sopenharmony_ci    0,                                                  /* tp_dictoffset */
36747db96d56Sopenharmony_ci    0,                                                  /* tp_init */
36757db96d56Sopenharmony_ci    0,                                                  /* tp_alloc */
36767db96d56Sopenharmony_ci    date_new,                                           /* tp_new */
36777db96d56Sopenharmony_ci    0,                                                  /* tp_free */
36787db96d56Sopenharmony_ci};
36797db96d56Sopenharmony_ci
36807db96d56Sopenharmony_ci/*
36817db96d56Sopenharmony_ci * PyDateTime_TZInfo implementation.
36827db96d56Sopenharmony_ci */
36837db96d56Sopenharmony_ci
36847db96d56Sopenharmony_ci/* This is a pure abstract base class, so doesn't do anything beyond
36857db96d56Sopenharmony_ci * raising NotImplemented exceptions.  Real tzinfo classes need
36867db96d56Sopenharmony_ci * to derive from this.  This is mostly for clarity, and for efficiency in
36877db96d56Sopenharmony_ci * datetime and time constructors (their tzinfo arguments need to
36887db96d56Sopenharmony_ci * be subclasses of this tzinfo class, which is easy and quick to check).
36897db96d56Sopenharmony_ci *
36907db96d56Sopenharmony_ci * Note:  For reasons having to do with pickling of subclasses, we have
36917db96d56Sopenharmony_ci * to allow tzinfo objects to be instantiated.  This wasn't an issue
36927db96d56Sopenharmony_ci * in the Python implementation (__init__() could raise NotImplementedError
36937db96d56Sopenharmony_ci * there without ill effect), but doing so in the C implementation hit a
36947db96d56Sopenharmony_ci * brick wall.
36957db96d56Sopenharmony_ci */
36967db96d56Sopenharmony_ci
36977db96d56Sopenharmony_cistatic PyObject *
36987db96d56Sopenharmony_citzinfo_nogo(const char* methodname)
36997db96d56Sopenharmony_ci{
37007db96d56Sopenharmony_ci    PyErr_Format(PyExc_NotImplementedError,
37017db96d56Sopenharmony_ci                 "a tzinfo subclass must implement %s()",
37027db96d56Sopenharmony_ci                 methodname);
37037db96d56Sopenharmony_ci    return NULL;
37047db96d56Sopenharmony_ci}
37057db96d56Sopenharmony_ci
37067db96d56Sopenharmony_ci/* Methods.  A subclass must implement these. */
37077db96d56Sopenharmony_ci
37087db96d56Sopenharmony_cistatic PyObject *
37097db96d56Sopenharmony_citzinfo_tzname(PyDateTime_TZInfo *self, PyObject *dt)
37107db96d56Sopenharmony_ci{
37117db96d56Sopenharmony_ci    return tzinfo_nogo("tzname");
37127db96d56Sopenharmony_ci}
37137db96d56Sopenharmony_ci
37147db96d56Sopenharmony_cistatic PyObject *
37157db96d56Sopenharmony_citzinfo_utcoffset(PyDateTime_TZInfo *self, PyObject *dt)
37167db96d56Sopenharmony_ci{
37177db96d56Sopenharmony_ci    return tzinfo_nogo("utcoffset");
37187db96d56Sopenharmony_ci}
37197db96d56Sopenharmony_ci
37207db96d56Sopenharmony_cistatic PyObject *
37217db96d56Sopenharmony_citzinfo_dst(PyDateTime_TZInfo *self, PyObject *dt)
37227db96d56Sopenharmony_ci{
37237db96d56Sopenharmony_ci    return tzinfo_nogo("dst");
37247db96d56Sopenharmony_ci}
37257db96d56Sopenharmony_ci
37267db96d56Sopenharmony_ci
37277db96d56Sopenharmony_cistatic PyObject *add_datetime_timedelta(PyDateTime_DateTime *date,
37287db96d56Sopenharmony_ci                                        PyDateTime_Delta *delta,
37297db96d56Sopenharmony_ci                                        int factor);
37307db96d56Sopenharmony_cistatic PyObject *datetime_utcoffset(PyObject *self, PyObject *);
37317db96d56Sopenharmony_cistatic PyObject *datetime_dst(PyObject *self, PyObject *);
37327db96d56Sopenharmony_ci
37337db96d56Sopenharmony_cistatic PyObject *
37347db96d56Sopenharmony_citzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt)
37357db96d56Sopenharmony_ci{
37367db96d56Sopenharmony_ci    PyObject *result = NULL;
37377db96d56Sopenharmony_ci    PyObject *off = NULL, *dst = NULL;
37387db96d56Sopenharmony_ci    PyDateTime_Delta *delta = NULL;
37397db96d56Sopenharmony_ci
37407db96d56Sopenharmony_ci    if (!PyDateTime_Check(dt)) {
37417db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
37427db96d56Sopenharmony_ci                        "fromutc: argument must be a datetime");
37437db96d56Sopenharmony_ci        return NULL;
37447db96d56Sopenharmony_ci    }
37457db96d56Sopenharmony_ci    if (GET_DT_TZINFO(dt) != (PyObject *)self) {
37467db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError, "fromutc: dt.tzinfo "
37477db96d56Sopenharmony_ci                        "is not self");
37487db96d56Sopenharmony_ci        return NULL;
37497db96d56Sopenharmony_ci    }
37507db96d56Sopenharmony_ci
37517db96d56Sopenharmony_ci    off = datetime_utcoffset(dt, NULL);
37527db96d56Sopenharmony_ci    if (off == NULL)
37537db96d56Sopenharmony_ci        return NULL;
37547db96d56Sopenharmony_ci    if (off == Py_None) {
37557db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError, "fromutc: non-None "
37567db96d56Sopenharmony_ci                        "utcoffset() result required");
37577db96d56Sopenharmony_ci        goto Fail;
37587db96d56Sopenharmony_ci    }
37597db96d56Sopenharmony_ci
37607db96d56Sopenharmony_ci    dst = datetime_dst(dt, NULL);
37617db96d56Sopenharmony_ci    if (dst == NULL)
37627db96d56Sopenharmony_ci        goto Fail;
37637db96d56Sopenharmony_ci    if (dst == Py_None) {
37647db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError, "fromutc: non-None "
37657db96d56Sopenharmony_ci                        "dst() result required");
37667db96d56Sopenharmony_ci        goto Fail;
37677db96d56Sopenharmony_ci    }
37687db96d56Sopenharmony_ci
37697db96d56Sopenharmony_ci    delta = (PyDateTime_Delta *)delta_subtract(off, dst);
37707db96d56Sopenharmony_ci    if (delta == NULL)
37717db96d56Sopenharmony_ci        goto Fail;
37727db96d56Sopenharmony_ci    result = add_datetime_timedelta((PyDateTime_DateTime *)dt, delta, 1);
37737db96d56Sopenharmony_ci    if (result == NULL)
37747db96d56Sopenharmony_ci        goto Fail;
37757db96d56Sopenharmony_ci
37767db96d56Sopenharmony_ci    Py_DECREF(dst);
37777db96d56Sopenharmony_ci    dst = call_dst(GET_DT_TZINFO(dt), result);
37787db96d56Sopenharmony_ci    if (dst == NULL)
37797db96d56Sopenharmony_ci        goto Fail;
37807db96d56Sopenharmony_ci    if (dst == Py_None)
37817db96d56Sopenharmony_ci        goto Inconsistent;
37827db96d56Sopenharmony_ci    if (delta_bool((PyDateTime_Delta *)dst) != 0) {
37837db96d56Sopenharmony_ci        Py_SETREF(result, add_datetime_timedelta((PyDateTime_DateTime *)result,
37847db96d56Sopenharmony_ci                                                 (PyDateTime_Delta *)dst, 1));
37857db96d56Sopenharmony_ci        if (result == NULL)
37867db96d56Sopenharmony_ci            goto Fail;
37877db96d56Sopenharmony_ci    }
37887db96d56Sopenharmony_ci    Py_DECREF(delta);
37897db96d56Sopenharmony_ci    Py_DECREF(dst);
37907db96d56Sopenharmony_ci    Py_DECREF(off);
37917db96d56Sopenharmony_ci    return result;
37927db96d56Sopenharmony_ci
37937db96d56Sopenharmony_ciInconsistent:
37947db96d56Sopenharmony_ci    PyErr_SetString(PyExc_ValueError, "fromutc: tz.dst() gave "
37957db96d56Sopenharmony_ci                    "inconsistent results; cannot convert");
37967db96d56Sopenharmony_ci
37977db96d56Sopenharmony_ci    /* fall through to failure */
37987db96d56Sopenharmony_ciFail:
37997db96d56Sopenharmony_ci    Py_XDECREF(off);
38007db96d56Sopenharmony_ci    Py_XDECREF(dst);
38017db96d56Sopenharmony_ci    Py_XDECREF(delta);
38027db96d56Sopenharmony_ci    Py_XDECREF(result);
38037db96d56Sopenharmony_ci    return NULL;
38047db96d56Sopenharmony_ci}
38057db96d56Sopenharmony_ci
38067db96d56Sopenharmony_ci/*
38077db96d56Sopenharmony_ci * Pickle support.  This is solely so that tzinfo subclasses can use
38087db96d56Sopenharmony_ci * pickling -- tzinfo itself is supposed to be uninstantiable.
38097db96d56Sopenharmony_ci */
38107db96d56Sopenharmony_ci
38117db96d56Sopenharmony_cistatic PyObject *
38127db96d56Sopenharmony_citzinfo_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
38137db96d56Sopenharmony_ci{
38147db96d56Sopenharmony_ci    PyObject *args, *state;
38157db96d56Sopenharmony_ci    PyObject *getinitargs;
38167db96d56Sopenharmony_ci    _Py_IDENTIFIER(__getinitargs__);
38177db96d56Sopenharmony_ci
38187db96d56Sopenharmony_ci    if (_PyObject_LookupAttrId(self, &PyId___getinitargs__, &getinitargs) < 0) {
38197db96d56Sopenharmony_ci        return NULL;
38207db96d56Sopenharmony_ci    }
38217db96d56Sopenharmony_ci    if (getinitargs != NULL) {
38227db96d56Sopenharmony_ci        args = PyObject_CallNoArgs(getinitargs);
38237db96d56Sopenharmony_ci        Py_DECREF(getinitargs);
38247db96d56Sopenharmony_ci    }
38257db96d56Sopenharmony_ci    else {
38267db96d56Sopenharmony_ci        args = PyTuple_New(0);
38277db96d56Sopenharmony_ci    }
38287db96d56Sopenharmony_ci    if (args == NULL) {
38297db96d56Sopenharmony_ci        return NULL;
38307db96d56Sopenharmony_ci    }
38317db96d56Sopenharmony_ci
38327db96d56Sopenharmony_ci    state = _PyObject_GetState(self);
38337db96d56Sopenharmony_ci    if (state == NULL) {
38347db96d56Sopenharmony_ci        Py_DECREF(args);
38357db96d56Sopenharmony_ci        return NULL;
38367db96d56Sopenharmony_ci    }
38377db96d56Sopenharmony_ci
38387db96d56Sopenharmony_ci    return Py_BuildValue("(ONN)", Py_TYPE(self), args, state);
38397db96d56Sopenharmony_ci}
38407db96d56Sopenharmony_ci
38417db96d56Sopenharmony_cistatic PyMethodDef tzinfo_methods[] = {
38427db96d56Sopenharmony_ci
38437db96d56Sopenharmony_ci    {"tzname",          (PyCFunction)tzinfo_tzname,             METH_O,
38447db96d56Sopenharmony_ci     PyDoc_STR("datetime -> string name of time zone.")},
38457db96d56Sopenharmony_ci
38467db96d56Sopenharmony_ci    {"utcoffset",       (PyCFunction)tzinfo_utcoffset,          METH_O,
38477db96d56Sopenharmony_ci     PyDoc_STR("datetime -> timedelta showing offset from UTC, negative "
38487db96d56Sopenharmony_ci           "values indicating West of UTC")},
38497db96d56Sopenharmony_ci
38507db96d56Sopenharmony_ci    {"dst",             (PyCFunction)tzinfo_dst,                METH_O,
38517db96d56Sopenharmony_ci     PyDoc_STR("datetime -> DST offset as timedelta positive east of UTC.")},
38527db96d56Sopenharmony_ci
38537db96d56Sopenharmony_ci    {"fromutc",         (PyCFunction)tzinfo_fromutc,            METH_O,
38547db96d56Sopenharmony_ci     PyDoc_STR("datetime in UTC -> datetime in local time.")},
38557db96d56Sopenharmony_ci
38567db96d56Sopenharmony_ci    {"__reduce__",  tzinfo_reduce,             METH_NOARGS,
38577db96d56Sopenharmony_ci     PyDoc_STR("-> (cls, state)")},
38587db96d56Sopenharmony_ci
38597db96d56Sopenharmony_ci    {NULL, NULL}
38607db96d56Sopenharmony_ci};
38617db96d56Sopenharmony_ci
38627db96d56Sopenharmony_cistatic const char tzinfo_doc[] =
38637db96d56Sopenharmony_ciPyDoc_STR("Abstract base class for time zone info objects.");
38647db96d56Sopenharmony_ci
38657db96d56Sopenharmony_cistatic PyTypeObject PyDateTime_TZInfoType = {
38667db96d56Sopenharmony_ci    PyVarObject_HEAD_INIT(NULL, 0)
38677db96d56Sopenharmony_ci    "datetime.tzinfo",                          /* tp_name */
38687db96d56Sopenharmony_ci    sizeof(PyDateTime_TZInfo),                  /* tp_basicsize */
38697db96d56Sopenharmony_ci    0,                                          /* tp_itemsize */
38707db96d56Sopenharmony_ci    0,                                          /* tp_dealloc */
38717db96d56Sopenharmony_ci    0,                                          /* tp_vectorcall_offset */
38727db96d56Sopenharmony_ci    0,                                          /* tp_getattr */
38737db96d56Sopenharmony_ci    0,                                          /* tp_setattr */
38747db96d56Sopenharmony_ci    0,                                          /* tp_as_async */
38757db96d56Sopenharmony_ci    0,                                          /* tp_repr */
38767db96d56Sopenharmony_ci    0,                                          /* tp_as_number */
38777db96d56Sopenharmony_ci    0,                                          /* tp_as_sequence */
38787db96d56Sopenharmony_ci    0,                                          /* tp_as_mapping */
38797db96d56Sopenharmony_ci    0,                                          /* tp_hash */
38807db96d56Sopenharmony_ci    0,                                          /* tp_call */
38817db96d56Sopenharmony_ci    0,                                          /* tp_str */
38827db96d56Sopenharmony_ci    PyObject_GenericGetAttr,                    /* tp_getattro */
38837db96d56Sopenharmony_ci    0,                                          /* tp_setattro */
38847db96d56Sopenharmony_ci    0,                                          /* tp_as_buffer */
38857db96d56Sopenharmony_ci    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags */
38867db96d56Sopenharmony_ci    tzinfo_doc,                                 /* tp_doc */
38877db96d56Sopenharmony_ci    0,                                          /* tp_traverse */
38887db96d56Sopenharmony_ci    0,                                          /* tp_clear */
38897db96d56Sopenharmony_ci    0,                                          /* tp_richcompare */
38907db96d56Sopenharmony_ci    0,                                          /* tp_weaklistoffset */
38917db96d56Sopenharmony_ci    0,                                          /* tp_iter */
38927db96d56Sopenharmony_ci    0,                                          /* tp_iternext */
38937db96d56Sopenharmony_ci    tzinfo_methods,                             /* tp_methods */
38947db96d56Sopenharmony_ci    0,                                          /* tp_members */
38957db96d56Sopenharmony_ci    0,                                          /* tp_getset */
38967db96d56Sopenharmony_ci    0,                                          /* tp_base */
38977db96d56Sopenharmony_ci    0,                                          /* tp_dict */
38987db96d56Sopenharmony_ci    0,                                          /* tp_descr_get */
38997db96d56Sopenharmony_ci    0,                                          /* tp_descr_set */
39007db96d56Sopenharmony_ci    0,                                          /* tp_dictoffset */
39017db96d56Sopenharmony_ci    0,                                          /* tp_init */
39027db96d56Sopenharmony_ci    0,                                          /* tp_alloc */
39037db96d56Sopenharmony_ci    PyType_GenericNew,                          /* tp_new */
39047db96d56Sopenharmony_ci    0,                                          /* tp_free */
39057db96d56Sopenharmony_ci};
39067db96d56Sopenharmony_ci
39077db96d56Sopenharmony_cistatic char *timezone_kws[] = {"offset", "name", NULL};
39087db96d56Sopenharmony_ci
39097db96d56Sopenharmony_cistatic PyObject *
39107db96d56Sopenharmony_citimezone_new(PyTypeObject *type, PyObject *args, PyObject *kw)
39117db96d56Sopenharmony_ci{
39127db96d56Sopenharmony_ci    PyObject *offset;
39137db96d56Sopenharmony_ci    PyObject *name = NULL;
39147db96d56Sopenharmony_ci    if (PyArg_ParseTupleAndKeywords(args, kw, "O!|U:timezone", timezone_kws,
39157db96d56Sopenharmony_ci                                    &PyDateTime_DeltaType, &offset, &name))
39167db96d56Sopenharmony_ci        return new_timezone(offset, name);
39177db96d56Sopenharmony_ci
39187db96d56Sopenharmony_ci    return NULL;
39197db96d56Sopenharmony_ci}
39207db96d56Sopenharmony_ci
39217db96d56Sopenharmony_cistatic void
39227db96d56Sopenharmony_citimezone_dealloc(PyDateTime_TimeZone *self)
39237db96d56Sopenharmony_ci{
39247db96d56Sopenharmony_ci    Py_CLEAR(self->offset);
39257db96d56Sopenharmony_ci    Py_CLEAR(self->name);
39267db96d56Sopenharmony_ci    Py_TYPE(self)->tp_free((PyObject *)self);
39277db96d56Sopenharmony_ci}
39287db96d56Sopenharmony_ci
39297db96d56Sopenharmony_cistatic PyObject *
39307db96d56Sopenharmony_citimezone_richcompare(PyDateTime_TimeZone *self,
39317db96d56Sopenharmony_ci                     PyDateTime_TimeZone *other, int op)
39327db96d56Sopenharmony_ci{
39337db96d56Sopenharmony_ci    if (op != Py_EQ && op != Py_NE)
39347db96d56Sopenharmony_ci        Py_RETURN_NOTIMPLEMENTED;
39357db96d56Sopenharmony_ci    if (!PyTimezone_Check(other)) {
39367db96d56Sopenharmony_ci        Py_RETURN_NOTIMPLEMENTED;
39377db96d56Sopenharmony_ci    }
39387db96d56Sopenharmony_ci    return delta_richcompare(self->offset, other->offset, op);
39397db96d56Sopenharmony_ci}
39407db96d56Sopenharmony_ci
39417db96d56Sopenharmony_cistatic Py_hash_t
39427db96d56Sopenharmony_citimezone_hash(PyDateTime_TimeZone *self)
39437db96d56Sopenharmony_ci{
39447db96d56Sopenharmony_ci    return delta_hash((PyDateTime_Delta *)self->offset);
39457db96d56Sopenharmony_ci}
39467db96d56Sopenharmony_ci
39477db96d56Sopenharmony_ci/* Check argument type passed to tzname, utcoffset, or dst methods.
39487db96d56Sopenharmony_ci   Returns 0 for good argument.  Returns -1 and sets exception info
39497db96d56Sopenharmony_ci   otherwise.
39507db96d56Sopenharmony_ci */
39517db96d56Sopenharmony_cistatic int
39527db96d56Sopenharmony_ci_timezone_check_argument(PyObject *dt, const char *meth)
39537db96d56Sopenharmony_ci{
39547db96d56Sopenharmony_ci    if (dt == Py_None || PyDateTime_Check(dt))
39557db96d56Sopenharmony_ci        return 0;
39567db96d56Sopenharmony_ci    PyErr_Format(PyExc_TypeError, "%s(dt) argument must be a datetime instance"
39577db96d56Sopenharmony_ci                 " or None, not %.200s", meth, Py_TYPE(dt)->tp_name);
39587db96d56Sopenharmony_ci    return -1;
39597db96d56Sopenharmony_ci}
39607db96d56Sopenharmony_ci
39617db96d56Sopenharmony_cistatic PyObject *
39627db96d56Sopenharmony_citimezone_repr(PyDateTime_TimeZone *self)
39637db96d56Sopenharmony_ci{
39647db96d56Sopenharmony_ci    /* Note that although timezone is not subclassable, it is convenient
39657db96d56Sopenharmony_ci       to use Py_TYPE(self)->tp_name here. */
39667db96d56Sopenharmony_ci    const char *type_name = Py_TYPE(self)->tp_name;
39677db96d56Sopenharmony_ci
39687db96d56Sopenharmony_ci    if (((PyObject *)self) == PyDateTime_TimeZone_UTC)
39697db96d56Sopenharmony_ci        return PyUnicode_FromFormat("%s.utc", type_name);
39707db96d56Sopenharmony_ci
39717db96d56Sopenharmony_ci    if (self->name == NULL)
39727db96d56Sopenharmony_ci        return PyUnicode_FromFormat("%s(%R)", type_name, self->offset);
39737db96d56Sopenharmony_ci
39747db96d56Sopenharmony_ci    return PyUnicode_FromFormat("%s(%R, %R)", type_name, self->offset,
39757db96d56Sopenharmony_ci                                self->name);
39767db96d56Sopenharmony_ci}
39777db96d56Sopenharmony_ci
39787db96d56Sopenharmony_ci
39797db96d56Sopenharmony_cistatic PyObject *
39807db96d56Sopenharmony_citimezone_str(PyDateTime_TimeZone *self)
39817db96d56Sopenharmony_ci{
39827db96d56Sopenharmony_ci    int hours, minutes, seconds, microseconds;
39837db96d56Sopenharmony_ci    PyObject *offset;
39847db96d56Sopenharmony_ci    char sign;
39857db96d56Sopenharmony_ci
39867db96d56Sopenharmony_ci    if (self->name != NULL) {
39877db96d56Sopenharmony_ci        Py_INCREF(self->name);
39887db96d56Sopenharmony_ci        return self->name;
39897db96d56Sopenharmony_ci    }
39907db96d56Sopenharmony_ci    if ((PyObject *)self == PyDateTime_TimeZone_UTC ||
39917db96d56Sopenharmony_ci           (GET_TD_DAYS(self->offset) == 0 &&
39927db96d56Sopenharmony_ci            GET_TD_SECONDS(self->offset) == 0 &&
39937db96d56Sopenharmony_ci            GET_TD_MICROSECONDS(self->offset) == 0))
39947db96d56Sopenharmony_ci        return PyUnicode_FromString("UTC");
39957db96d56Sopenharmony_ci    /* Offset is normalized, so it is negative if days < 0 */
39967db96d56Sopenharmony_ci    if (GET_TD_DAYS(self->offset) < 0) {
39977db96d56Sopenharmony_ci        sign = '-';
39987db96d56Sopenharmony_ci        offset = delta_negative((PyDateTime_Delta *)self->offset);
39997db96d56Sopenharmony_ci        if (offset == NULL)
40007db96d56Sopenharmony_ci            return NULL;
40017db96d56Sopenharmony_ci    }
40027db96d56Sopenharmony_ci    else {
40037db96d56Sopenharmony_ci        sign = '+';
40047db96d56Sopenharmony_ci        offset = self->offset;
40057db96d56Sopenharmony_ci        Py_INCREF(offset);
40067db96d56Sopenharmony_ci    }
40077db96d56Sopenharmony_ci    /* Offset is not negative here. */
40087db96d56Sopenharmony_ci    microseconds = GET_TD_MICROSECONDS(offset);
40097db96d56Sopenharmony_ci    seconds = GET_TD_SECONDS(offset);
40107db96d56Sopenharmony_ci    Py_DECREF(offset);
40117db96d56Sopenharmony_ci    minutes = divmod(seconds, 60, &seconds);
40127db96d56Sopenharmony_ci    hours = divmod(minutes, 60, &minutes);
40137db96d56Sopenharmony_ci    if (microseconds != 0) {
40147db96d56Sopenharmony_ci        return PyUnicode_FromFormat("UTC%c%02d:%02d:%02d.%06d",
40157db96d56Sopenharmony_ci                                    sign, hours, minutes,
40167db96d56Sopenharmony_ci                                    seconds, microseconds);
40177db96d56Sopenharmony_ci    }
40187db96d56Sopenharmony_ci    if (seconds != 0) {
40197db96d56Sopenharmony_ci        return PyUnicode_FromFormat("UTC%c%02d:%02d:%02d",
40207db96d56Sopenharmony_ci                                    sign, hours, minutes, seconds);
40217db96d56Sopenharmony_ci    }
40227db96d56Sopenharmony_ci    return PyUnicode_FromFormat("UTC%c%02d:%02d", sign, hours, minutes);
40237db96d56Sopenharmony_ci}
40247db96d56Sopenharmony_ci
40257db96d56Sopenharmony_cistatic PyObject *
40267db96d56Sopenharmony_citimezone_tzname(PyDateTime_TimeZone *self, PyObject *dt)
40277db96d56Sopenharmony_ci{
40287db96d56Sopenharmony_ci    if (_timezone_check_argument(dt, "tzname") == -1)
40297db96d56Sopenharmony_ci        return NULL;
40307db96d56Sopenharmony_ci
40317db96d56Sopenharmony_ci    return timezone_str(self);
40327db96d56Sopenharmony_ci}
40337db96d56Sopenharmony_ci
40347db96d56Sopenharmony_cistatic PyObject *
40357db96d56Sopenharmony_citimezone_utcoffset(PyDateTime_TimeZone *self, PyObject *dt)
40367db96d56Sopenharmony_ci{
40377db96d56Sopenharmony_ci    if (_timezone_check_argument(dt, "utcoffset") == -1)
40387db96d56Sopenharmony_ci        return NULL;
40397db96d56Sopenharmony_ci
40407db96d56Sopenharmony_ci    Py_INCREF(self->offset);
40417db96d56Sopenharmony_ci    return self->offset;
40427db96d56Sopenharmony_ci}
40437db96d56Sopenharmony_ci
40447db96d56Sopenharmony_cistatic PyObject *
40457db96d56Sopenharmony_citimezone_dst(PyObject *self, PyObject *dt)
40467db96d56Sopenharmony_ci{
40477db96d56Sopenharmony_ci    if (_timezone_check_argument(dt, "dst") == -1)
40487db96d56Sopenharmony_ci        return NULL;
40497db96d56Sopenharmony_ci
40507db96d56Sopenharmony_ci    Py_RETURN_NONE;
40517db96d56Sopenharmony_ci}
40527db96d56Sopenharmony_ci
40537db96d56Sopenharmony_cistatic PyObject *
40547db96d56Sopenharmony_citimezone_fromutc(PyDateTime_TimeZone *self, PyDateTime_DateTime *dt)
40557db96d56Sopenharmony_ci{
40567db96d56Sopenharmony_ci    if (!PyDateTime_Check(dt)) {
40577db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
40587db96d56Sopenharmony_ci                        "fromutc: argument must be a datetime");
40597db96d56Sopenharmony_ci        return NULL;
40607db96d56Sopenharmony_ci    }
40617db96d56Sopenharmony_ci    if (!HASTZINFO(dt) || dt->tzinfo != (PyObject *)self) {
40627db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError, "fromutc: dt.tzinfo "
40637db96d56Sopenharmony_ci                        "is not self");
40647db96d56Sopenharmony_ci        return NULL;
40657db96d56Sopenharmony_ci    }
40667db96d56Sopenharmony_ci
40677db96d56Sopenharmony_ci    return add_datetime_timedelta(dt, (PyDateTime_Delta *)self->offset, 1);
40687db96d56Sopenharmony_ci}
40697db96d56Sopenharmony_ci
40707db96d56Sopenharmony_cistatic PyObject *
40717db96d56Sopenharmony_citimezone_getinitargs(PyDateTime_TimeZone *self, PyObject *Py_UNUSED(ignored))
40727db96d56Sopenharmony_ci{
40737db96d56Sopenharmony_ci    if (self->name == NULL)
40747db96d56Sopenharmony_ci        return Py_BuildValue("(O)", self->offset);
40757db96d56Sopenharmony_ci    return Py_BuildValue("(OO)", self->offset, self->name);
40767db96d56Sopenharmony_ci}
40777db96d56Sopenharmony_ci
40787db96d56Sopenharmony_cistatic PyMethodDef timezone_methods[] = {
40797db96d56Sopenharmony_ci    {"tzname", (PyCFunction)timezone_tzname, METH_O,
40807db96d56Sopenharmony_ci     PyDoc_STR("If name is specified when timezone is created, returns the name."
40817db96d56Sopenharmony_ci               "  Otherwise returns offset as 'UTC(+|-)HH:MM'.")},
40827db96d56Sopenharmony_ci
40837db96d56Sopenharmony_ci    {"utcoffset", (PyCFunction)timezone_utcoffset, METH_O,
40847db96d56Sopenharmony_ci     PyDoc_STR("Return fixed offset.")},
40857db96d56Sopenharmony_ci
40867db96d56Sopenharmony_ci    {"dst", (PyCFunction)timezone_dst, METH_O,
40877db96d56Sopenharmony_ci     PyDoc_STR("Return None.")},
40887db96d56Sopenharmony_ci
40897db96d56Sopenharmony_ci    {"fromutc", (PyCFunction)timezone_fromutc, METH_O,
40907db96d56Sopenharmony_ci     PyDoc_STR("datetime in UTC -> datetime in local time.")},
40917db96d56Sopenharmony_ci
40927db96d56Sopenharmony_ci    {"__getinitargs__", (PyCFunction)timezone_getinitargs, METH_NOARGS,
40937db96d56Sopenharmony_ci     PyDoc_STR("pickle support")},
40947db96d56Sopenharmony_ci
40957db96d56Sopenharmony_ci    {NULL, NULL}
40967db96d56Sopenharmony_ci};
40977db96d56Sopenharmony_ci
40987db96d56Sopenharmony_cistatic const char timezone_doc[] =
40997db96d56Sopenharmony_ciPyDoc_STR("Fixed offset from UTC implementation of tzinfo.");
41007db96d56Sopenharmony_ci
41017db96d56Sopenharmony_cistatic PyTypeObject PyDateTime_TimeZoneType = {
41027db96d56Sopenharmony_ci    PyVarObject_HEAD_INIT(NULL, 0)
41037db96d56Sopenharmony_ci    "datetime.timezone",              /* tp_name */
41047db96d56Sopenharmony_ci    sizeof(PyDateTime_TimeZone),      /* tp_basicsize */
41057db96d56Sopenharmony_ci    0,                                /* tp_itemsize */
41067db96d56Sopenharmony_ci    (destructor)timezone_dealloc,     /* tp_dealloc */
41077db96d56Sopenharmony_ci    0,                                /* tp_vectorcall_offset */
41087db96d56Sopenharmony_ci    0,                                /* tp_getattr */
41097db96d56Sopenharmony_ci    0,                                /* tp_setattr */
41107db96d56Sopenharmony_ci    0,                                /* tp_as_async */
41117db96d56Sopenharmony_ci    (reprfunc)timezone_repr,          /* tp_repr */
41127db96d56Sopenharmony_ci    0,                                /* tp_as_number */
41137db96d56Sopenharmony_ci    0,                                /* tp_as_sequence */
41147db96d56Sopenharmony_ci    0,                                /* tp_as_mapping */
41157db96d56Sopenharmony_ci    (hashfunc)timezone_hash,          /* tp_hash */
41167db96d56Sopenharmony_ci    0,                                /* tp_call */
41177db96d56Sopenharmony_ci    (reprfunc)timezone_str,           /* tp_str */
41187db96d56Sopenharmony_ci    0,                                /* tp_getattro */
41197db96d56Sopenharmony_ci    0,                                /* tp_setattro */
41207db96d56Sopenharmony_ci    0,                                /* tp_as_buffer */
41217db96d56Sopenharmony_ci    Py_TPFLAGS_DEFAULT,               /* tp_flags */
41227db96d56Sopenharmony_ci    timezone_doc,                     /* tp_doc */
41237db96d56Sopenharmony_ci    0,                                /* tp_traverse */
41247db96d56Sopenharmony_ci    0,                                /* tp_clear */
41257db96d56Sopenharmony_ci    (richcmpfunc)timezone_richcompare,/* tp_richcompare */
41267db96d56Sopenharmony_ci    0,                                /* tp_weaklistoffset */
41277db96d56Sopenharmony_ci    0,                                /* tp_iter */
41287db96d56Sopenharmony_ci    0,                                /* tp_iternext */
41297db96d56Sopenharmony_ci    timezone_methods,                 /* tp_methods */
41307db96d56Sopenharmony_ci    0,                                /* tp_members */
41317db96d56Sopenharmony_ci    0,                                /* tp_getset */
41327db96d56Sopenharmony_ci    0,                                /* tp_base; filled in PyInit__datetime */
41337db96d56Sopenharmony_ci    0,                                /* tp_dict */
41347db96d56Sopenharmony_ci    0,                                /* tp_descr_get */
41357db96d56Sopenharmony_ci    0,                                /* tp_descr_set */
41367db96d56Sopenharmony_ci    0,                                /* tp_dictoffset */
41377db96d56Sopenharmony_ci    0,                                /* tp_init */
41387db96d56Sopenharmony_ci    0,                                /* tp_alloc */
41397db96d56Sopenharmony_ci    timezone_new,                     /* tp_new */
41407db96d56Sopenharmony_ci};
41417db96d56Sopenharmony_ci
41427db96d56Sopenharmony_ci/*
41437db96d56Sopenharmony_ci * PyDateTime_Time implementation.
41447db96d56Sopenharmony_ci */
41457db96d56Sopenharmony_ci
41467db96d56Sopenharmony_ci/* Accessor properties.
41477db96d56Sopenharmony_ci */
41487db96d56Sopenharmony_ci
41497db96d56Sopenharmony_cistatic PyObject *
41507db96d56Sopenharmony_citime_hour(PyDateTime_Time *self, void *unused)
41517db96d56Sopenharmony_ci{
41527db96d56Sopenharmony_ci    return PyLong_FromLong(TIME_GET_HOUR(self));
41537db96d56Sopenharmony_ci}
41547db96d56Sopenharmony_ci
41557db96d56Sopenharmony_cistatic PyObject *
41567db96d56Sopenharmony_citime_minute(PyDateTime_Time *self, void *unused)
41577db96d56Sopenharmony_ci{
41587db96d56Sopenharmony_ci    return PyLong_FromLong(TIME_GET_MINUTE(self));
41597db96d56Sopenharmony_ci}
41607db96d56Sopenharmony_ci
41617db96d56Sopenharmony_ci/* The name time_second conflicted with some platform header file. */
41627db96d56Sopenharmony_cistatic PyObject *
41637db96d56Sopenharmony_cipy_time_second(PyDateTime_Time *self, void *unused)
41647db96d56Sopenharmony_ci{
41657db96d56Sopenharmony_ci    return PyLong_FromLong(TIME_GET_SECOND(self));
41667db96d56Sopenharmony_ci}
41677db96d56Sopenharmony_ci
41687db96d56Sopenharmony_cistatic PyObject *
41697db96d56Sopenharmony_citime_microsecond(PyDateTime_Time *self, void *unused)
41707db96d56Sopenharmony_ci{
41717db96d56Sopenharmony_ci    return PyLong_FromLong(TIME_GET_MICROSECOND(self));
41727db96d56Sopenharmony_ci}
41737db96d56Sopenharmony_ci
41747db96d56Sopenharmony_cistatic PyObject *
41757db96d56Sopenharmony_citime_tzinfo(PyDateTime_Time *self, void *unused)
41767db96d56Sopenharmony_ci{
41777db96d56Sopenharmony_ci    PyObject *result = HASTZINFO(self) ? self->tzinfo : Py_None;
41787db96d56Sopenharmony_ci    Py_INCREF(result);
41797db96d56Sopenharmony_ci    return result;
41807db96d56Sopenharmony_ci}
41817db96d56Sopenharmony_ci
41827db96d56Sopenharmony_cistatic PyObject *
41837db96d56Sopenharmony_citime_fold(PyDateTime_Time *self, void *unused)
41847db96d56Sopenharmony_ci{
41857db96d56Sopenharmony_ci    return PyLong_FromLong(TIME_GET_FOLD(self));
41867db96d56Sopenharmony_ci}
41877db96d56Sopenharmony_ci
41887db96d56Sopenharmony_cistatic PyGetSetDef time_getset[] = {
41897db96d56Sopenharmony_ci    {"hour",        (getter)time_hour},
41907db96d56Sopenharmony_ci    {"minute",      (getter)time_minute},
41917db96d56Sopenharmony_ci    {"second",      (getter)py_time_second},
41927db96d56Sopenharmony_ci    {"microsecond", (getter)time_microsecond},
41937db96d56Sopenharmony_ci    {"tzinfo",      (getter)time_tzinfo},
41947db96d56Sopenharmony_ci    {"fold",        (getter)time_fold},
41957db96d56Sopenharmony_ci    {NULL}
41967db96d56Sopenharmony_ci};
41977db96d56Sopenharmony_ci
41987db96d56Sopenharmony_ci/*
41997db96d56Sopenharmony_ci * Constructors.
42007db96d56Sopenharmony_ci */
42017db96d56Sopenharmony_ci
42027db96d56Sopenharmony_cistatic char *time_kws[] = {"hour", "minute", "second", "microsecond",
42037db96d56Sopenharmony_ci                           "tzinfo", "fold", NULL};
42047db96d56Sopenharmony_ci
42057db96d56Sopenharmony_cistatic PyObject *
42067db96d56Sopenharmony_citime_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo)
42077db96d56Sopenharmony_ci{
42087db96d56Sopenharmony_ci    PyDateTime_Time *me;
42097db96d56Sopenharmony_ci    char aware = (char)(tzinfo != Py_None);
42107db96d56Sopenharmony_ci
42117db96d56Sopenharmony_ci    if (aware && check_tzinfo_subclass(tzinfo) < 0) {
42127db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError, "bad tzinfo state arg");
42137db96d56Sopenharmony_ci        return NULL;
42147db96d56Sopenharmony_ci    }
42157db96d56Sopenharmony_ci
42167db96d56Sopenharmony_ci    me = (PyDateTime_Time *) (type->tp_alloc(type, aware));
42177db96d56Sopenharmony_ci    if (me != NULL) {
42187db96d56Sopenharmony_ci        const char *pdata = PyBytes_AS_STRING(state);
42197db96d56Sopenharmony_ci
42207db96d56Sopenharmony_ci        memcpy(me->data, pdata, _PyDateTime_TIME_DATASIZE);
42217db96d56Sopenharmony_ci        me->hashcode = -1;
42227db96d56Sopenharmony_ci        me->hastzinfo = aware;
42237db96d56Sopenharmony_ci        if (aware) {
42247db96d56Sopenharmony_ci            Py_INCREF(tzinfo);
42257db96d56Sopenharmony_ci            me->tzinfo = tzinfo;
42267db96d56Sopenharmony_ci        }
42277db96d56Sopenharmony_ci        if (pdata[0] & (1 << 7)) {
42287db96d56Sopenharmony_ci            me->data[0] -= 128;
42297db96d56Sopenharmony_ci            me->fold = 1;
42307db96d56Sopenharmony_ci        }
42317db96d56Sopenharmony_ci        else {
42327db96d56Sopenharmony_ci            me->fold = 0;
42337db96d56Sopenharmony_ci        }
42347db96d56Sopenharmony_ci    }
42357db96d56Sopenharmony_ci    return (PyObject *)me;
42367db96d56Sopenharmony_ci}
42377db96d56Sopenharmony_ci
42387db96d56Sopenharmony_cistatic PyObject *
42397db96d56Sopenharmony_citime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
42407db96d56Sopenharmony_ci{
42417db96d56Sopenharmony_ci    PyObject *self = NULL;
42427db96d56Sopenharmony_ci    int hour = 0;
42437db96d56Sopenharmony_ci    int minute = 0;
42447db96d56Sopenharmony_ci    int second = 0;
42457db96d56Sopenharmony_ci    int usecond = 0;
42467db96d56Sopenharmony_ci    PyObject *tzinfo = Py_None;
42477db96d56Sopenharmony_ci    int fold = 0;
42487db96d56Sopenharmony_ci
42497db96d56Sopenharmony_ci    /* Check for invocation from pickle with __getstate__ state */
42507db96d56Sopenharmony_ci    if (PyTuple_GET_SIZE(args) >= 1 && PyTuple_GET_SIZE(args) <= 2) {
42517db96d56Sopenharmony_ci        PyObject *state = PyTuple_GET_ITEM(args, 0);
42527db96d56Sopenharmony_ci        if (PyTuple_GET_SIZE(args) == 2) {
42537db96d56Sopenharmony_ci            tzinfo = PyTuple_GET_ITEM(args, 1);
42547db96d56Sopenharmony_ci        }
42557db96d56Sopenharmony_ci        if (PyBytes_Check(state)) {
42567db96d56Sopenharmony_ci            if (PyBytes_GET_SIZE(state) == _PyDateTime_TIME_DATASIZE &&
42577db96d56Sopenharmony_ci                (0x7F & ((unsigned char) (PyBytes_AS_STRING(state)[0]))) < 24)
42587db96d56Sopenharmony_ci            {
42597db96d56Sopenharmony_ci                return time_from_pickle(type, state, tzinfo);
42607db96d56Sopenharmony_ci            }
42617db96d56Sopenharmony_ci        }
42627db96d56Sopenharmony_ci        else if (PyUnicode_Check(state)) {
42637db96d56Sopenharmony_ci            if (PyUnicode_READY(state)) {
42647db96d56Sopenharmony_ci                return NULL;
42657db96d56Sopenharmony_ci            }
42667db96d56Sopenharmony_ci            if (PyUnicode_GET_LENGTH(state) == _PyDateTime_TIME_DATASIZE &&
42677db96d56Sopenharmony_ci                (0x7F & PyUnicode_READ_CHAR(state, 0)) < 24)
42687db96d56Sopenharmony_ci            {
42697db96d56Sopenharmony_ci                state = PyUnicode_AsLatin1String(state);
42707db96d56Sopenharmony_ci                if (state == NULL) {
42717db96d56Sopenharmony_ci                    if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
42727db96d56Sopenharmony_ci                        /* More informative error message. */
42737db96d56Sopenharmony_ci                        PyErr_SetString(PyExc_ValueError,
42747db96d56Sopenharmony_ci                            "Failed to encode latin1 string when unpickling "
42757db96d56Sopenharmony_ci                            "a time object. "
42767db96d56Sopenharmony_ci                            "pickle.load(data, encoding='latin1') is assumed.");
42777db96d56Sopenharmony_ci                    }
42787db96d56Sopenharmony_ci                    return NULL;
42797db96d56Sopenharmony_ci                }
42807db96d56Sopenharmony_ci                self = time_from_pickle(type, state, tzinfo);
42817db96d56Sopenharmony_ci                Py_DECREF(state);
42827db96d56Sopenharmony_ci                return self;
42837db96d56Sopenharmony_ci            }
42847db96d56Sopenharmony_ci        }
42857db96d56Sopenharmony_ci        tzinfo = Py_None;
42867db96d56Sopenharmony_ci    }
42877db96d56Sopenharmony_ci
42887db96d56Sopenharmony_ci    if (PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO$i", time_kws,
42897db96d56Sopenharmony_ci                                    &hour, &minute, &second, &usecond,
42907db96d56Sopenharmony_ci                                    &tzinfo, &fold)) {
42917db96d56Sopenharmony_ci        self = new_time_ex2(hour, minute, second, usecond, tzinfo, fold,
42927db96d56Sopenharmony_ci                            type);
42937db96d56Sopenharmony_ci    }
42947db96d56Sopenharmony_ci    return self;
42957db96d56Sopenharmony_ci}
42967db96d56Sopenharmony_ci
42977db96d56Sopenharmony_ci/*
42987db96d56Sopenharmony_ci * Destructor.
42997db96d56Sopenharmony_ci */
43007db96d56Sopenharmony_ci
43017db96d56Sopenharmony_cistatic void
43027db96d56Sopenharmony_citime_dealloc(PyDateTime_Time *self)
43037db96d56Sopenharmony_ci{
43047db96d56Sopenharmony_ci    if (HASTZINFO(self)) {
43057db96d56Sopenharmony_ci        Py_XDECREF(self->tzinfo);
43067db96d56Sopenharmony_ci    }
43077db96d56Sopenharmony_ci    Py_TYPE(self)->tp_free((PyObject *)self);
43087db96d56Sopenharmony_ci}
43097db96d56Sopenharmony_ci
43107db96d56Sopenharmony_ci/*
43117db96d56Sopenharmony_ci * Indirect access to tzinfo methods.
43127db96d56Sopenharmony_ci */
43137db96d56Sopenharmony_ci
43147db96d56Sopenharmony_ci/* These are all METH_NOARGS, so don't need to check the arglist. */
43157db96d56Sopenharmony_cistatic PyObject *
43167db96d56Sopenharmony_citime_utcoffset(PyObject *self, PyObject *unused) {
43177db96d56Sopenharmony_ci    return call_utcoffset(GET_TIME_TZINFO(self), Py_None);
43187db96d56Sopenharmony_ci}
43197db96d56Sopenharmony_ci
43207db96d56Sopenharmony_cistatic PyObject *
43217db96d56Sopenharmony_citime_dst(PyObject *self, PyObject *unused) {
43227db96d56Sopenharmony_ci    return call_dst(GET_TIME_TZINFO(self), Py_None);
43237db96d56Sopenharmony_ci}
43247db96d56Sopenharmony_ci
43257db96d56Sopenharmony_cistatic PyObject *
43267db96d56Sopenharmony_citime_tzname(PyDateTime_Time *self, PyObject *unused) {
43277db96d56Sopenharmony_ci    return call_tzname(GET_TIME_TZINFO(self), Py_None);
43287db96d56Sopenharmony_ci}
43297db96d56Sopenharmony_ci
43307db96d56Sopenharmony_ci/*
43317db96d56Sopenharmony_ci * Various ways to turn a time into a string.
43327db96d56Sopenharmony_ci */
43337db96d56Sopenharmony_ci
43347db96d56Sopenharmony_cistatic PyObject *
43357db96d56Sopenharmony_citime_repr(PyDateTime_Time *self)
43367db96d56Sopenharmony_ci{
43377db96d56Sopenharmony_ci    const char *type_name = Py_TYPE(self)->tp_name;
43387db96d56Sopenharmony_ci    int h = TIME_GET_HOUR(self);
43397db96d56Sopenharmony_ci    int m = TIME_GET_MINUTE(self);
43407db96d56Sopenharmony_ci    int s = TIME_GET_SECOND(self);
43417db96d56Sopenharmony_ci    int us = TIME_GET_MICROSECOND(self);
43427db96d56Sopenharmony_ci    int fold = TIME_GET_FOLD(self);
43437db96d56Sopenharmony_ci    PyObject *result = NULL;
43447db96d56Sopenharmony_ci
43457db96d56Sopenharmony_ci    if (us)
43467db96d56Sopenharmony_ci        result = PyUnicode_FromFormat("%s(%d, %d, %d, %d)",
43477db96d56Sopenharmony_ci                                      type_name, h, m, s, us);
43487db96d56Sopenharmony_ci    else if (s)
43497db96d56Sopenharmony_ci        result = PyUnicode_FromFormat("%s(%d, %d, %d)",
43507db96d56Sopenharmony_ci                                      type_name, h, m, s);
43517db96d56Sopenharmony_ci    else
43527db96d56Sopenharmony_ci        result = PyUnicode_FromFormat("%s(%d, %d)", type_name, h, m);
43537db96d56Sopenharmony_ci    if (result != NULL && HASTZINFO(self))
43547db96d56Sopenharmony_ci        result = append_keyword_tzinfo(result, self->tzinfo);
43557db96d56Sopenharmony_ci    if (result != NULL && fold)
43567db96d56Sopenharmony_ci        result = append_keyword_fold(result, fold);
43577db96d56Sopenharmony_ci    return result;
43587db96d56Sopenharmony_ci}
43597db96d56Sopenharmony_ci
43607db96d56Sopenharmony_cistatic PyObject *
43617db96d56Sopenharmony_citime_str(PyDateTime_Time *self)
43627db96d56Sopenharmony_ci{
43637db96d56Sopenharmony_ci    return _PyObject_CallMethodIdNoArgs((PyObject *)self, &PyId_isoformat);
43647db96d56Sopenharmony_ci}
43657db96d56Sopenharmony_ci
43667db96d56Sopenharmony_cistatic PyObject *
43677db96d56Sopenharmony_citime_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw)
43687db96d56Sopenharmony_ci{
43697db96d56Sopenharmony_ci    char buf[100];
43707db96d56Sopenharmony_ci    const char *timespec = NULL;
43717db96d56Sopenharmony_ci    static char *keywords[] = {"timespec", NULL};
43727db96d56Sopenharmony_ci    PyObject *result;
43737db96d56Sopenharmony_ci    int us = TIME_GET_MICROSECOND(self);
43747db96d56Sopenharmony_ci    static const char *specs[][2] = {
43757db96d56Sopenharmony_ci        {"hours", "%02d"},
43767db96d56Sopenharmony_ci        {"minutes", "%02d:%02d"},
43777db96d56Sopenharmony_ci        {"seconds", "%02d:%02d:%02d"},
43787db96d56Sopenharmony_ci        {"milliseconds", "%02d:%02d:%02d.%03d"},
43797db96d56Sopenharmony_ci        {"microseconds", "%02d:%02d:%02d.%06d"},
43807db96d56Sopenharmony_ci    };
43817db96d56Sopenharmony_ci    size_t given_spec;
43827db96d56Sopenharmony_ci
43837db96d56Sopenharmony_ci    if (!PyArg_ParseTupleAndKeywords(args, kw, "|s:isoformat", keywords, &timespec))
43847db96d56Sopenharmony_ci        return NULL;
43857db96d56Sopenharmony_ci
43867db96d56Sopenharmony_ci    if (timespec == NULL || strcmp(timespec, "auto") == 0) {
43877db96d56Sopenharmony_ci        if (us == 0) {
43887db96d56Sopenharmony_ci            /* seconds */
43897db96d56Sopenharmony_ci            given_spec = 2;
43907db96d56Sopenharmony_ci        }
43917db96d56Sopenharmony_ci        else {
43927db96d56Sopenharmony_ci            /* microseconds */
43937db96d56Sopenharmony_ci            given_spec = 4;
43947db96d56Sopenharmony_ci        }
43957db96d56Sopenharmony_ci    }
43967db96d56Sopenharmony_ci    else {
43977db96d56Sopenharmony_ci        for (given_spec = 0; given_spec < Py_ARRAY_LENGTH(specs); given_spec++) {
43987db96d56Sopenharmony_ci            if (strcmp(timespec, specs[given_spec][0]) == 0) {
43997db96d56Sopenharmony_ci                if (given_spec == 3) {
44007db96d56Sopenharmony_ci                    /* milliseconds */
44017db96d56Sopenharmony_ci                    us = us / 1000;
44027db96d56Sopenharmony_ci                }
44037db96d56Sopenharmony_ci                break;
44047db96d56Sopenharmony_ci            }
44057db96d56Sopenharmony_ci        }
44067db96d56Sopenharmony_ci    }
44077db96d56Sopenharmony_ci
44087db96d56Sopenharmony_ci    if (given_spec == Py_ARRAY_LENGTH(specs)) {
44097db96d56Sopenharmony_ci        PyErr_Format(PyExc_ValueError, "Unknown timespec value");
44107db96d56Sopenharmony_ci        return NULL;
44117db96d56Sopenharmony_ci    }
44127db96d56Sopenharmony_ci    else {
44137db96d56Sopenharmony_ci        result = PyUnicode_FromFormat(specs[given_spec][1],
44147db96d56Sopenharmony_ci                                      TIME_GET_HOUR(self), TIME_GET_MINUTE(self),
44157db96d56Sopenharmony_ci                                      TIME_GET_SECOND(self), us);
44167db96d56Sopenharmony_ci    }
44177db96d56Sopenharmony_ci
44187db96d56Sopenharmony_ci    if (result == NULL || !HASTZINFO(self) || self->tzinfo == Py_None)
44197db96d56Sopenharmony_ci        return result;
44207db96d56Sopenharmony_ci
44217db96d56Sopenharmony_ci    /* We need to append the UTC offset. */
44227db96d56Sopenharmony_ci    if (format_utcoffset(buf, sizeof(buf), ":", self->tzinfo,
44237db96d56Sopenharmony_ci                         Py_None) < 0) {
44247db96d56Sopenharmony_ci        Py_DECREF(result);
44257db96d56Sopenharmony_ci        return NULL;
44267db96d56Sopenharmony_ci    }
44277db96d56Sopenharmony_ci    PyUnicode_AppendAndDel(&result, PyUnicode_FromString(buf));
44287db96d56Sopenharmony_ci    return result;
44297db96d56Sopenharmony_ci}
44307db96d56Sopenharmony_ci
44317db96d56Sopenharmony_cistatic PyObject *
44327db96d56Sopenharmony_citime_strftime(PyDateTime_Time *self, PyObject *args, PyObject *kw)
44337db96d56Sopenharmony_ci{
44347db96d56Sopenharmony_ci    PyObject *result;
44357db96d56Sopenharmony_ci    PyObject *tuple;
44367db96d56Sopenharmony_ci    PyObject *format;
44377db96d56Sopenharmony_ci    static char *keywords[] = {"format", NULL};
44387db96d56Sopenharmony_ci
44397db96d56Sopenharmony_ci    if (! PyArg_ParseTupleAndKeywords(args, kw, "U:strftime", keywords,
44407db96d56Sopenharmony_ci                                      &format))
44417db96d56Sopenharmony_ci        return NULL;
44427db96d56Sopenharmony_ci
44437db96d56Sopenharmony_ci    /* Python's strftime does insane things with the year part of the
44447db96d56Sopenharmony_ci     * timetuple.  The year is forced to (the otherwise nonsensical)
44457db96d56Sopenharmony_ci     * 1900 to work around that.
44467db96d56Sopenharmony_ci     */
44477db96d56Sopenharmony_ci    tuple = Py_BuildValue("iiiiiiiii",
44487db96d56Sopenharmony_ci                          1900, 1, 1, /* year, month, day */
44497db96d56Sopenharmony_ci                  TIME_GET_HOUR(self),
44507db96d56Sopenharmony_ci                  TIME_GET_MINUTE(self),
44517db96d56Sopenharmony_ci                  TIME_GET_SECOND(self),
44527db96d56Sopenharmony_ci                  0, 1, -1); /* weekday, daynum, dst */
44537db96d56Sopenharmony_ci    if (tuple == NULL)
44547db96d56Sopenharmony_ci        return NULL;
44557db96d56Sopenharmony_ci    assert(PyTuple_Size(tuple) == 9);
44567db96d56Sopenharmony_ci    result = wrap_strftime((PyObject *)self, format, tuple,
44577db96d56Sopenharmony_ci                           Py_None);
44587db96d56Sopenharmony_ci    Py_DECREF(tuple);
44597db96d56Sopenharmony_ci    return result;
44607db96d56Sopenharmony_ci}
44617db96d56Sopenharmony_ci
44627db96d56Sopenharmony_ci/*
44637db96d56Sopenharmony_ci * Miscellaneous methods.
44647db96d56Sopenharmony_ci */
44657db96d56Sopenharmony_ci
44667db96d56Sopenharmony_cistatic PyObject *
44677db96d56Sopenharmony_citime_richcompare(PyObject *self, PyObject *other, int op)
44687db96d56Sopenharmony_ci{
44697db96d56Sopenharmony_ci    PyObject *result = NULL;
44707db96d56Sopenharmony_ci    PyObject *offset1, *offset2;
44717db96d56Sopenharmony_ci    int diff;
44727db96d56Sopenharmony_ci
44737db96d56Sopenharmony_ci    if (! PyTime_Check(other))
44747db96d56Sopenharmony_ci        Py_RETURN_NOTIMPLEMENTED;
44757db96d56Sopenharmony_ci
44767db96d56Sopenharmony_ci    if (GET_TIME_TZINFO(self) == GET_TIME_TZINFO(other)) {
44777db96d56Sopenharmony_ci        diff = memcmp(((PyDateTime_Time *)self)->data,
44787db96d56Sopenharmony_ci                      ((PyDateTime_Time *)other)->data,
44797db96d56Sopenharmony_ci                      _PyDateTime_TIME_DATASIZE);
44807db96d56Sopenharmony_ci        return diff_to_bool(diff, op);
44817db96d56Sopenharmony_ci    }
44827db96d56Sopenharmony_ci    offset1 = time_utcoffset(self, NULL);
44837db96d56Sopenharmony_ci    if (offset1 == NULL)
44847db96d56Sopenharmony_ci        return NULL;
44857db96d56Sopenharmony_ci    offset2 = time_utcoffset(other, NULL);
44867db96d56Sopenharmony_ci    if (offset2 == NULL)
44877db96d56Sopenharmony_ci        goto done;
44887db96d56Sopenharmony_ci    /* If they're both naive, or both aware and have the same offsets,
44897db96d56Sopenharmony_ci     * we get off cheap.  Note that if they're both naive, offset1 ==
44907db96d56Sopenharmony_ci     * offset2 == Py_None at this point.
44917db96d56Sopenharmony_ci     */
44927db96d56Sopenharmony_ci    if ((offset1 == offset2) ||
44937db96d56Sopenharmony_ci        (PyDelta_Check(offset1) && PyDelta_Check(offset2) &&
44947db96d56Sopenharmony_ci         delta_cmp(offset1, offset2) == 0)) {
44957db96d56Sopenharmony_ci        diff = memcmp(((PyDateTime_Time *)self)->data,
44967db96d56Sopenharmony_ci                      ((PyDateTime_Time *)other)->data,
44977db96d56Sopenharmony_ci                      _PyDateTime_TIME_DATASIZE);
44987db96d56Sopenharmony_ci        result = diff_to_bool(diff, op);
44997db96d56Sopenharmony_ci    }
45007db96d56Sopenharmony_ci    /* The hard case: both aware with different UTC offsets */
45017db96d56Sopenharmony_ci    else if (offset1 != Py_None && offset2 != Py_None) {
45027db96d56Sopenharmony_ci        int offsecs1, offsecs2;
45037db96d56Sopenharmony_ci        assert(offset1 != offset2); /* else last "if" handled it */
45047db96d56Sopenharmony_ci        offsecs1 = TIME_GET_HOUR(self) * 3600 +
45057db96d56Sopenharmony_ci                   TIME_GET_MINUTE(self) * 60 +
45067db96d56Sopenharmony_ci                   TIME_GET_SECOND(self) -
45077db96d56Sopenharmony_ci                   GET_TD_DAYS(offset1) * 86400 -
45087db96d56Sopenharmony_ci                   GET_TD_SECONDS(offset1);
45097db96d56Sopenharmony_ci        offsecs2 = TIME_GET_HOUR(other) * 3600 +
45107db96d56Sopenharmony_ci                   TIME_GET_MINUTE(other) * 60 +
45117db96d56Sopenharmony_ci                   TIME_GET_SECOND(other) -
45127db96d56Sopenharmony_ci                   GET_TD_DAYS(offset2) * 86400 -
45137db96d56Sopenharmony_ci                   GET_TD_SECONDS(offset2);
45147db96d56Sopenharmony_ci        diff = offsecs1 - offsecs2;
45157db96d56Sopenharmony_ci        if (diff == 0)
45167db96d56Sopenharmony_ci            diff = TIME_GET_MICROSECOND(self) -
45177db96d56Sopenharmony_ci                   TIME_GET_MICROSECOND(other);
45187db96d56Sopenharmony_ci        result = diff_to_bool(diff, op);
45197db96d56Sopenharmony_ci    }
45207db96d56Sopenharmony_ci    else if (op == Py_EQ) {
45217db96d56Sopenharmony_ci        result = Py_False;
45227db96d56Sopenharmony_ci        Py_INCREF(result);
45237db96d56Sopenharmony_ci    }
45247db96d56Sopenharmony_ci    else if (op == Py_NE) {
45257db96d56Sopenharmony_ci        result = Py_True;
45267db96d56Sopenharmony_ci        Py_INCREF(result);
45277db96d56Sopenharmony_ci    }
45287db96d56Sopenharmony_ci    else {
45297db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
45307db96d56Sopenharmony_ci                        "can't compare offset-naive and "
45317db96d56Sopenharmony_ci                        "offset-aware times");
45327db96d56Sopenharmony_ci    }
45337db96d56Sopenharmony_ci done:
45347db96d56Sopenharmony_ci    Py_DECREF(offset1);
45357db96d56Sopenharmony_ci    Py_XDECREF(offset2);
45367db96d56Sopenharmony_ci    return result;
45377db96d56Sopenharmony_ci}
45387db96d56Sopenharmony_ci
45397db96d56Sopenharmony_cistatic Py_hash_t
45407db96d56Sopenharmony_citime_hash(PyDateTime_Time *self)
45417db96d56Sopenharmony_ci{
45427db96d56Sopenharmony_ci    if (self->hashcode == -1) {
45437db96d56Sopenharmony_ci        PyObject *offset, *self0;
45447db96d56Sopenharmony_ci        if (TIME_GET_FOLD(self)) {
45457db96d56Sopenharmony_ci            self0 = new_time_ex2(TIME_GET_HOUR(self),
45467db96d56Sopenharmony_ci                                 TIME_GET_MINUTE(self),
45477db96d56Sopenharmony_ci                                 TIME_GET_SECOND(self),
45487db96d56Sopenharmony_ci                                 TIME_GET_MICROSECOND(self),
45497db96d56Sopenharmony_ci                                 HASTZINFO(self) ? self->tzinfo : Py_None,
45507db96d56Sopenharmony_ci                                 0, Py_TYPE(self));
45517db96d56Sopenharmony_ci            if (self0 == NULL)
45527db96d56Sopenharmony_ci                return -1;
45537db96d56Sopenharmony_ci        }
45547db96d56Sopenharmony_ci        else {
45557db96d56Sopenharmony_ci            self0 = (PyObject *)self;
45567db96d56Sopenharmony_ci            Py_INCREF(self0);
45577db96d56Sopenharmony_ci        }
45587db96d56Sopenharmony_ci        offset = time_utcoffset(self0, NULL);
45597db96d56Sopenharmony_ci        Py_DECREF(self0);
45607db96d56Sopenharmony_ci
45617db96d56Sopenharmony_ci        if (offset == NULL)
45627db96d56Sopenharmony_ci            return -1;
45637db96d56Sopenharmony_ci
45647db96d56Sopenharmony_ci        /* Reduce this to a hash of another object. */
45657db96d56Sopenharmony_ci        if (offset == Py_None)
45667db96d56Sopenharmony_ci            self->hashcode = generic_hash(
45677db96d56Sopenharmony_ci                (unsigned char *)self->data, _PyDateTime_TIME_DATASIZE);
45687db96d56Sopenharmony_ci        else {
45697db96d56Sopenharmony_ci            PyObject *temp1, *temp2;
45707db96d56Sopenharmony_ci            int seconds, microseconds;
45717db96d56Sopenharmony_ci            assert(HASTZINFO(self));
45727db96d56Sopenharmony_ci            seconds = TIME_GET_HOUR(self) * 3600 +
45737db96d56Sopenharmony_ci                      TIME_GET_MINUTE(self) * 60 +
45747db96d56Sopenharmony_ci                      TIME_GET_SECOND(self);
45757db96d56Sopenharmony_ci            microseconds = TIME_GET_MICROSECOND(self);
45767db96d56Sopenharmony_ci            temp1 = new_delta(0, seconds, microseconds, 1);
45777db96d56Sopenharmony_ci            if (temp1 == NULL) {
45787db96d56Sopenharmony_ci                Py_DECREF(offset);
45797db96d56Sopenharmony_ci                return -1;
45807db96d56Sopenharmony_ci            }
45817db96d56Sopenharmony_ci            temp2 = delta_subtract(temp1, offset);
45827db96d56Sopenharmony_ci            Py_DECREF(temp1);
45837db96d56Sopenharmony_ci            if (temp2 == NULL) {
45847db96d56Sopenharmony_ci                Py_DECREF(offset);
45857db96d56Sopenharmony_ci                return -1;
45867db96d56Sopenharmony_ci            }
45877db96d56Sopenharmony_ci            self->hashcode = PyObject_Hash(temp2);
45887db96d56Sopenharmony_ci            Py_DECREF(temp2);
45897db96d56Sopenharmony_ci        }
45907db96d56Sopenharmony_ci        Py_DECREF(offset);
45917db96d56Sopenharmony_ci    }
45927db96d56Sopenharmony_ci    return self->hashcode;
45937db96d56Sopenharmony_ci}
45947db96d56Sopenharmony_ci
45957db96d56Sopenharmony_cistatic PyObject *
45967db96d56Sopenharmony_citime_replace(PyDateTime_Time *self, PyObject *args, PyObject *kw)
45977db96d56Sopenharmony_ci{
45987db96d56Sopenharmony_ci    PyObject *clone;
45997db96d56Sopenharmony_ci    PyObject *tuple;
46007db96d56Sopenharmony_ci    int hh = TIME_GET_HOUR(self);
46017db96d56Sopenharmony_ci    int mm = TIME_GET_MINUTE(self);
46027db96d56Sopenharmony_ci    int ss = TIME_GET_SECOND(self);
46037db96d56Sopenharmony_ci    int us = TIME_GET_MICROSECOND(self);
46047db96d56Sopenharmony_ci    PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None;
46057db96d56Sopenharmony_ci    int fold = TIME_GET_FOLD(self);
46067db96d56Sopenharmony_ci
46077db96d56Sopenharmony_ci    if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO$i:replace",
46087db96d56Sopenharmony_ci                                      time_kws,
46097db96d56Sopenharmony_ci                                      &hh, &mm, &ss, &us, &tzinfo, &fold))
46107db96d56Sopenharmony_ci        return NULL;
46117db96d56Sopenharmony_ci    if (fold != 0 && fold != 1) {
46127db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
46137db96d56Sopenharmony_ci                        "fold must be either 0 or 1");
46147db96d56Sopenharmony_ci        return NULL;
46157db96d56Sopenharmony_ci    }
46167db96d56Sopenharmony_ci    tuple = Py_BuildValue("iiiiO", hh, mm, ss, us, tzinfo);
46177db96d56Sopenharmony_ci    if (tuple == NULL)
46187db96d56Sopenharmony_ci        return NULL;
46197db96d56Sopenharmony_ci    clone = time_new(Py_TYPE(self), tuple, NULL);
46207db96d56Sopenharmony_ci    if (clone != NULL) {
46217db96d56Sopenharmony_ci        TIME_SET_FOLD(clone, fold);
46227db96d56Sopenharmony_ci    }
46237db96d56Sopenharmony_ci    Py_DECREF(tuple);
46247db96d56Sopenharmony_ci    return clone;
46257db96d56Sopenharmony_ci}
46267db96d56Sopenharmony_ci
46277db96d56Sopenharmony_cistatic PyObject *
46287db96d56Sopenharmony_citime_fromisoformat(PyObject *cls, PyObject *tstr) {
46297db96d56Sopenharmony_ci    assert(tstr != NULL);
46307db96d56Sopenharmony_ci
46317db96d56Sopenharmony_ci    if (!PyUnicode_Check(tstr)) {
46327db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError, "fromisoformat: argument must be str");
46337db96d56Sopenharmony_ci        return NULL;
46347db96d56Sopenharmony_ci    }
46357db96d56Sopenharmony_ci
46367db96d56Sopenharmony_ci    Py_ssize_t len;
46377db96d56Sopenharmony_ci    const char *p = PyUnicode_AsUTF8AndSize(tstr, &len);
46387db96d56Sopenharmony_ci
46397db96d56Sopenharmony_ci    if (p == NULL) {
46407db96d56Sopenharmony_ci        goto invalid_string_error;
46417db96d56Sopenharmony_ci    }
46427db96d56Sopenharmony_ci
46437db96d56Sopenharmony_ci    // The spec actually requires that time-only ISO 8601 strings start with
46447db96d56Sopenharmony_ci    // T, but the extended format allows this to be omitted as long as there
46457db96d56Sopenharmony_ci    // is no ambiguity with date strings.
46467db96d56Sopenharmony_ci    if (*p == 'T') {
46477db96d56Sopenharmony_ci        ++p;
46487db96d56Sopenharmony_ci        len -= 1;
46497db96d56Sopenharmony_ci    }
46507db96d56Sopenharmony_ci
46517db96d56Sopenharmony_ci    int hour = 0, minute = 0, second = 0, microsecond = 0;
46527db96d56Sopenharmony_ci    int tzoffset, tzimicrosecond = 0;
46537db96d56Sopenharmony_ci    int rv = parse_isoformat_time(p, len,
46547db96d56Sopenharmony_ci                                  &hour, &minute, &second, &microsecond,
46557db96d56Sopenharmony_ci                                  &tzoffset, &tzimicrosecond);
46567db96d56Sopenharmony_ci
46577db96d56Sopenharmony_ci    if (rv < 0) {
46587db96d56Sopenharmony_ci        goto invalid_string_error;
46597db96d56Sopenharmony_ci    }
46607db96d56Sopenharmony_ci
46617db96d56Sopenharmony_ci    PyObject *tzinfo = tzinfo_from_isoformat_results(rv, tzoffset,
46627db96d56Sopenharmony_ci                                                     tzimicrosecond);
46637db96d56Sopenharmony_ci
46647db96d56Sopenharmony_ci    if (tzinfo == NULL) {
46657db96d56Sopenharmony_ci        return NULL;
46667db96d56Sopenharmony_ci    }
46677db96d56Sopenharmony_ci
46687db96d56Sopenharmony_ci    PyObject *t;
46697db96d56Sopenharmony_ci    if ( (PyTypeObject *)cls == &PyDateTime_TimeType ) {
46707db96d56Sopenharmony_ci        t = new_time(hour, minute, second, microsecond, tzinfo, 0);
46717db96d56Sopenharmony_ci    } else {
46727db96d56Sopenharmony_ci        t = PyObject_CallFunction(cls, "iiiiO",
46737db96d56Sopenharmony_ci                                  hour, minute, second, microsecond, tzinfo);
46747db96d56Sopenharmony_ci    }
46757db96d56Sopenharmony_ci
46767db96d56Sopenharmony_ci    Py_DECREF(tzinfo);
46777db96d56Sopenharmony_ci    return t;
46787db96d56Sopenharmony_ci
46797db96d56Sopenharmony_ciinvalid_string_error:
46807db96d56Sopenharmony_ci    PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", tstr);
46817db96d56Sopenharmony_ci    return NULL;
46827db96d56Sopenharmony_ci}
46837db96d56Sopenharmony_ci
46847db96d56Sopenharmony_ci
46857db96d56Sopenharmony_ci/* Pickle support, a simple use of __reduce__. */
46867db96d56Sopenharmony_ci
46877db96d56Sopenharmony_ci/* Let basestate be the non-tzinfo data string.
46887db96d56Sopenharmony_ci * If tzinfo is None, this returns (basestate,), else (basestate, tzinfo).
46897db96d56Sopenharmony_ci * So it's a tuple in any (non-error) case.
46907db96d56Sopenharmony_ci * __getstate__ isn't exposed.
46917db96d56Sopenharmony_ci */
46927db96d56Sopenharmony_cistatic PyObject *
46937db96d56Sopenharmony_citime_getstate(PyDateTime_Time *self, int proto)
46947db96d56Sopenharmony_ci{
46957db96d56Sopenharmony_ci    PyObject *basestate;
46967db96d56Sopenharmony_ci    PyObject *result = NULL;
46977db96d56Sopenharmony_ci
46987db96d56Sopenharmony_ci    basestate =  PyBytes_FromStringAndSize((char *)self->data,
46997db96d56Sopenharmony_ci                                            _PyDateTime_TIME_DATASIZE);
47007db96d56Sopenharmony_ci    if (basestate != NULL) {
47017db96d56Sopenharmony_ci        if (proto > 3 && TIME_GET_FOLD(self))
47027db96d56Sopenharmony_ci            /* Set the first bit of the first byte */
47037db96d56Sopenharmony_ci            PyBytes_AS_STRING(basestate)[0] |= (1 << 7);
47047db96d56Sopenharmony_ci        if (! HASTZINFO(self) || self->tzinfo == Py_None)
47057db96d56Sopenharmony_ci            result = PyTuple_Pack(1, basestate);
47067db96d56Sopenharmony_ci        else
47077db96d56Sopenharmony_ci            result = PyTuple_Pack(2, basestate, self->tzinfo);
47087db96d56Sopenharmony_ci        Py_DECREF(basestate);
47097db96d56Sopenharmony_ci    }
47107db96d56Sopenharmony_ci    return result;
47117db96d56Sopenharmony_ci}
47127db96d56Sopenharmony_ci
47137db96d56Sopenharmony_cistatic PyObject *
47147db96d56Sopenharmony_citime_reduce_ex(PyDateTime_Time *self, PyObject *args)
47157db96d56Sopenharmony_ci{
47167db96d56Sopenharmony_ci    int proto;
47177db96d56Sopenharmony_ci    if (!PyArg_ParseTuple(args, "i:__reduce_ex__", &proto))
47187db96d56Sopenharmony_ci        return NULL;
47197db96d56Sopenharmony_ci
47207db96d56Sopenharmony_ci    return Py_BuildValue("(ON)", Py_TYPE(self), time_getstate(self, proto));
47217db96d56Sopenharmony_ci}
47227db96d56Sopenharmony_ci
47237db96d56Sopenharmony_cistatic PyObject *
47247db96d56Sopenharmony_citime_reduce(PyDateTime_Time *self, PyObject *arg)
47257db96d56Sopenharmony_ci{
47267db96d56Sopenharmony_ci    return Py_BuildValue("(ON)", Py_TYPE(self), time_getstate(self, 2));
47277db96d56Sopenharmony_ci}
47287db96d56Sopenharmony_ci
47297db96d56Sopenharmony_cistatic PyMethodDef time_methods[] = {
47307db96d56Sopenharmony_ci
47317db96d56Sopenharmony_ci    {"isoformat",   _PyCFunction_CAST(time_isoformat),        METH_VARARGS | METH_KEYWORDS,
47327db96d56Sopenharmony_ci     PyDoc_STR("Return string in ISO 8601 format, [HH[:MM[:SS[.mmm[uuu]]]]]"
47337db96d56Sopenharmony_ci               "[+HH:MM].\n\n"
47347db96d56Sopenharmony_ci               "The optional argument timespec specifies the number "
47357db96d56Sopenharmony_ci               "of additional terms\nof the time to include. Valid "
47367db96d56Sopenharmony_ci               "options are 'auto', 'hours', 'minutes',\n'seconds', "
47377db96d56Sopenharmony_ci               "'milliseconds' and 'microseconds'.\n")},
47387db96d56Sopenharmony_ci
47397db96d56Sopenharmony_ci    {"strftime",        _PyCFunction_CAST(time_strftime),     METH_VARARGS | METH_KEYWORDS,
47407db96d56Sopenharmony_ci     PyDoc_STR("format -> strftime() style string.")},
47417db96d56Sopenharmony_ci
47427db96d56Sopenharmony_ci    {"__format__",      (PyCFunction)date_format,       METH_VARARGS,
47437db96d56Sopenharmony_ci     PyDoc_STR("Formats self with strftime.")},
47447db96d56Sopenharmony_ci
47457db96d56Sopenharmony_ci    {"utcoffset",       (PyCFunction)time_utcoffset,    METH_NOARGS,
47467db96d56Sopenharmony_ci     PyDoc_STR("Return self.tzinfo.utcoffset(self).")},
47477db96d56Sopenharmony_ci
47487db96d56Sopenharmony_ci    {"tzname",          (PyCFunction)time_tzname,       METH_NOARGS,
47497db96d56Sopenharmony_ci     PyDoc_STR("Return self.tzinfo.tzname(self).")},
47507db96d56Sopenharmony_ci
47517db96d56Sopenharmony_ci    {"dst",             (PyCFunction)time_dst,          METH_NOARGS,
47527db96d56Sopenharmony_ci     PyDoc_STR("Return self.tzinfo.dst(self).")},
47537db96d56Sopenharmony_ci
47547db96d56Sopenharmony_ci    {"replace",     _PyCFunction_CAST(time_replace),          METH_VARARGS | METH_KEYWORDS,
47557db96d56Sopenharmony_ci     PyDoc_STR("Return time with new specified fields.")},
47567db96d56Sopenharmony_ci
47577db96d56Sopenharmony_ci     {"fromisoformat", (PyCFunction)time_fromisoformat, METH_O | METH_CLASS,
47587db96d56Sopenharmony_ci     PyDoc_STR("string -> time from a string in ISO 8601 format")},
47597db96d56Sopenharmony_ci
47607db96d56Sopenharmony_ci    {"__reduce_ex__", (PyCFunction)time_reduce_ex,        METH_VARARGS,
47617db96d56Sopenharmony_ci     PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")},
47627db96d56Sopenharmony_ci
47637db96d56Sopenharmony_ci    {"__reduce__", (PyCFunction)time_reduce,        METH_NOARGS,
47647db96d56Sopenharmony_ci     PyDoc_STR("__reduce__() -> (cls, state)")},
47657db96d56Sopenharmony_ci
47667db96d56Sopenharmony_ci    {NULL,      NULL}
47677db96d56Sopenharmony_ci};
47687db96d56Sopenharmony_ci
47697db96d56Sopenharmony_cistatic const char time_doc[] =
47707db96d56Sopenharmony_ciPyDoc_STR("time([hour[, minute[, second[, microsecond[, tzinfo]]]]]) --> a time object\n\
47717db96d56Sopenharmony_ci\n\
47727db96d56Sopenharmony_ciAll arguments are optional. tzinfo may be None, or an instance of\n\
47737db96d56Sopenharmony_cia tzinfo subclass. The remaining arguments may be ints.\n");
47747db96d56Sopenharmony_ci
47757db96d56Sopenharmony_cistatic PyTypeObject PyDateTime_TimeType = {
47767db96d56Sopenharmony_ci    PyVarObject_HEAD_INIT(NULL, 0)
47777db96d56Sopenharmony_ci    "datetime.time",                            /* tp_name */
47787db96d56Sopenharmony_ci    sizeof(PyDateTime_Time),                    /* tp_basicsize */
47797db96d56Sopenharmony_ci    0,                                          /* tp_itemsize */
47807db96d56Sopenharmony_ci    (destructor)time_dealloc,                   /* tp_dealloc */
47817db96d56Sopenharmony_ci    0,                                          /* tp_vectorcall_offset */
47827db96d56Sopenharmony_ci    0,                                          /* tp_getattr */
47837db96d56Sopenharmony_ci    0,                                          /* tp_setattr */
47847db96d56Sopenharmony_ci    0,                                          /* tp_as_async */
47857db96d56Sopenharmony_ci    (reprfunc)time_repr,                        /* tp_repr */
47867db96d56Sopenharmony_ci    0,                                          /* tp_as_number */
47877db96d56Sopenharmony_ci    0,                                          /* tp_as_sequence */
47887db96d56Sopenharmony_ci    0,                                          /* tp_as_mapping */
47897db96d56Sopenharmony_ci    (hashfunc)time_hash,                        /* tp_hash */
47907db96d56Sopenharmony_ci    0,                                          /* tp_call */
47917db96d56Sopenharmony_ci    (reprfunc)time_str,                         /* tp_str */
47927db96d56Sopenharmony_ci    PyObject_GenericGetAttr,                    /* tp_getattro */
47937db96d56Sopenharmony_ci    0,                                          /* tp_setattro */
47947db96d56Sopenharmony_ci    0,                                          /* tp_as_buffer */
47957db96d56Sopenharmony_ci    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
47967db96d56Sopenharmony_ci    time_doc,                                   /* tp_doc */
47977db96d56Sopenharmony_ci    0,                                          /* tp_traverse */
47987db96d56Sopenharmony_ci    0,                                          /* tp_clear */
47997db96d56Sopenharmony_ci    time_richcompare,                           /* tp_richcompare */
48007db96d56Sopenharmony_ci    0,                                          /* tp_weaklistoffset */
48017db96d56Sopenharmony_ci    0,                                          /* tp_iter */
48027db96d56Sopenharmony_ci    0,                                          /* tp_iternext */
48037db96d56Sopenharmony_ci    time_methods,                               /* tp_methods */
48047db96d56Sopenharmony_ci    0,                                          /* tp_members */
48057db96d56Sopenharmony_ci    time_getset,                                /* tp_getset */
48067db96d56Sopenharmony_ci    0,                                          /* tp_base */
48077db96d56Sopenharmony_ci    0,                                          /* tp_dict */
48087db96d56Sopenharmony_ci    0,                                          /* tp_descr_get */
48097db96d56Sopenharmony_ci    0,                                          /* tp_descr_set */
48107db96d56Sopenharmony_ci    0,                                          /* tp_dictoffset */
48117db96d56Sopenharmony_ci    0,                                          /* tp_init */
48127db96d56Sopenharmony_ci    time_alloc,                                 /* tp_alloc */
48137db96d56Sopenharmony_ci    time_new,                                   /* tp_new */
48147db96d56Sopenharmony_ci    0,                                          /* tp_free */
48157db96d56Sopenharmony_ci};
48167db96d56Sopenharmony_ci
48177db96d56Sopenharmony_ci/*
48187db96d56Sopenharmony_ci * PyDateTime_DateTime implementation.
48197db96d56Sopenharmony_ci */
48207db96d56Sopenharmony_ci
48217db96d56Sopenharmony_ci/* Accessor properties.  Properties for day, month, and year are inherited
48227db96d56Sopenharmony_ci * from date.
48237db96d56Sopenharmony_ci */
48247db96d56Sopenharmony_ci
48257db96d56Sopenharmony_cistatic PyObject *
48267db96d56Sopenharmony_cidatetime_hour(PyDateTime_DateTime *self, void *unused)
48277db96d56Sopenharmony_ci{
48287db96d56Sopenharmony_ci    return PyLong_FromLong(DATE_GET_HOUR(self));
48297db96d56Sopenharmony_ci}
48307db96d56Sopenharmony_ci
48317db96d56Sopenharmony_cistatic PyObject *
48327db96d56Sopenharmony_cidatetime_minute(PyDateTime_DateTime *self, void *unused)
48337db96d56Sopenharmony_ci{
48347db96d56Sopenharmony_ci    return PyLong_FromLong(DATE_GET_MINUTE(self));
48357db96d56Sopenharmony_ci}
48367db96d56Sopenharmony_ci
48377db96d56Sopenharmony_cistatic PyObject *
48387db96d56Sopenharmony_cidatetime_second(PyDateTime_DateTime *self, void *unused)
48397db96d56Sopenharmony_ci{
48407db96d56Sopenharmony_ci    return PyLong_FromLong(DATE_GET_SECOND(self));
48417db96d56Sopenharmony_ci}
48427db96d56Sopenharmony_ci
48437db96d56Sopenharmony_cistatic PyObject *
48447db96d56Sopenharmony_cidatetime_microsecond(PyDateTime_DateTime *self, void *unused)
48457db96d56Sopenharmony_ci{
48467db96d56Sopenharmony_ci    return PyLong_FromLong(DATE_GET_MICROSECOND(self));
48477db96d56Sopenharmony_ci}
48487db96d56Sopenharmony_ci
48497db96d56Sopenharmony_cistatic PyObject *
48507db96d56Sopenharmony_cidatetime_tzinfo(PyDateTime_DateTime *self, void *unused)
48517db96d56Sopenharmony_ci{
48527db96d56Sopenharmony_ci    PyObject *result = HASTZINFO(self) ? self->tzinfo : Py_None;
48537db96d56Sopenharmony_ci    Py_INCREF(result);
48547db96d56Sopenharmony_ci    return result;
48557db96d56Sopenharmony_ci}
48567db96d56Sopenharmony_ci
48577db96d56Sopenharmony_cistatic PyObject *
48587db96d56Sopenharmony_cidatetime_fold(PyDateTime_DateTime *self, void *unused)
48597db96d56Sopenharmony_ci{
48607db96d56Sopenharmony_ci    return PyLong_FromLong(DATE_GET_FOLD(self));
48617db96d56Sopenharmony_ci}
48627db96d56Sopenharmony_ci
48637db96d56Sopenharmony_cistatic PyGetSetDef datetime_getset[] = {
48647db96d56Sopenharmony_ci    {"hour",        (getter)datetime_hour},
48657db96d56Sopenharmony_ci    {"minute",      (getter)datetime_minute},
48667db96d56Sopenharmony_ci    {"second",      (getter)datetime_second},
48677db96d56Sopenharmony_ci    {"microsecond", (getter)datetime_microsecond},
48687db96d56Sopenharmony_ci    {"tzinfo",      (getter)datetime_tzinfo},
48697db96d56Sopenharmony_ci    {"fold",        (getter)datetime_fold},
48707db96d56Sopenharmony_ci    {NULL}
48717db96d56Sopenharmony_ci};
48727db96d56Sopenharmony_ci
48737db96d56Sopenharmony_ci/*
48747db96d56Sopenharmony_ci * Constructors.
48757db96d56Sopenharmony_ci */
48767db96d56Sopenharmony_ci
48777db96d56Sopenharmony_cistatic char *datetime_kws[] = {
48787db96d56Sopenharmony_ci    "year", "month", "day", "hour", "minute", "second",
48797db96d56Sopenharmony_ci    "microsecond", "tzinfo", "fold", NULL
48807db96d56Sopenharmony_ci};
48817db96d56Sopenharmony_ci
48827db96d56Sopenharmony_cistatic PyObject *
48837db96d56Sopenharmony_cidatetime_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo)
48847db96d56Sopenharmony_ci{
48857db96d56Sopenharmony_ci    PyDateTime_DateTime *me;
48867db96d56Sopenharmony_ci    char aware = (char)(tzinfo != Py_None);
48877db96d56Sopenharmony_ci
48887db96d56Sopenharmony_ci    if (aware && check_tzinfo_subclass(tzinfo) < 0) {
48897db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError, "bad tzinfo state arg");
48907db96d56Sopenharmony_ci        return NULL;
48917db96d56Sopenharmony_ci    }
48927db96d56Sopenharmony_ci
48937db96d56Sopenharmony_ci    me = (PyDateTime_DateTime *) (type->tp_alloc(type , aware));
48947db96d56Sopenharmony_ci    if (me != NULL) {
48957db96d56Sopenharmony_ci        const char *pdata = PyBytes_AS_STRING(state);
48967db96d56Sopenharmony_ci
48977db96d56Sopenharmony_ci        memcpy(me->data, pdata, _PyDateTime_DATETIME_DATASIZE);
48987db96d56Sopenharmony_ci        me->hashcode = -1;
48997db96d56Sopenharmony_ci        me->hastzinfo = aware;
49007db96d56Sopenharmony_ci        if (aware) {
49017db96d56Sopenharmony_ci            Py_INCREF(tzinfo);
49027db96d56Sopenharmony_ci            me->tzinfo = tzinfo;
49037db96d56Sopenharmony_ci        }
49047db96d56Sopenharmony_ci        if (pdata[2] & (1 << 7)) {
49057db96d56Sopenharmony_ci            me->data[2] -= 128;
49067db96d56Sopenharmony_ci            me->fold = 1;
49077db96d56Sopenharmony_ci        }
49087db96d56Sopenharmony_ci        else {
49097db96d56Sopenharmony_ci            me->fold = 0;
49107db96d56Sopenharmony_ci        }
49117db96d56Sopenharmony_ci    }
49127db96d56Sopenharmony_ci    return (PyObject *)me;
49137db96d56Sopenharmony_ci}
49147db96d56Sopenharmony_ci
49157db96d56Sopenharmony_cistatic PyObject *
49167db96d56Sopenharmony_cidatetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
49177db96d56Sopenharmony_ci{
49187db96d56Sopenharmony_ci    PyObject *self = NULL;
49197db96d56Sopenharmony_ci    int year;
49207db96d56Sopenharmony_ci    int month;
49217db96d56Sopenharmony_ci    int day;
49227db96d56Sopenharmony_ci    int hour = 0;
49237db96d56Sopenharmony_ci    int minute = 0;
49247db96d56Sopenharmony_ci    int second = 0;
49257db96d56Sopenharmony_ci    int usecond = 0;
49267db96d56Sopenharmony_ci    int fold = 0;
49277db96d56Sopenharmony_ci    PyObject *tzinfo = Py_None;
49287db96d56Sopenharmony_ci
49297db96d56Sopenharmony_ci    /* Check for invocation from pickle with __getstate__ state */
49307db96d56Sopenharmony_ci    if (PyTuple_GET_SIZE(args) >= 1 && PyTuple_GET_SIZE(args) <= 2) {
49317db96d56Sopenharmony_ci        PyObject *state = PyTuple_GET_ITEM(args, 0);
49327db96d56Sopenharmony_ci        if (PyTuple_GET_SIZE(args) == 2) {
49337db96d56Sopenharmony_ci            tzinfo = PyTuple_GET_ITEM(args, 1);
49347db96d56Sopenharmony_ci        }
49357db96d56Sopenharmony_ci        if (PyBytes_Check(state)) {
49367db96d56Sopenharmony_ci            if (PyBytes_GET_SIZE(state) == _PyDateTime_DATETIME_DATASIZE &&
49377db96d56Sopenharmony_ci                MONTH_IS_SANE(PyBytes_AS_STRING(state)[2] & 0x7F))
49387db96d56Sopenharmony_ci            {
49397db96d56Sopenharmony_ci                return datetime_from_pickle(type, state, tzinfo);
49407db96d56Sopenharmony_ci            }
49417db96d56Sopenharmony_ci        }
49427db96d56Sopenharmony_ci        else if (PyUnicode_Check(state)) {
49437db96d56Sopenharmony_ci            if (PyUnicode_READY(state)) {
49447db96d56Sopenharmony_ci                return NULL;
49457db96d56Sopenharmony_ci            }
49467db96d56Sopenharmony_ci            if (PyUnicode_GET_LENGTH(state) == _PyDateTime_DATETIME_DATASIZE &&
49477db96d56Sopenharmony_ci                MONTH_IS_SANE(PyUnicode_READ_CHAR(state, 2) & 0x7F))
49487db96d56Sopenharmony_ci            {
49497db96d56Sopenharmony_ci                state = PyUnicode_AsLatin1String(state);
49507db96d56Sopenharmony_ci                if (state == NULL) {
49517db96d56Sopenharmony_ci                    if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
49527db96d56Sopenharmony_ci                        /* More informative error message. */
49537db96d56Sopenharmony_ci                        PyErr_SetString(PyExc_ValueError,
49547db96d56Sopenharmony_ci                            "Failed to encode latin1 string when unpickling "
49557db96d56Sopenharmony_ci                            "a datetime object. "
49567db96d56Sopenharmony_ci                            "pickle.load(data, encoding='latin1') is assumed.");
49577db96d56Sopenharmony_ci                    }
49587db96d56Sopenharmony_ci                    return NULL;
49597db96d56Sopenharmony_ci                }
49607db96d56Sopenharmony_ci                self = datetime_from_pickle(type, state, tzinfo);
49617db96d56Sopenharmony_ci                Py_DECREF(state);
49627db96d56Sopenharmony_ci                return self;
49637db96d56Sopenharmony_ci            }
49647db96d56Sopenharmony_ci        }
49657db96d56Sopenharmony_ci        tzinfo = Py_None;
49667db96d56Sopenharmony_ci    }
49677db96d56Sopenharmony_ci
49687db96d56Sopenharmony_ci    if (PyArg_ParseTupleAndKeywords(args, kw, "iii|iiiiO$i", datetime_kws,
49697db96d56Sopenharmony_ci                                    &year, &month, &day, &hour, &minute,
49707db96d56Sopenharmony_ci                                    &second, &usecond, &tzinfo, &fold)) {
49717db96d56Sopenharmony_ci        self = new_datetime_ex2(year, month, day,
49727db96d56Sopenharmony_ci                                hour, minute, second, usecond,
49737db96d56Sopenharmony_ci                                tzinfo, fold, type);
49747db96d56Sopenharmony_ci    }
49757db96d56Sopenharmony_ci    return self;
49767db96d56Sopenharmony_ci}
49777db96d56Sopenharmony_ci
49787db96d56Sopenharmony_ci/* TM_FUNC is the shared type of _PyTime_localtime() and
49797db96d56Sopenharmony_ci * _PyTime_gmtime(). */
49807db96d56Sopenharmony_citypedef int (*TM_FUNC)(time_t timer, struct tm*);
49817db96d56Sopenharmony_ci
49827db96d56Sopenharmony_ci/* As of version 2015f max fold in IANA database is
49837db96d56Sopenharmony_ci * 23 hours at 1969-09-30 13:00:00 in Kwajalein. */
49847db96d56Sopenharmony_cistatic long long max_fold_seconds = 24 * 3600;
49857db96d56Sopenharmony_ci/* NB: date(1970,1,1).toordinal() == 719163 */
49867db96d56Sopenharmony_cistatic long long epoch = 719163LL * 24 * 60 * 60;
49877db96d56Sopenharmony_ci
49887db96d56Sopenharmony_cistatic long long
49897db96d56Sopenharmony_ciutc_to_seconds(int year, int month, int day,
49907db96d56Sopenharmony_ci               int hour, int minute, int second)
49917db96d56Sopenharmony_ci{
49927db96d56Sopenharmony_ci    long long ordinal;
49937db96d56Sopenharmony_ci
49947db96d56Sopenharmony_ci    /* ymd_to_ord() doesn't support year <= 0 */
49957db96d56Sopenharmony_ci    if (year < MINYEAR || year > MAXYEAR) {
49967db96d56Sopenharmony_ci        PyErr_Format(PyExc_ValueError, "year %i is out of range", year);
49977db96d56Sopenharmony_ci        return -1;
49987db96d56Sopenharmony_ci    }
49997db96d56Sopenharmony_ci
50007db96d56Sopenharmony_ci    ordinal = ymd_to_ord(year, month, day);
50017db96d56Sopenharmony_ci    return ((ordinal * 24 + hour) * 60 + minute) * 60 + second;
50027db96d56Sopenharmony_ci}
50037db96d56Sopenharmony_ci
50047db96d56Sopenharmony_cistatic long long
50057db96d56Sopenharmony_cilocal(long long u)
50067db96d56Sopenharmony_ci{
50077db96d56Sopenharmony_ci    struct tm local_time;
50087db96d56Sopenharmony_ci    time_t t;
50097db96d56Sopenharmony_ci    u -= epoch;
50107db96d56Sopenharmony_ci    t = u;
50117db96d56Sopenharmony_ci    if (t != u) {
50127db96d56Sopenharmony_ci        PyErr_SetString(PyExc_OverflowError,
50137db96d56Sopenharmony_ci        "timestamp out of range for platform time_t");
50147db96d56Sopenharmony_ci        return -1;
50157db96d56Sopenharmony_ci    }
50167db96d56Sopenharmony_ci    if (_PyTime_localtime(t, &local_time) != 0)
50177db96d56Sopenharmony_ci        return -1;
50187db96d56Sopenharmony_ci    return utc_to_seconds(local_time.tm_year + 1900,
50197db96d56Sopenharmony_ci                          local_time.tm_mon + 1,
50207db96d56Sopenharmony_ci                          local_time.tm_mday,
50217db96d56Sopenharmony_ci                          local_time.tm_hour,
50227db96d56Sopenharmony_ci                          local_time.tm_min,
50237db96d56Sopenharmony_ci                          local_time.tm_sec);
50247db96d56Sopenharmony_ci}
50257db96d56Sopenharmony_ci
50267db96d56Sopenharmony_ci/* Internal helper.
50277db96d56Sopenharmony_ci * Build datetime from a time_t and a distinct count of microseconds.
50287db96d56Sopenharmony_ci * Pass localtime or gmtime for f, to control the interpretation of timet.
50297db96d56Sopenharmony_ci */
50307db96d56Sopenharmony_cistatic PyObject *
50317db96d56Sopenharmony_cidatetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us,
50327db96d56Sopenharmony_ci                           PyObject *tzinfo)
50337db96d56Sopenharmony_ci{
50347db96d56Sopenharmony_ci    struct tm tm;
50357db96d56Sopenharmony_ci    int year, month, day, hour, minute, second, fold = 0;
50367db96d56Sopenharmony_ci
50377db96d56Sopenharmony_ci    if (f(timet, &tm) != 0)
50387db96d56Sopenharmony_ci        return NULL;
50397db96d56Sopenharmony_ci
50407db96d56Sopenharmony_ci    year = tm.tm_year + 1900;
50417db96d56Sopenharmony_ci    month = tm.tm_mon + 1;
50427db96d56Sopenharmony_ci    day = tm.tm_mday;
50437db96d56Sopenharmony_ci    hour = tm.tm_hour;
50447db96d56Sopenharmony_ci    minute = tm.tm_min;
50457db96d56Sopenharmony_ci    /* The platform localtime/gmtime may insert leap seconds,
50467db96d56Sopenharmony_ci     * indicated by tm.tm_sec > 59.  We don't care about them,
50477db96d56Sopenharmony_ci     * except to the extent that passing them on to the datetime
50487db96d56Sopenharmony_ci     * constructor would raise ValueError for a reason that
50497db96d56Sopenharmony_ci     * made no sense to the user.
50507db96d56Sopenharmony_ci     */
50517db96d56Sopenharmony_ci    second = Py_MIN(59, tm.tm_sec);
50527db96d56Sopenharmony_ci
50537db96d56Sopenharmony_ci    /* local timezone requires to compute fold */
50547db96d56Sopenharmony_ci    if (tzinfo == Py_None && f == _PyTime_localtime
50557db96d56Sopenharmony_ci    /* On Windows, passing a negative value to local results
50567db96d56Sopenharmony_ci     * in an OSError because localtime_s on Windows does
50577db96d56Sopenharmony_ci     * not support negative timestamps. Unfortunately this
50587db96d56Sopenharmony_ci     * means that fold detection for time values between
50597db96d56Sopenharmony_ci     * 0 and max_fold_seconds will result in an identical
50607db96d56Sopenharmony_ci     * error since we subtract max_fold_seconds to detect a
50617db96d56Sopenharmony_ci     * fold. However, since we know there haven't been any
50627db96d56Sopenharmony_ci     * folds in the interval [0, max_fold_seconds) in any
50637db96d56Sopenharmony_ci     * timezone, we can hackily just forego fold detection
50647db96d56Sopenharmony_ci     * for this time range.
50657db96d56Sopenharmony_ci     */
50667db96d56Sopenharmony_ci#ifdef MS_WINDOWS
50677db96d56Sopenharmony_ci        && (timet - max_fold_seconds > 0)
50687db96d56Sopenharmony_ci#endif
50697db96d56Sopenharmony_ci        ) {
50707db96d56Sopenharmony_ci        long long probe_seconds, result_seconds, transition;
50717db96d56Sopenharmony_ci
50727db96d56Sopenharmony_ci        result_seconds = utc_to_seconds(year, month, day,
50737db96d56Sopenharmony_ci                                        hour, minute, second);
50747db96d56Sopenharmony_ci        if (result_seconds == -1 && PyErr_Occurred()) {
50757db96d56Sopenharmony_ci            return NULL;
50767db96d56Sopenharmony_ci        }
50777db96d56Sopenharmony_ci
50787db96d56Sopenharmony_ci        /* Probe max_fold_seconds to detect a fold. */
50797db96d56Sopenharmony_ci        probe_seconds = local(epoch + timet - max_fold_seconds);
50807db96d56Sopenharmony_ci        if (probe_seconds == -1)
50817db96d56Sopenharmony_ci            return NULL;
50827db96d56Sopenharmony_ci        transition = result_seconds - probe_seconds - max_fold_seconds;
50837db96d56Sopenharmony_ci        if (transition < 0) {
50847db96d56Sopenharmony_ci            probe_seconds = local(epoch + timet + transition);
50857db96d56Sopenharmony_ci            if (probe_seconds == -1)
50867db96d56Sopenharmony_ci                return NULL;
50877db96d56Sopenharmony_ci            if (probe_seconds == result_seconds)
50887db96d56Sopenharmony_ci                fold = 1;
50897db96d56Sopenharmony_ci        }
50907db96d56Sopenharmony_ci    }
50917db96d56Sopenharmony_ci    return new_datetime_subclass_fold_ex(year, month, day, hour, minute,
50927db96d56Sopenharmony_ci                                         second, us, tzinfo, fold, cls);
50937db96d56Sopenharmony_ci}
50947db96d56Sopenharmony_ci
50957db96d56Sopenharmony_ci/* Internal helper.
50967db96d56Sopenharmony_ci * Build datetime from a Python timestamp.  Pass localtime or gmtime for f,
50977db96d56Sopenharmony_ci * to control the interpretation of the timestamp.  Since a double doesn't
50987db96d56Sopenharmony_ci * have enough bits to cover a datetime's full range of precision, it's
50997db96d56Sopenharmony_ci * better to call datetime_from_timet_and_us provided you have a way
51007db96d56Sopenharmony_ci * to get that much precision (e.g., C time() isn't good enough).
51017db96d56Sopenharmony_ci */
51027db96d56Sopenharmony_cistatic PyObject *
51037db96d56Sopenharmony_cidatetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp,
51047db96d56Sopenharmony_ci                        PyObject *tzinfo)
51057db96d56Sopenharmony_ci{
51067db96d56Sopenharmony_ci    time_t timet;
51077db96d56Sopenharmony_ci    long us;
51087db96d56Sopenharmony_ci
51097db96d56Sopenharmony_ci    if (_PyTime_ObjectToTimeval(timestamp,
51107db96d56Sopenharmony_ci                                &timet, &us, _PyTime_ROUND_HALF_EVEN) == -1)
51117db96d56Sopenharmony_ci        return NULL;
51127db96d56Sopenharmony_ci
51137db96d56Sopenharmony_ci    return datetime_from_timet_and_us(cls, f, timet, (int)us, tzinfo);
51147db96d56Sopenharmony_ci}
51157db96d56Sopenharmony_ci
51167db96d56Sopenharmony_ci/* Internal helper.
51177db96d56Sopenharmony_ci * Build most accurate possible datetime for current time.  Pass localtime or
51187db96d56Sopenharmony_ci * gmtime for f as appropriate.
51197db96d56Sopenharmony_ci */
51207db96d56Sopenharmony_cistatic PyObject *
51217db96d56Sopenharmony_cidatetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo)
51227db96d56Sopenharmony_ci{
51237db96d56Sopenharmony_ci    _PyTime_t ts = _PyTime_GetSystemClock();
51247db96d56Sopenharmony_ci    time_t secs;
51257db96d56Sopenharmony_ci    int us;
51267db96d56Sopenharmony_ci
51277db96d56Sopenharmony_ci    if (_PyTime_AsTimevalTime_t(ts, &secs, &us, _PyTime_ROUND_FLOOR) < 0)
51287db96d56Sopenharmony_ci        return NULL;
51297db96d56Sopenharmony_ci    assert(0 <= us && us <= 999999);
51307db96d56Sopenharmony_ci
51317db96d56Sopenharmony_ci    return datetime_from_timet_and_us(cls, f, secs, us, tzinfo);
51327db96d56Sopenharmony_ci}
51337db96d56Sopenharmony_ci
51347db96d56Sopenharmony_ci/*[clinic input]
51357db96d56Sopenharmony_ci
51367db96d56Sopenharmony_ci@classmethod
51377db96d56Sopenharmony_cidatetime.datetime.now
51387db96d56Sopenharmony_ci
51397db96d56Sopenharmony_ci    tz: object = None
51407db96d56Sopenharmony_ci        Timezone object.
51417db96d56Sopenharmony_ci
51427db96d56Sopenharmony_ciReturns new datetime object representing current time local to tz.
51437db96d56Sopenharmony_ci
51447db96d56Sopenharmony_ciIf no tz is specified, uses local timezone.
51457db96d56Sopenharmony_ci[clinic start generated code]*/
51467db96d56Sopenharmony_ci
51477db96d56Sopenharmony_cistatic PyObject *
51487db96d56Sopenharmony_cidatetime_datetime_now_impl(PyTypeObject *type, PyObject *tz)
51497db96d56Sopenharmony_ci/*[clinic end generated code: output=b3386e5345e2b47a input=80d09869c5267d00]*/
51507db96d56Sopenharmony_ci{
51517db96d56Sopenharmony_ci    PyObject *self;
51527db96d56Sopenharmony_ci
51537db96d56Sopenharmony_ci    /* Return best possible local time -- this isn't constrained by the
51547db96d56Sopenharmony_ci     * precision of a timestamp.
51557db96d56Sopenharmony_ci     */
51567db96d56Sopenharmony_ci    if (check_tzinfo_subclass(tz) < 0)
51577db96d56Sopenharmony_ci        return NULL;
51587db96d56Sopenharmony_ci
51597db96d56Sopenharmony_ci    self = datetime_best_possible((PyObject *)type,
51607db96d56Sopenharmony_ci                                  tz == Py_None ? _PyTime_localtime :
51617db96d56Sopenharmony_ci                                  _PyTime_gmtime,
51627db96d56Sopenharmony_ci                                  tz);
51637db96d56Sopenharmony_ci    if (self != NULL && tz != Py_None) {
51647db96d56Sopenharmony_ci        /* Convert UTC to tzinfo's zone. */
51657db96d56Sopenharmony_ci        self = _PyObject_CallMethodId(tz, &PyId_fromutc, "N", self);
51667db96d56Sopenharmony_ci    }
51677db96d56Sopenharmony_ci    return self;
51687db96d56Sopenharmony_ci}
51697db96d56Sopenharmony_ci
51707db96d56Sopenharmony_ci/* Return best possible UTC time -- this isn't constrained by the
51717db96d56Sopenharmony_ci * precision of a timestamp.
51727db96d56Sopenharmony_ci */
51737db96d56Sopenharmony_cistatic PyObject *
51747db96d56Sopenharmony_cidatetime_utcnow(PyObject *cls, PyObject *dummy)
51757db96d56Sopenharmony_ci{
51767db96d56Sopenharmony_ci    return datetime_best_possible(cls, _PyTime_gmtime, Py_None);
51777db96d56Sopenharmony_ci}
51787db96d56Sopenharmony_ci
51797db96d56Sopenharmony_ci/* Return new local datetime from timestamp (Python timestamp -- a double). */
51807db96d56Sopenharmony_cistatic PyObject *
51817db96d56Sopenharmony_cidatetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw)
51827db96d56Sopenharmony_ci{
51837db96d56Sopenharmony_ci    PyObject *self;
51847db96d56Sopenharmony_ci    PyObject *timestamp;
51857db96d56Sopenharmony_ci    PyObject *tzinfo = Py_None;
51867db96d56Sopenharmony_ci    static char *keywords[] = {"timestamp", "tz", NULL};
51877db96d56Sopenharmony_ci
51887db96d56Sopenharmony_ci    if (! PyArg_ParseTupleAndKeywords(args, kw, "O|O:fromtimestamp",
51897db96d56Sopenharmony_ci                                      keywords, &timestamp, &tzinfo))
51907db96d56Sopenharmony_ci        return NULL;
51917db96d56Sopenharmony_ci    if (check_tzinfo_subclass(tzinfo) < 0)
51927db96d56Sopenharmony_ci        return NULL;
51937db96d56Sopenharmony_ci
51947db96d56Sopenharmony_ci    self = datetime_from_timestamp(cls,
51957db96d56Sopenharmony_ci                                   tzinfo == Py_None ? _PyTime_localtime :
51967db96d56Sopenharmony_ci                                   _PyTime_gmtime,
51977db96d56Sopenharmony_ci                                   timestamp,
51987db96d56Sopenharmony_ci                                   tzinfo);
51997db96d56Sopenharmony_ci    if (self != NULL && tzinfo != Py_None) {
52007db96d56Sopenharmony_ci        /* Convert UTC to tzinfo's zone. */
52017db96d56Sopenharmony_ci        self = _PyObject_CallMethodId(tzinfo, &PyId_fromutc, "N", self);
52027db96d56Sopenharmony_ci    }
52037db96d56Sopenharmony_ci    return self;
52047db96d56Sopenharmony_ci}
52057db96d56Sopenharmony_ci
52067db96d56Sopenharmony_ci/* Return new UTC datetime from timestamp (Python timestamp -- a double). */
52077db96d56Sopenharmony_cistatic PyObject *
52087db96d56Sopenharmony_cidatetime_utcfromtimestamp(PyObject *cls, PyObject *args)
52097db96d56Sopenharmony_ci{
52107db96d56Sopenharmony_ci    PyObject *timestamp;
52117db96d56Sopenharmony_ci    PyObject *result = NULL;
52127db96d56Sopenharmony_ci
52137db96d56Sopenharmony_ci    if (PyArg_ParseTuple(args, "O:utcfromtimestamp", &timestamp))
52147db96d56Sopenharmony_ci        result = datetime_from_timestamp(cls, _PyTime_gmtime, timestamp,
52157db96d56Sopenharmony_ci                                         Py_None);
52167db96d56Sopenharmony_ci    return result;
52177db96d56Sopenharmony_ci}
52187db96d56Sopenharmony_ci
52197db96d56Sopenharmony_ci/* Return new datetime from _strptime.strptime_datetime(). */
52207db96d56Sopenharmony_cistatic PyObject *
52217db96d56Sopenharmony_cidatetime_strptime(PyObject *cls, PyObject *args)
52227db96d56Sopenharmony_ci{
52237db96d56Sopenharmony_ci    static PyObject *module = NULL;
52247db96d56Sopenharmony_ci    PyObject *string, *format;
52257db96d56Sopenharmony_ci    _Py_IDENTIFIER(_strptime_datetime);
52267db96d56Sopenharmony_ci
52277db96d56Sopenharmony_ci    if (!PyArg_ParseTuple(args, "UU:strptime", &string, &format))
52287db96d56Sopenharmony_ci        return NULL;
52297db96d56Sopenharmony_ci
52307db96d56Sopenharmony_ci    if (module == NULL) {
52317db96d56Sopenharmony_ci        module = PyImport_ImportModule("_strptime");
52327db96d56Sopenharmony_ci        if (module == NULL)
52337db96d56Sopenharmony_ci            return NULL;
52347db96d56Sopenharmony_ci    }
52357db96d56Sopenharmony_ci    return _PyObject_CallMethodIdObjArgs(module, &PyId__strptime_datetime,
52367db96d56Sopenharmony_ci                                         cls, string, format, NULL);
52377db96d56Sopenharmony_ci}
52387db96d56Sopenharmony_ci
52397db96d56Sopenharmony_ci/* Return new datetime from date/datetime and time arguments. */
52407db96d56Sopenharmony_cistatic PyObject *
52417db96d56Sopenharmony_cidatetime_combine(PyObject *cls, PyObject *args, PyObject *kw)
52427db96d56Sopenharmony_ci{
52437db96d56Sopenharmony_ci    static char *keywords[] = {"date", "time", "tzinfo", NULL};
52447db96d56Sopenharmony_ci    PyObject *date;
52457db96d56Sopenharmony_ci    PyObject *time;
52467db96d56Sopenharmony_ci    PyObject *tzinfo = NULL;
52477db96d56Sopenharmony_ci    PyObject *result = NULL;
52487db96d56Sopenharmony_ci
52497db96d56Sopenharmony_ci    if (PyArg_ParseTupleAndKeywords(args, kw, "O!O!|O:combine", keywords,
52507db96d56Sopenharmony_ci                                    &PyDateTime_DateType, &date,
52517db96d56Sopenharmony_ci                                    &PyDateTime_TimeType, &time, &tzinfo)) {
52527db96d56Sopenharmony_ci        if (tzinfo == NULL) {
52537db96d56Sopenharmony_ci            if (HASTZINFO(time))
52547db96d56Sopenharmony_ci                tzinfo = ((PyDateTime_Time *)time)->tzinfo;
52557db96d56Sopenharmony_ci            else
52567db96d56Sopenharmony_ci                tzinfo = Py_None;
52577db96d56Sopenharmony_ci        }
52587db96d56Sopenharmony_ci        result = new_datetime_subclass_fold_ex(GET_YEAR(date),
52597db96d56Sopenharmony_ci                                               GET_MONTH(date),
52607db96d56Sopenharmony_ci                                               GET_DAY(date),
52617db96d56Sopenharmony_ci                                               TIME_GET_HOUR(time),
52627db96d56Sopenharmony_ci                                               TIME_GET_MINUTE(time),
52637db96d56Sopenharmony_ci                                               TIME_GET_SECOND(time),
52647db96d56Sopenharmony_ci                                               TIME_GET_MICROSECOND(time),
52657db96d56Sopenharmony_ci                                               tzinfo,
52667db96d56Sopenharmony_ci                                               TIME_GET_FOLD(time),
52677db96d56Sopenharmony_ci                                               cls);
52687db96d56Sopenharmony_ci    }
52697db96d56Sopenharmony_ci    return result;
52707db96d56Sopenharmony_ci}
52717db96d56Sopenharmony_ci
52727db96d56Sopenharmony_cistatic PyObject *
52737db96d56Sopenharmony_ci_sanitize_isoformat_str(PyObject *dtstr)
52747db96d56Sopenharmony_ci{
52757db96d56Sopenharmony_ci    Py_ssize_t len = PyUnicode_GetLength(dtstr);
52767db96d56Sopenharmony_ci    if (len < 7) {  // All valid ISO 8601 strings are at least 7 characters long
52777db96d56Sopenharmony_ci        return NULL;
52787db96d56Sopenharmony_ci    }
52797db96d56Sopenharmony_ci
52807db96d56Sopenharmony_ci    // `fromisoformat` allows surrogate characters in exactly one position,
52817db96d56Sopenharmony_ci    // the separator; to allow datetime_fromisoformat to make the simplifying
52827db96d56Sopenharmony_ci    // assumption that all valid strings can be encoded in UTF-8, this function
52837db96d56Sopenharmony_ci    // replaces any surrogate character separators with `T`.
52847db96d56Sopenharmony_ci    //
52857db96d56Sopenharmony_ci    // The result of this, if not NULL, returns a new reference
52867db96d56Sopenharmony_ci    const void* const unicode_data = PyUnicode_DATA(dtstr);
52877db96d56Sopenharmony_ci    const unsigned int kind = PyUnicode_KIND(dtstr);
52887db96d56Sopenharmony_ci
52897db96d56Sopenharmony_ci    // Depending on the format of the string, the separator can only ever be
52907db96d56Sopenharmony_ci    // in positions 7, 8 or 10. We'll check each of these for a surrogate and
52917db96d56Sopenharmony_ci    // if we find one, replace it with `T`. If there is more than one surrogate,
52927db96d56Sopenharmony_ci    // we don't have to bother sanitizing it, because the function will later
52937db96d56Sopenharmony_ci    // fail when we try to encode the string as ASCII.
52947db96d56Sopenharmony_ci    static const size_t potential_separators[3] = {7, 8, 10};
52957db96d56Sopenharmony_ci    size_t surrogate_separator = 0;
52967db96d56Sopenharmony_ci    for(size_t idx = 0;
52977db96d56Sopenharmony_ci         idx < sizeof(potential_separators) / sizeof(*potential_separators);
52987db96d56Sopenharmony_ci         ++idx) {
52997db96d56Sopenharmony_ci        size_t pos = potential_separators[idx];
53007db96d56Sopenharmony_ci        if (pos > (size_t)len) {
53017db96d56Sopenharmony_ci            break;
53027db96d56Sopenharmony_ci        }
53037db96d56Sopenharmony_ci
53047db96d56Sopenharmony_ci        if(Py_UNICODE_IS_SURROGATE(PyUnicode_READ(kind, unicode_data, pos))) {
53057db96d56Sopenharmony_ci            surrogate_separator = pos;
53067db96d56Sopenharmony_ci            break;
53077db96d56Sopenharmony_ci        }
53087db96d56Sopenharmony_ci    }
53097db96d56Sopenharmony_ci
53107db96d56Sopenharmony_ci    if (surrogate_separator == 0) {
53117db96d56Sopenharmony_ci        Py_INCREF(dtstr);
53127db96d56Sopenharmony_ci        return dtstr;
53137db96d56Sopenharmony_ci    }
53147db96d56Sopenharmony_ci
53157db96d56Sopenharmony_ci    PyObject *str_out = _PyUnicode_Copy(dtstr);
53167db96d56Sopenharmony_ci    if (str_out == NULL) {
53177db96d56Sopenharmony_ci        return NULL;
53187db96d56Sopenharmony_ci    }
53197db96d56Sopenharmony_ci
53207db96d56Sopenharmony_ci    if (PyUnicode_WriteChar(str_out, surrogate_separator, (Py_UCS4)'T')) {
53217db96d56Sopenharmony_ci        Py_DECREF(str_out);
53227db96d56Sopenharmony_ci        return NULL;
53237db96d56Sopenharmony_ci    }
53247db96d56Sopenharmony_ci
53257db96d56Sopenharmony_ci    return str_out;
53267db96d56Sopenharmony_ci}
53277db96d56Sopenharmony_ci
53287db96d56Sopenharmony_ci
53297db96d56Sopenharmony_cistatic Py_ssize_t
53307db96d56Sopenharmony_ci_find_isoformat_datetime_separator(const char *dtstr, Py_ssize_t len) {
53317db96d56Sopenharmony_ci    // The valid date formats can all be distinguished by characters 4 and 5
53327db96d56Sopenharmony_ci    // and further narrowed down by character
53337db96d56Sopenharmony_ci    // which tells us where to look for the separator character.
53347db96d56Sopenharmony_ci    // Format    |  As-rendered |   Position
53357db96d56Sopenharmony_ci    // ---------------------------------------
53367db96d56Sopenharmony_ci    // %Y-%m-%d  |  YYYY-MM-DD  |    10
53377db96d56Sopenharmony_ci    // %Y%m%d    |  YYYYMMDD    |     8
53387db96d56Sopenharmony_ci    // %Y-W%V    |  YYYY-Www    |     8
53397db96d56Sopenharmony_ci    // %YW%V     |  YYYYWww     |     7
53407db96d56Sopenharmony_ci    // %Y-W%V-%u |  YYYY-Www-d  |    10
53417db96d56Sopenharmony_ci    // %YW%V%u   |  YYYYWwwd    |     8
53427db96d56Sopenharmony_ci    // %Y-%j     |  YYYY-DDD    |     8
53437db96d56Sopenharmony_ci    // %Y%j      |  YYYYDDD     |     7
53447db96d56Sopenharmony_ci    //
53457db96d56Sopenharmony_ci    // Note that because we allow *any* character for the separator, in the
53467db96d56Sopenharmony_ci    // case where character 4 is W, it's not straightforward to determine where
53477db96d56Sopenharmony_ci    // the separator is — in the case of YYYY-Www-d, you have actual ambiguity,
53487db96d56Sopenharmony_ci    // e.g. 2020-W01-0000 could be YYYY-Www-D0HH or YYYY-Www-HHMM, when the
53497db96d56Sopenharmony_ci    // separator character is a number in the former case or a hyphen in the
53507db96d56Sopenharmony_ci    // latter case.
53517db96d56Sopenharmony_ci    //
53527db96d56Sopenharmony_ci    // The case of YYYYWww can be distinguished from YYYYWwwd by tracking ahead
53537db96d56Sopenharmony_ci    // to either the end of the string or the first non-numeric character —
53547db96d56Sopenharmony_ci    // since the time components all come in pairs YYYYWww#HH can be
53557db96d56Sopenharmony_ci    // distinguished from YYYYWwwd#HH by the fact that there will always be an
53567db96d56Sopenharmony_ci    // odd number of digits before the first non-digit character in the former
53577db96d56Sopenharmony_ci    // case.
53587db96d56Sopenharmony_ci    static const char date_separator = '-';
53597db96d56Sopenharmony_ci    static const char week_indicator = 'W';
53607db96d56Sopenharmony_ci
53617db96d56Sopenharmony_ci    if (len == 7) {
53627db96d56Sopenharmony_ci        return 7;
53637db96d56Sopenharmony_ci    }
53647db96d56Sopenharmony_ci
53657db96d56Sopenharmony_ci    if (dtstr[4] == date_separator) {
53667db96d56Sopenharmony_ci        // YYYY-???
53677db96d56Sopenharmony_ci
53687db96d56Sopenharmony_ci        if (dtstr[5] == week_indicator) {
53697db96d56Sopenharmony_ci            // YYYY-W??
53707db96d56Sopenharmony_ci
53717db96d56Sopenharmony_ci            if (len < 8) {
53727db96d56Sopenharmony_ci                return -1;
53737db96d56Sopenharmony_ci            }
53747db96d56Sopenharmony_ci
53757db96d56Sopenharmony_ci            if (len > 8 && dtstr[8] == date_separator) {
53767db96d56Sopenharmony_ci                // YYYY-Www-D (10) or YYYY-Www-HH (8)
53777db96d56Sopenharmony_ci                if (len == 9) { return -1; }
53787db96d56Sopenharmony_ci                if (len > 10 && is_digit(dtstr[10])) {
53797db96d56Sopenharmony_ci                    // This is as far as we'll try to go to resolve the
53807db96d56Sopenharmony_ci                    // ambiguity for the moment — if we have YYYY-Www-##, the
53817db96d56Sopenharmony_ci                    // separator is either a hyphen at 8 or a number at 10.
53827db96d56Sopenharmony_ci                    //
53837db96d56Sopenharmony_ci                    // We'll assume it's a hyphen at 8 because it's way more
53847db96d56Sopenharmony_ci                    // likely that someone will use a hyphen as a separator
53857db96d56Sopenharmony_ci                    // than a number, but at this point it's really best effort
53867db96d56Sopenharmony_ci                    // because this is an extension of the spec anyway.
53877db96d56Sopenharmony_ci                    return 8;
53887db96d56Sopenharmony_ci                }
53897db96d56Sopenharmony_ci
53907db96d56Sopenharmony_ci                return 10;
53917db96d56Sopenharmony_ci            } else {
53927db96d56Sopenharmony_ci                // YYYY-Www (8)
53937db96d56Sopenharmony_ci                return 8;
53947db96d56Sopenharmony_ci            }
53957db96d56Sopenharmony_ci        } else {
53967db96d56Sopenharmony_ci            // YYYY-MM-DD (10)
53977db96d56Sopenharmony_ci            return 10;
53987db96d56Sopenharmony_ci        }
53997db96d56Sopenharmony_ci    } else {
54007db96d56Sopenharmony_ci        // YYYY???
54017db96d56Sopenharmony_ci        if (dtstr[4] == week_indicator) {
54027db96d56Sopenharmony_ci            // YYYYWww (7) or YYYYWwwd (8)
54037db96d56Sopenharmony_ci            size_t idx = 7;
54047db96d56Sopenharmony_ci            for (; idx < (size_t)len; ++idx) {
54057db96d56Sopenharmony_ci                // Keep going until we run out of digits.
54067db96d56Sopenharmony_ci                if (!is_digit(dtstr[idx])) {
54077db96d56Sopenharmony_ci                    break;
54087db96d56Sopenharmony_ci                }
54097db96d56Sopenharmony_ci            }
54107db96d56Sopenharmony_ci
54117db96d56Sopenharmony_ci            if (idx < 9) {
54127db96d56Sopenharmony_ci                return idx;
54137db96d56Sopenharmony_ci            }
54147db96d56Sopenharmony_ci
54157db96d56Sopenharmony_ci            if (idx % 2 == 0) {
54167db96d56Sopenharmony_ci                // If the index of the last number is even, it's YYYYWww
54177db96d56Sopenharmony_ci                return 7;
54187db96d56Sopenharmony_ci            } else {
54197db96d56Sopenharmony_ci                return 8;
54207db96d56Sopenharmony_ci            }
54217db96d56Sopenharmony_ci        } else {
54227db96d56Sopenharmony_ci            // YYYYMMDD (8)
54237db96d56Sopenharmony_ci            return 8;
54247db96d56Sopenharmony_ci        }
54257db96d56Sopenharmony_ci    }
54267db96d56Sopenharmony_ci}
54277db96d56Sopenharmony_ci
54287db96d56Sopenharmony_cistatic PyObject *
54297db96d56Sopenharmony_cidatetime_fromisoformat(PyObject *cls, PyObject *dtstr)
54307db96d56Sopenharmony_ci{
54317db96d56Sopenharmony_ci    assert(dtstr != NULL);
54327db96d56Sopenharmony_ci
54337db96d56Sopenharmony_ci    if (!PyUnicode_Check(dtstr)) {
54347db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
54357db96d56Sopenharmony_ci                        "fromisoformat: argument must be str");
54367db96d56Sopenharmony_ci        return NULL;
54377db96d56Sopenharmony_ci    }
54387db96d56Sopenharmony_ci
54397db96d56Sopenharmony_ci    // We only need to sanitize this string if the separator is a surrogate
54407db96d56Sopenharmony_ci    // character. In the situation where the separator location is ambiguous,
54417db96d56Sopenharmony_ci    // we don't have to sanitize it anything because that can only happen when
54427db96d56Sopenharmony_ci    // the separator is either '-' or a number. This should mostly be a noop
54437db96d56Sopenharmony_ci    // but it makes the reference counting easier if we still sanitize.
54447db96d56Sopenharmony_ci    PyObject *dtstr_clean = _sanitize_isoformat_str(dtstr);
54457db96d56Sopenharmony_ci    if (dtstr_clean == NULL) {
54467db96d56Sopenharmony_ci        goto invalid_string_error;
54477db96d56Sopenharmony_ci    }
54487db96d56Sopenharmony_ci
54497db96d56Sopenharmony_ci    Py_ssize_t len;
54507db96d56Sopenharmony_ci    const char *dt_ptr = PyUnicode_AsUTF8AndSize(dtstr_clean, &len);
54517db96d56Sopenharmony_ci
54527db96d56Sopenharmony_ci    if (dt_ptr == NULL) {
54537db96d56Sopenharmony_ci        if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
54547db96d56Sopenharmony_ci            // Encoding errors are invalid string errors at this point
54557db96d56Sopenharmony_ci            goto invalid_string_error;
54567db96d56Sopenharmony_ci        }
54577db96d56Sopenharmony_ci        else {
54587db96d56Sopenharmony_ci            goto error;
54597db96d56Sopenharmony_ci        }
54607db96d56Sopenharmony_ci    }
54617db96d56Sopenharmony_ci
54627db96d56Sopenharmony_ci    const Py_ssize_t separator_location = _find_isoformat_datetime_separator(
54637db96d56Sopenharmony_ci            dt_ptr, len);
54647db96d56Sopenharmony_ci
54657db96d56Sopenharmony_ci
54667db96d56Sopenharmony_ci    const char *p = dt_ptr;
54677db96d56Sopenharmony_ci
54687db96d56Sopenharmony_ci    int year = 0, month = 0, day = 0;
54697db96d56Sopenharmony_ci    int hour = 0, minute = 0, second = 0, microsecond = 0;
54707db96d56Sopenharmony_ci    int tzoffset = 0, tzusec = 0;
54717db96d56Sopenharmony_ci
54727db96d56Sopenharmony_ci    // date runs up to separator_location
54737db96d56Sopenharmony_ci    int rv = parse_isoformat_date(p, separator_location, &year, &month, &day);
54747db96d56Sopenharmony_ci
54757db96d56Sopenharmony_ci    if (!rv && len > separator_location) {
54767db96d56Sopenharmony_ci        // In UTF-8, the length of multi-byte characters is encoded in the MSB
54777db96d56Sopenharmony_ci        p += separator_location;
54787db96d56Sopenharmony_ci        if ((p[0] & 0x80) == 0) {
54797db96d56Sopenharmony_ci            p += 1;
54807db96d56Sopenharmony_ci        }
54817db96d56Sopenharmony_ci        else {
54827db96d56Sopenharmony_ci            switch (p[0] & 0xf0) {
54837db96d56Sopenharmony_ci                case 0xe0:
54847db96d56Sopenharmony_ci                    p += 3;
54857db96d56Sopenharmony_ci                    break;
54867db96d56Sopenharmony_ci                case 0xf0:
54877db96d56Sopenharmony_ci                    p += 4;
54887db96d56Sopenharmony_ci                    break;
54897db96d56Sopenharmony_ci                default:
54907db96d56Sopenharmony_ci                    p += 2;
54917db96d56Sopenharmony_ci                    break;
54927db96d56Sopenharmony_ci            }
54937db96d56Sopenharmony_ci        }
54947db96d56Sopenharmony_ci
54957db96d56Sopenharmony_ci        len -= (p - dt_ptr);
54967db96d56Sopenharmony_ci        rv = parse_isoformat_time(p, len, &hour, &minute, &second,
54977db96d56Sopenharmony_ci                                  &microsecond, &tzoffset, &tzusec);
54987db96d56Sopenharmony_ci    }
54997db96d56Sopenharmony_ci    if (rv < 0) {
55007db96d56Sopenharmony_ci        goto invalid_string_error;
55017db96d56Sopenharmony_ci    }
55027db96d56Sopenharmony_ci
55037db96d56Sopenharmony_ci    PyObject *tzinfo = tzinfo_from_isoformat_results(rv, tzoffset, tzusec);
55047db96d56Sopenharmony_ci    if (tzinfo == NULL) {
55057db96d56Sopenharmony_ci        goto error;
55067db96d56Sopenharmony_ci    }
55077db96d56Sopenharmony_ci
55087db96d56Sopenharmony_ci    PyObject *dt = new_datetime_subclass_ex(year, month, day, hour, minute,
55097db96d56Sopenharmony_ci                                            second, microsecond, tzinfo, cls);
55107db96d56Sopenharmony_ci
55117db96d56Sopenharmony_ci    Py_DECREF(tzinfo);
55127db96d56Sopenharmony_ci    Py_DECREF(dtstr_clean);
55137db96d56Sopenharmony_ci    return dt;
55147db96d56Sopenharmony_ci
55157db96d56Sopenharmony_ciinvalid_string_error:
55167db96d56Sopenharmony_ci    PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", dtstr);
55177db96d56Sopenharmony_ci
55187db96d56Sopenharmony_cierror:
55197db96d56Sopenharmony_ci    Py_XDECREF(dtstr_clean);
55207db96d56Sopenharmony_ci
55217db96d56Sopenharmony_ci    return NULL;
55227db96d56Sopenharmony_ci}
55237db96d56Sopenharmony_ci
55247db96d56Sopenharmony_ci/*
55257db96d56Sopenharmony_ci * Destructor.
55267db96d56Sopenharmony_ci */
55277db96d56Sopenharmony_ci
55287db96d56Sopenharmony_cistatic void
55297db96d56Sopenharmony_cidatetime_dealloc(PyDateTime_DateTime *self)
55307db96d56Sopenharmony_ci{
55317db96d56Sopenharmony_ci    if (HASTZINFO(self)) {
55327db96d56Sopenharmony_ci        Py_XDECREF(self->tzinfo);
55337db96d56Sopenharmony_ci    }
55347db96d56Sopenharmony_ci    Py_TYPE(self)->tp_free((PyObject *)self);
55357db96d56Sopenharmony_ci}
55367db96d56Sopenharmony_ci
55377db96d56Sopenharmony_ci/*
55387db96d56Sopenharmony_ci * Indirect access to tzinfo methods.
55397db96d56Sopenharmony_ci */
55407db96d56Sopenharmony_ci
55417db96d56Sopenharmony_ci/* These are all METH_NOARGS, so don't need to check the arglist. */
55427db96d56Sopenharmony_cistatic PyObject *
55437db96d56Sopenharmony_cidatetime_utcoffset(PyObject *self, PyObject *unused) {
55447db96d56Sopenharmony_ci    return call_utcoffset(GET_DT_TZINFO(self), self);
55457db96d56Sopenharmony_ci}
55467db96d56Sopenharmony_ci
55477db96d56Sopenharmony_cistatic PyObject *
55487db96d56Sopenharmony_cidatetime_dst(PyObject *self, PyObject *unused) {
55497db96d56Sopenharmony_ci    return call_dst(GET_DT_TZINFO(self), self);
55507db96d56Sopenharmony_ci}
55517db96d56Sopenharmony_ci
55527db96d56Sopenharmony_cistatic PyObject *
55537db96d56Sopenharmony_cidatetime_tzname(PyObject *self, PyObject *unused) {
55547db96d56Sopenharmony_ci    return call_tzname(GET_DT_TZINFO(self), self);
55557db96d56Sopenharmony_ci}
55567db96d56Sopenharmony_ci
55577db96d56Sopenharmony_ci/*
55587db96d56Sopenharmony_ci * datetime arithmetic.
55597db96d56Sopenharmony_ci */
55607db96d56Sopenharmony_ci
55617db96d56Sopenharmony_ci/* factor must be 1 (to add) or -1 (to subtract).  The result inherits
55627db96d56Sopenharmony_ci * the tzinfo state of date.
55637db96d56Sopenharmony_ci */
55647db96d56Sopenharmony_cistatic PyObject *
55657db96d56Sopenharmony_ciadd_datetime_timedelta(PyDateTime_DateTime *date, PyDateTime_Delta *delta,
55667db96d56Sopenharmony_ci                       int factor)
55677db96d56Sopenharmony_ci{
55687db96d56Sopenharmony_ci    /* Note that the C-level additions can't overflow, because of
55697db96d56Sopenharmony_ci     * invariant bounds on the member values.
55707db96d56Sopenharmony_ci     */
55717db96d56Sopenharmony_ci    int year = GET_YEAR(date);
55727db96d56Sopenharmony_ci    int month = GET_MONTH(date);
55737db96d56Sopenharmony_ci    int day = GET_DAY(date) + GET_TD_DAYS(delta) * factor;
55747db96d56Sopenharmony_ci    int hour = DATE_GET_HOUR(date);
55757db96d56Sopenharmony_ci    int minute = DATE_GET_MINUTE(date);
55767db96d56Sopenharmony_ci    int second = DATE_GET_SECOND(date) + GET_TD_SECONDS(delta) * factor;
55777db96d56Sopenharmony_ci    int microsecond = DATE_GET_MICROSECOND(date) +
55787db96d56Sopenharmony_ci                      GET_TD_MICROSECONDS(delta) * factor;
55797db96d56Sopenharmony_ci
55807db96d56Sopenharmony_ci    assert(factor == 1 || factor == -1);
55817db96d56Sopenharmony_ci    if (normalize_datetime(&year, &month, &day,
55827db96d56Sopenharmony_ci                           &hour, &minute, &second, &microsecond) < 0) {
55837db96d56Sopenharmony_ci        return NULL;
55847db96d56Sopenharmony_ci    }
55857db96d56Sopenharmony_ci
55867db96d56Sopenharmony_ci    return new_datetime_subclass_ex(year, month, day,
55877db96d56Sopenharmony_ci                                    hour, minute, second, microsecond,
55887db96d56Sopenharmony_ci                                    HASTZINFO(date) ? date->tzinfo : Py_None,
55897db96d56Sopenharmony_ci                                    (PyObject *)Py_TYPE(date));
55907db96d56Sopenharmony_ci}
55917db96d56Sopenharmony_ci
55927db96d56Sopenharmony_cistatic PyObject *
55937db96d56Sopenharmony_cidatetime_add(PyObject *left, PyObject *right)
55947db96d56Sopenharmony_ci{
55957db96d56Sopenharmony_ci    if (PyDateTime_Check(left)) {
55967db96d56Sopenharmony_ci        /* datetime + ??? */
55977db96d56Sopenharmony_ci        if (PyDelta_Check(right))
55987db96d56Sopenharmony_ci            /* datetime + delta */
55997db96d56Sopenharmony_ci            return add_datetime_timedelta(
56007db96d56Sopenharmony_ci                            (PyDateTime_DateTime *)left,
56017db96d56Sopenharmony_ci                            (PyDateTime_Delta *)right,
56027db96d56Sopenharmony_ci                            1);
56037db96d56Sopenharmony_ci    }
56047db96d56Sopenharmony_ci    else if (PyDelta_Check(left)) {
56057db96d56Sopenharmony_ci        /* delta + datetime */
56067db96d56Sopenharmony_ci        return add_datetime_timedelta((PyDateTime_DateTime *) right,
56077db96d56Sopenharmony_ci                                      (PyDateTime_Delta *) left,
56087db96d56Sopenharmony_ci                                      1);
56097db96d56Sopenharmony_ci    }
56107db96d56Sopenharmony_ci    Py_RETURN_NOTIMPLEMENTED;
56117db96d56Sopenharmony_ci}
56127db96d56Sopenharmony_ci
56137db96d56Sopenharmony_cistatic PyObject *
56147db96d56Sopenharmony_cidatetime_subtract(PyObject *left, PyObject *right)
56157db96d56Sopenharmony_ci{
56167db96d56Sopenharmony_ci    PyObject *result = Py_NotImplemented;
56177db96d56Sopenharmony_ci
56187db96d56Sopenharmony_ci    if (PyDateTime_Check(left)) {
56197db96d56Sopenharmony_ci        /* datetime - ??? */
56207db96d56Sopenharmony_ci        if (PyDateTime_Check(right)) {
56217db96d56Sopenharmony_ci            /* datetime - datetime */
56227db96d56Sopenharmony_ci            PyObject *offset1, *offset2, *offdiff = NULL;
56237db96d56Sopenharmony_ci            int delta_d, delta_s, delta_us;
56247db96d56Sopenharmony_ci
56257db96d56Sopenharmony_ci            if (GET_DT_TZINFO(left) == GET_DT_TZINFO(right)) {
56267db96d56Sopenharmony_ci                offset2 = offset1 = Py_None;
56277db96d56Sopenharmony_ci                Py_INCREF(offset1);
56287db96d56Sopenharmony_ci                Py_INCREF(offset2);
56297db96d56Sopenharmony_ci            }
56307db96d56Sopenharmony_ci            else {
56317db96d56Sopenharmony_ci                offset1 = datetime_utcoffset(left, NULL);
56327db96d56Sopenharmony_ci                if (offset1 == NULL)
56337db96d56Sopenharmony_ci                    return NULL;
56347db96d56Sopenharmony_ci                offset2 = datetime_utcoffset(right, NULL);
56357db96d56Sopenharmony_ci                if (offset2 == NULL) {
56367db96d56Sopenharmony_ci                    Py_DECREF(offset1);
56377db96d56Sopenharmony_ci                    return NULL;
56387db96d56Sopenharmony_ci                }
56397db96d56Sopenharmony_ci                if ((offset1 != Py_None) != (offset2 != Py_None)) {
56407db96d56Sopenharmony_ci                    PyErr_SetString(PyExc_TypeError,
56417db96d56Sopenharmony_ci                                    "can't subtract offset-naive and "
56427db96d56Sopenharmony_ci                                    "offset-aware datetimes");
56437db96d56Sopenharmony_ci                    Py_DECREF(offset1);
56447db96d56Sopenharmony_ci                    Py_DECREF(offset2);
56457db96d56Sopenharmony_ci                    return NULL;
56467db96d56Sopenharmony_ci                }
56477db96d56Sopenharmony_ci            }
56487db96d56Sopenharmony_ci            if ((offset1 != offset2) &&
56497db96d56Sopenharmony_ci                delta_cmp(offset1, offset2) != 0) {
56507db96d56Sopenharmony_ci                offdiff = delta_subtract(offset1, offset2);
56517db96d56Sopenharmony_ci                if (offdiff == NULL) {
56527db96d56Sopenharmony_ci                    Py_DECREF(offset1);
56537db96d56Sopenharmony_ci                    Py_DECREF(offset2);
56547db96d56Sopenharmony_ci                    return NULL;
56557db96d56Sopenharmony_ci                }
56567db96d56Sopenharmony_ci            }
56577db96d56Sopenharmony_ci            Py_DECREF(offset1);
56587db96d56Sopenharmony_ci            Py_DECREF(offset2);
56597db96d56Sopenharmony_ci            delta_d = ymd_to_ord(GET_YEAR(left),
56607db96d56Sopenharmony_ci                                 GET_MONTH(left),
56617db96d56Sopenharmony_ci                                 GET_DAY(left)) -
56627db96d56Sopenharmony_ci                      ymd_to_ord(GET_YEAR(right),
56637db96d56Sopenharmony_ci                                 GET_MONTH(right),
56647db96d56Sopenharmony_ci                                 GET_DAY(right));
56657db96d56Sopenharmony_ci            /* These can't overflow, since the values are
56667db96d56Sopenharmony_ci             * normalized.  At most this gives the number of
56677db96d56Sopenharmony_ci             * seconds in one day.
56687db96d56Sopenharmony_ci             */
56697db96d56Sopenharmony_ci            delta_s = (DATE_GET_HOUR(left) -
56707db96d56Sopenharmony_ci                       DATE_GET_HOUR(right)) * 3600 +
56717db96d56Sopenharmony_ci                      (DATE_GET_MINUTE(left) -
56727db96d56Sopenharmony_ci                       DATE_GET_MINUTE(right)) * 60 +
56737db96d56Sopenharmony_ci                      (DATE_GET_SECOND(left) -
56747db96d56Sopenharmony_ci                       DATE_GET_SECOND(right));
56757db96d56Sopenharmony_ci            delta_us = DATE_GET_MICROSECOND(left) -
56767db96d56Sopenharmony_ci                       DATE_GET_MICROSECOND(right);
56777db96d56Sopenharmony_ci            result = new_delta(delta_d, delta_s, delta_us, 1);
56787db96d56Sopenharmony_ci            if (result == NULL)
56797db96d56Sopenharmony_ci                return NULL;
56807db96d56Sopenharmony_ci
56817db96d56Sopenharmony_ci            if (offdiff != NULL) {
56827db96d56Sopenharmony_ci                Py_SETREF(result, delta_subtract(result, offdiff));
56837db96d56Sopenharmony_ci                Py_DECREF(offdiff);
56847db96d56Sopenharmony_ci            }
56857db96d56Sopenharmony_ci        }
56867db96d56Sopenharmony_ci        else if (PyDelta_Check(right)) {
56877db96d56Sopenharmony_ci            /* datetime - delta */
56887db96d56Sopenharmony_ci            result = add_datetime_timedelta(
56897db96d56Sopenharmony_ci                            (PyDateTime_DateTime *)left,
56907db96d56Sopenharmony_ci                            (PyDateTime_Delta *)right,
56917db96d56Sopenharmony_ci                            -1);
56927db96d56Sopenharmony_ci        }
56937db96d56Sopenharmony_ci    }
56947db96d56Sopenharmony_ci
56957db96d56Sopenharmony_ci    if (result == Py_NotImplemented)
56967db96d56Sopenharmony_ci        Py_INCREF(result);
56977db96d56Sopenharmony_ci    return result;
56987db96d56Sopenharmony_ci}
56997db96d56Sopenharmony_ci
57007db96d56Sopenharmony_ci/* Various ways to turn a datetime into a string. */
57017db96d56Sopenharmony_ci
57027db96d56Sopenharmony_cistatic PyObject *
57037db96d56Sopenharmony_cidatetime_repr(PyDateTime_DateTime *self)
57047db96d56Sopenharmony_ci{
57057db96d56Sopenharmony_ci    const char *type_name = Py_TYPE(self)->tp_name;
57067db96d56Sopenharmony_ci    PyObject *baserepr;
57077db96d56Sopenharmony_ci
57087db96d56Sopenharmony_ci    if (DATE_GET_MICROSECOND(self)) {
57097db96d56Sopenharmony_ci        baserepr = PyUnicode_FromFormat(
57107db96d56Sopenharmony_ci                      "%s(%d, %d, %d, %d, %d, %d, %d)",
57117db96d56Sopenharmony_ci                      type_name,
57127db96d56Sopenharmony_ci                      GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
57137db96d56Sopenharmony_ci                      DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
57147db96d56Sopenharmony_ci                      DATE_GET_SECOND(self),
57157db96d56Sopenharmony_ci                      DATE_GET_MICROSECOND(self));
57167db96d56Sopenharmony_ci    }
57177db96d56Sopenharmony_ci    else if (DATE_GET_SECOND(self)) {
57187db96d56Sopenharmony_ci        baserepr = PyUnicode_FromFormat(
57197db96d56Sopenharmony_ci                      "%s(%d, %d, %d, %d, %d, %d)",
57207db96d56Sopenharmony_ci                      type_name,
57217db96d56Sopenharmony_ci                      GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
57227db96d56Sopenharmony_ci                      DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
57237db96d56Sopenharmony_ci                      DATE_GET_SECOND(self));
57247db96d56Sopenharmony_ci    }
57257db96d56Sopenharmony_ci    else {
57267db96d56Sopenharmony_ci        baserepr = PyUnicode_FromFormat(
57277db96d56Sopenharmony_ci                      "%s(%d, %d, %d, %d, %d)",
57287db96d56Sopenharmony_ci                      type_name,
57297db96d56Sopenharmony_ci                      GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
57307db96d56Sopenharmony_ci                      DATE_GET_HOUR(self), DATE_GET_MINUTE(self));
57317db96d56Sopenharmony_ci    }
57327db96d56Sopenharmony_ci    if (baserepr != NULL && DATE_GET_FOLD(self) != 0)
57337db96d56Sopenharmony_ci        baserepr = append_keyword_fold(baserepr, DATE_GET_FOLD(self));
57347db96d56Sopenharmony_ci    if (baserepr == NULL || ! HASTZINFO(self))
57357db96d56Sopenharmony_ci        return baserepr;
57367db96d56Sopenharmony_ci    return append_keyword_tzinfo(baserepr, self->tzinfo);
57377db96d56Sopenharmony_ci}
57387db96d56Sopenharmony_ci
57397db96d56Sopenharmony_cistatic PyObject *
57407db96d56Sopenharmony_cidatetime_str(PyDateTime_DateTime *self)
57417db96d56Sopenharmony_ci{
57427db96d56Sopenharmony_ci    return _PyObject_CallMethodId((PyObject *)self, &PyId_isoformat, "s", " ");
57437db96d56Sopenharmony_ci}
57447db96d56Sopenharmony_ci
57457db96d56Sopenharmony_cistatic PyObject *
57467db96d56Sopenharmony_cidatetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
57477db96d56Sopenharmony_ci{
57487db96d56Sopenharmony_ci    int sep = 'T';
57497db96d56Sopenharmony_ci    char *timespec = NULL;
57507db96d56Sopenharmony_ci    static char *keywords[] = {"sep", "timespec", NULL};
57517db96d56Sopenharmony_ci    char buffer[100];
57527db96d56Sopenharmony_ci    PyObject *result = NULL;
57537db96d56Sopenharmony_ci    int us = DATE_GET_MICROSECOND(self);
57547db96d56Sopenharmony_ci    static const char *specs[][2] = {
57557db96d56Sopenharmony_ci        {"hours", "%04d-%02d-%02d%c%02d"},
57567db96d56Sopenharmony_ci        {"minutes", "%04d-%02d-%02d%c%02d:%02d"},
57577db96d56Sopenharmony_ci        {"seconds", "%04d-%02d-%02d%c%02d:%02d:%02d"},
57587db96d56Sopenharmony_ci        {"milliseconds", "%04d-%02d-%02d%c%02d:%02d:%02d.%03d"},
57597db96d56Sopenharmony_ci        {"microseconds", "%04d-%02d-%02d%c%02d:%02d:%02d.%06d"},
57607db96d56Sopenharmony_ci    };
57617db96d56Sopenharmony_ci    size_t given_spec;
57627db96d56Sopenharmony_ci
57637db96d56Sopenharmony_ci    if (!PyArg_ParseTupleAndKeywords(args, kw, "|Cs:isoformat", keywords, &sep, &timespec))
57647db96d56Sopenharmony_ci        return NULL;
57657db96d56Sopenharmony_ci
57667db96d56Sopenharmony_ci    if (timespec == NULL || strcmp(timespec, "auto") == 0) {
57677db96d56Sopenharmony_ci        if (us == 0) {
57687db96d56Sopenharmony_ci            /* seconds */
57697db96d56Sopenharmony_ci            given_spec = 2;
57707db96d56Sopenharmony_ci        }
57717db96d56Sopenharmony_ci        else {
57727db96d56Sopenharmony_ci            /* microseconds */
57737db96d56Sopenharmony_ci            given_spec = 4;
57747db96d56Sopenharmony_ci        }
57757db96d56Sopenharmony_ci    }
57767db96d56Sopenharmony_ci    else {
57777db96d56Sopenharmony_ci        for (given_spec = 0; given_spec < Py_ARRAY_LENGTH(specs); given_spec++) {
57787db96d56Sopenharmony_ci            if (strcmp(timespec, specs[given_spec][0]) == 0) {
57797db96d56Sopenharmony_ci                if (given_spec == 3) {
57807db96d56Sopenharmony_ci                    us = us / 1000;
57817db96d56Sopenharmony_ci                }
57827db96d56Sopenharmony_ci                break;
57837db96d56Sopenharmony_ci            }
57847db96d56Sopenharmony_ci        }
57857db96d56Sopenharmony_ci    }
57867db96d56Sopenharmony_ci
57877db96d56Sopenharmony_ci    if (given_spec == Py_ARRAY_LENGTH(specs)) {
57887db96d56Sopenharmony_ci        PyErr_Format(PyExc_ValueError, "Unknown timespec value");
57897db96d56Sopenharmony_ci        return NULL;
57907db96d56Sopenharmony_ci    }
57917db96d56Sopenharmony_ci    else {
57927db96d56Sopenharmony_ci        result = PyUnicode_FromFormat(specs[given_spec][1],
57937db96d56Sopenharmony_ci                                      GET_YEAR(self), GET_MONTH(self),
57947db96d56Sopenharmony_ci                                      GET_DAY(self), (int)sep,
57957db96d56Sopenharmony_ci                                      DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
57967db96d56Sopenharmony_ci                                      DATE_GET_SECOND(self), us);
57977db96d56Sopenharmony_ci    }
57987db96d56Sopenharmony_ci
57997db96d56Sopenharmony_ci    if (!result || !HASTZINFO(self))
58007db96d56Sopenharmony_ci        return result;
58017db96d56Sopenharmony_ci
58027db96d56Sopenharmony_ci    /* We need to append the UTC offset. */
58037db96d56Sopenharmony_ci    if (format_utcoffset(buffer, sizeof(buffer), ":", self->tzinfo,
58047db96d56Sopenharmony_ci                         (PyObject *)self) < 0) {
58057db96d56Sopenharmony_ci        Py_DECREF(result);
58067db96d56Sopenharmony_ci        return NULL;
58077db96d56Sopenharmony_ci    }
58087db96d56Sopenharmony_ci    PyUnicode_AppendAndDel(&result, PyUnicode_FromString(buffer));
58097db96d56Sopenharmony_ci    return result;
58107db96d56Sopenharmony_ci}
58117db96d56Sopenharmony_ci
58127db96d56Sopenharmony_cistatic PyObject *
58137db96d56Sopenharmony_cidatetime_ctime(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
58147db96d56Sopenharmony_ci{
58157db96d56Sopenharmony_ci    return format_ctime((PyDateTime_Date *)self,
58167db96d56Sopenharmony_ci                        DATE_GET_HOUR(self),
58177db96d56Sopenharmony_ci                        DATE_GET_MINUTE(self),
58187db96d56Sopenharmony_ci                        DATE_GET_SECOND(self));
58197db96d56Sopenharmony_ci}
58207db96d56Sopenharmony_ci
58217db96d56Sopenharmony_ci/* Miscellaneous methods. */
58227db96d56Sopenharmony_ci
58237db96d56Sopenharmony_cistatic PyObject *
58247db96d56Sopenharmony_ciflip_fold(PyObject *dt)
58257db96d56Sopenharmony_ci{
58267db96d56Sopenharmony_ci    return new_datetime_ex2(GET_YEAR(dt),
58277db96d56Sopenharmony_ci                            GET_MONTH(dt),
58287db96d56Sopenharmony_ci                            GET_DAY(dt),
58297db96d56Sopenharmony_ci                            DATE_GET_HOUR(dt),
58307db96d56Sopenharmony_ci                            DATE_GET_MINUTE(dt),
58317db96d56Sopenharmony_ci                            DATE_GET_SECOND(dt),
58327db96d56Sopenharmony_ci                            DATE_GET_MICROSECOND(dt),
58337db96d56Sopenharmony_ci                            HASTZINFO(dt) ?
58347db96d56Sopenharmony_ci                             ((PyDateTime_DateTime *)dt)->tzinfo : Py_None,
58357db96d56Sopenharmony_ci                            !DATE_GET_FOLD(dt),
58367db96d56Sopenharmony_ci                            Py_TYPE(dt));
58377db96d56Sopenharmony_ci}
58387db96d56Sopenharmony_ci
58397db96d56Sopenharmony_cistatic PyObject *
58407db96d56Sopenharmony_ciget_flip_fold_offset(PyObject *dt)
58417db96d56Sopenharmony_ci{
58427db96d56Sopenharmony_ci    PyObject *result, *flip_dt;
58437db96d56Sopenharmony_ci
58447db96d56Sopenharmony_ci    flip_dt = flip_fold(dt);
58457db96d56Sopenharmony_ci    if (flip_dt == NULL)
58467db96d56Sopenharmony_ci        return NULL;
58477db96d56Sopenharmony_ci    result = datetime_utcoffset(flip_dt, NULL);
58487db96d56Sopenharmony_ci    Py_DECREF(flip_dt);
58497db96d56Sopenharmony_ci    return result;
58507db96d56Sopenharmony_ci}
58517db96d56Sopenharmony_ci
58527db96d56Sopenharmony_ci/* PEP 495 exception: Whenever one or both of the operands in
58537db96d56Sopenharmony_ci * inter-zone comparison is such that its utcoffset() depends
58547db96d56Sopenharmony_ci * on the value of its fold attribute, the result is False.
58557db96d56Sopenharmony_ci *
58567db96d56Sopenharmony_ci * Return 1 if exception applies, 0 if not,  and -1 on error.
58577db96d56Sopenharmony_ci */
58587db96d56Sopenharmony_cistatic int
58597db96d56Sopenharmony_cipep495_eq_exception(PyObject *self, PyObject *other,
58607db96d56Sopenharmony_ci                    PyObject *offset_self, PyObject *offset_other)
58617db96d56Sopenharmony_ci{
58627db96d56Sopenharmony_ci    int result = 0;
58637db96d56Sopenharmony_ci    PyObject *flip_offset;
58647db96d56Sopenharmony_ci
58657db96d56Sopenharmony_ci    flip_offset = get_flip_fold_offset(self);
58667db96d56Sopenharmony_ci    if (flip_offset == NULL)
58677db96d56Sopenharmony_ci        return -1;
58687db96d56Sopenharmony_ci    if (flip_offset != offset_self &&
58697db96d56Sopenharmony_ci        delta_cmp(flip_offset, offset_self))
58707db96d56Sopenharmony_ci    {
58717db96d56Sopenharmony_ci        result = 1;
58727db96d56Sopenharmony_ci        goto done;
58737db96d56Sopenharmony_ci    }
58747db96d56Sopenharmony_ci    Py_DECREF(flip_offset);
58757db96d56Sopenharmony_ci
58767db96d56Sopenharmony_ci    flip_offset = get_flip_fold_offset(other);
58777db96d56Sopenharmony_ci    if (flip_offset == NULL)
58787db96d56Sopenharmony_ci        return -1;
58797db96d56Sopenharmony_ci    if (flip_offset != offset_other &&
58807db96d56Sopenharmony_ci        delta_cmp(flip_offset, offset_other))
58817db96d56Sopenharmony_ci        result = 1;
58827db96d56Sopenharmony_ci done:
58837db96d56Sopenharmony_ci    Py_DECREF(flip_offset);
58847db96d56Sopenharmony_ci    return result;
58857db96d56Sopenharmony_ci}
58867db96d56Sopenharmony_ci
58877db96d56Sopenharmony_cistatic PyObject *
58887db96d56Sopenharmony_cidatetime_richcompare(PyObject *self, PyObject *other, int op)
58897db96d56Sopenharmony_ci{
58907db96d56Sopenharmony_ci    PyObject *result = NULL;
58917db96d56Sopenharmony_ci    PyObject *offset1, *offset2;
58927db96d56Sopenharmony_ci    int diff;
58937db96d56Sopenharmony_ci
58947db96d56Sopenharmony_ci    if (! PyDateTime_Check(other)) {
58957db96d56Sopenharmony_ci        if (PyDate_Check(other)) {
58967db96d56Sopenharmony_ci            /* Prevent invocation of date_richcompare.  We want to
58977db96d56Sopenharmony_ci               return NotImplemented here to give the other object
58987db96d56Sopenharmony_ci               a chance.  But since DateTime is a subclass of
58997db96d56Sopenharmony_ci               Date, if the other object is a Date, it would
59007db96d56Sopenharmony_ci               compute an ordering based on the date part alone,
59017db96d56Sopenharmony_ci               and we don't want that.  So force unequal or
59027db96d56Sopenharmony_ci               uncomparable here in that case. */
59037db96d56Sopenharmony_ci            if (op == Py_EQ)
59047db96d56Sopenharmony_ci                Py_RETURN_FALSE;
59057db96d56Sopenharmony_ci            if (op == Py_NE)
59067db96d56Sopenharmony_ci                Py_RETURN_TRUE;
59077db96d56Sopenharmony_ci            return cmperror(self, other);
59087db96d56Sopenharmony_ci        }
59097db96d56Sopenharmony_ci        Py_RETURN_NOTIMPLEMENTED;
59107db96d56Sopenharmony_ci    }
59117db96d56Sopenharmony_ci
59127db96d56Sopenharmony_ci    if (GET_DT_TZINFO(self) == GET_DT_TZINFO(other)) {
59137db96d56Sopenharmony_ci        diff = memcmp(((PyDateTime_DateTime *)self)->data,
59147db96d56Sopenharmony_ci                      ((PyDateTime_DateTime *)other)->data,
59157db96d56Sopenharmony_ci                      _PyDateTime_DATETIME_DATASIZE);
59167db96d56Sopenharmony_ci        return diff_to_bool(diff, op);
59177db96d56Sopenharmony_ci    }
59187db96d56Sopenharmony_ci    offset1 = datetime_utcoffset(self, NULL);
59197db96d56Sopenharmony_ci    if (offset1 == NULL)
59207db96d56Sopenharmony_ci        return NULL;
59217db96d56Sopenharmony_ci    offset2 = datetime_utcoffset(other, NULL);
59227db96d56Sopenharmony_ci    if (offset2 == NULL)
59237db96d56Sopenharmony_ci        goto done;
59247db96d56Sopenharmony_ci    /* If they're both naive, or both aware and have the same offsets,
59257db96d56Sopenharmony_ci     * we get off cheap.  Note that if they're both naive, offset1 ==
59267db96d56Sopenharmony_ci     * offset2 == Py_None at this point.
59277db96d56Sopenharmony_ci     */
59287db96d56Sopenharmony_ci    if ((offset1 == offset2) ||
59297db96d56Sopenharmony_ci        (PyDelta_Check(offset1) && PyDelta_Check(offset2) &&
59307db96d56Sopenharmony_ci         delta_cmp(offset1, offset2) == 0)) {
59317db96d56Sopenharmony_ci        diff = memcmp(((PyDateTime_DateTime *)self)->data,
59327db96d56Sopenharmony_ci                      ((PyDateTime_DateTime *)other)->data,
59337db96d56Sopenharmony_ci                      _PyDateTime_DATETIME_DATASIZE);
59347db96d56Sopenharmony_ci        if ((op == Py_EQ || op == Py_NE) && diff == 0) {
59357db96d56Sopenharmony_ci            int ex = pep495_eq_exception(self, other, offset1, offset2);
59367db96d56Sopenharmony_ci            if (ex == -1)
59377db96d56Sopenharmony_ci                goto done;
59387db96d56Sopenharmony_ci            if (ex)
59397db96d56Sopenharmony_ci                diff = 1;
59407db96d56Sopenharmony_ci        }
59417db96d56Sopenharmony_ci        result = diff_to_bool(diff, op);
59427db96d56Sopenharmony_ci    }
59437db96d56Sopenharmony_ci    else if (offset1 != Py_None && offset2 != Py_None) {
59447db96d56Sopenharmony_ci        PyDateTime_Delta *delta;
59457db96d56Sopenharmony_ci
59467db96d56Sopenharmony_ci        assert(offset1 != offset2); /* else last "if" handled it */
59477db96d56Sopenharmony_ci        delta = (PyDateTime_Delta *)datetime_subtract((PyObject *)self,
59487db96d56Sopenharmony_ci                                                       other);
59497db96d56Sopenharmony_ci        if (delta == NULL)
59507db96d56Sopenharmony_ci            goto done;
59517db96d56Sopenharmony_ci        diff = GET_TD_DAYS(delta);
59527db96d56Sopenharmony_ci        if (diff == 0)
59537db96d56Sopenharmony_ci            diff = GET_TD_SECONDS(delta) |
59547db96d56Sopenharmony_ci                   GET_TD_MICROSECONDS(delta);
59557db96d56Sopenharmony_ci        Py_DECREF(delta);
59567db96d56Sopenharmony_ci        if ((op == Py_EQ || op == Py_NE) && diff == 0) {
59577db96d56Sopenharmony_ci            int ex = pep495_eq_exception(self, other, offset1, offset2);
59587db96d56Sopenharmony_ci            if (ex == -1)
59597db96d56Sopenharmony_ci                goto done;
59607db96d56Sopenharmony_ci            if (ex)
59617db96d56Sopenharmony_ci                diff = 1;
59627db96d56Sopenharmony_ci        }
59637db96d56Sopenharmony_ci        result = diff_to_bool(diff, op);
59647db96d56Sopenharmony_ci    }
59657db96d56Sopenharmony_ci    else if (op == Py_EQ) {
59667db96d56Sopenharmony_ci        result = Py_False;
59677db96d56Sopenharmony_ci        Py_INCREF(result);
59687db96d56Sopenharmony_ci    }
59697db96d56Sopenharmony_ci    else if (op == Py_NE) {
59707db96d56Sopenharmony_ci        result = Py_True;
59717db96d56Sopenharmony_ci        Py_INCREF(result);
59727db96d56Sopenharmony_ci    }
59737db96d56Sopenharmony_ci    else {
59747db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
59757db96d56Sopenharmony_ci                        "can't compare offset-naive and "
59767db96d56Sopenharmony_ci                        "offset-aware datetimes");
59777db96d56Sopenharmony_ci    }
59787db96d56Sopenharmony_ci done:
59797db96d56Sopenharmony_ci    Py_DECREF(offset1);
59807db96d56Sopenharmony_ci    Py_XDECREF(offset2);
59817db96d56Sopenharmony_ci    return result;
59827db96d56Sopenharmony_ci}
59837db96d56Sopenharmony_ci
59847db96d56Sopenharmony_cistatic Py_hash_t
59857db96d56Sopenharmony_cidatetime_hash(PyDateTime_DateTime *self)
59867db96d56Sopenharmony_ci{
59877db96d56Sopenharmony_ci    if (self->hashcode == -1) {
59887db96d56Sopenharmony_ci        PyObject *offset, *self0;
59897db96d56Sopenharmony_ci        if (DATE_GET_FOLD(self)) {
59907db96d56Sopenharmony_ci            self0 = new_datetime_ex2(GET_YEAR(self),
59917db96d56Sopenharmony_ci                                     GET_MONTH(self),
59927db96d56Sopenharmony_ci                                     GET_DAY(self),
59937db96d56Sopenharmony_ci                                     DATE_GET_HOUR(self),
59947db96d56Sopenharmony_ci                                     DATE_GET_MINUTE(self),
59957db96d56Sopenharmony_ci                                     DATE_GET_SECOND(self),
59967db96d56Sopenharmony_ci                                     DATE_GET_MICROSECOND(self),
59977db96d56Sopenharmony_ci                                     HASTZINFO(self) ? self->tzinfo : Py_None,
59987db96d56Sopenharmony_ci                                     0, Py_TYPE(self));
59997db96d56Sopenharmony_ci            if (self0 == NULL)
60007db96d56Sopenharmony_ci                return -1;
60017db96d56Sopenharmony_ci        }
60027db96d56Sopenharmony_ci        else {
60037db96d56Sopenharmony_ci            self0 = (PyObject *)self;
60047db96d56Sopenharmony_ci            Py_INCREF(self0);
60057db96d56Sopenharmony_ci        }
60067db96d56Sopenharmony_ci        offset = datetime_utcoffset(self0, NULL);
60077db96d56Sopenharmony_ci        Py_DECREF(self0);
60087db96d56Sopenharmony_ci
60097db96d56Sopenharmony_ci        if (offset == NULL)
60107db96d56Sopenharmony_ci            return -1;
60117db96d56Sopenharmony_ci
60127db96d56Sopenharmony_ci        /* Reduce this to a hash of another object. */
60137db96d56Sopenharmony_ci        if (offset == Py_None)
60147db96d56Sopenharmony_ci            self->hashcode = generic_hash(
60157db96d56Sopenharmony_ci                (unsigned char *)self->data, _PyDateTime_DATETIME_DATASIZE);
60167db96d56Sopenharmony_ci        else {
60177db96d56Sopenharmony_ci            PyObject *temp1, *temp2;
60187db96d56Sopenharmony_ci            int days, seconds;
60197db96d56Sopenharmony_ci
60207db96d56Sopenharmony_ci            assert(HASTZINFO(self));
60217db96d56Sopenharmony_ci            days = ymd_to_ord(GET_YEAR(self),
60227db96d56Sopenharmony_ci                              GET_MONTH(self),
60237db96d56Sopenharmony_ci                              GET_DAY(self));
60247db96d56Sopenharmony_ci            seconds = DATE_GET_HOUR(self) * 3600 +
60257db96d56Sopenharmony_ci                      DATE_GET_MINUTE(self) * 60 +
60267db96d56Sopenharmony_ci                      DATE_GET_SECOND(self);
60277db96d56Sopenharmony_ci            temp1 = new_delta(days, seconds,
60287db96d56Sopenharmony_ci                              DATE_GET_MICROSECOND(self),
60297db96d56Sopenharmony_ci                              1);
60307db96d56Sopenharmony_ci            if (temp1 == NULL) {
60317db96d56Sopenharmony_ci                Py_DECREF(offset);
60327db96d56Sopenharmony_ci                return -1;
60337db96d56Sopenharmony_ci            }
60347db96d56Sopenharmony_ci            temp2 = delta_subtract(temp1, offset);
60357db96d56Sopenharmony_ci            Py_DECREF(temp1);
60367db96d56Sopenharmony_ci            if (temp2 == NULL) {
60377db96d56Sopenharmony_ci                Py_DECREF(offset);
60387db96d56Sopenharmony_ci                return -1;
60397db96d56Sopenharmony_ci            }
60407db96d56Sopenharmony_ci            self->hashcode = PyObject_Hash(temp2);
60417db96d56Sopenharmony_ci            Py_DECREF(temp2);
60427db96d56Sopenharmony_ci        }
60437db96d56Sopenharmony_ci        Py_DECREF(offset);
60447db96d56Sopenharmony_ci    }
60457db96d56Sopenharmony_ci    return self->hashcode;
60467db96d56Sopenharmony_ci}
60477db96d56Sopenharmony_ci
60487db96d56Sopenharmony_cistatic PyObject *
60497db96d56Sopenharmony_cidatetime_replace(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
60507db96d56Sopenharmony_ci{
60517db96d56Sopenharmony_ci    PyObject *clone;
60527db96d56Sopenharmony_ci    PyObject *tuple;
60537db96d56Sopenharmony_ci    int y = GET_YEAR(self);
60547db96d56Sopenharmony_ci    int m = GET_MONTH(self);
60557db96d56Sopenharmony_ci    int d = GET_DAY(self);
60567db96d56Sopenharmony_ci    int hh = DATE_GET_HOUR(self);
60577db96d56Sopenharmony_ci    int mm = DATE_GET_MINUTE(self);
60587db96d56Sopenharmony_ci    int ss = DATE_GET_SECOND(self);
60597db96d56Sopenharmony_ci    int us = DATE_GET_MICROSECOND(self);
60607db96d56Sopenharmony_ci    PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None;
60617db96d56Sopenharmony_ci    int fold = DATE_GET_FOLD(self);
60627db96d56Sopenharmony_ci
60637db96d56Sopenharmony_ci    if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiiiiO$i:replace",
60647db96d56Sopenharmony_ci                                      datetime_kws,
60657db96d56Sopenharmony_ci                                      &y, &m, &d, &hh, &mm, &ss, &us,
60667db96d56Sopenharmony_ci                                      &tzinfo, &fold))
60677db96d56Sopenharmony_ci        return NULL;
60687db96d56Sopenharmony_ci    if (fold != 0 && fold != 1) {
60697db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
60707db96d56Sopenharmony_ci                        "fold must be either 0 or 1");
60717db96d56Sopenharmony_ci        return NULL;
60727db96d56Sopenharmony_ci    }
60737db96d56Sopenharmony_ci    tuple = Py_BuildValue("iiiiiiiO", y, m, d, hh, mm, ss, us, tzinfo);
60747db96d56Sopenharmony_ci    if (tuple == NULL)
60757db96d56Sopenharmony_ci        return NULL;
60767db96d56Sopenharmony_ci    clone = datetime_new(Py_TYPE(self), tuple, NULL);
60777db96d56Sopenharmony_ci    if (clone != NULL) {
60787db96d56Sopenharmony_ci        DATE_SET_FOLD(clone, fold);
60797db96d56Sopenharmony_ci    }
60807db96d56Sopenharmony_ci    Py_DECREF(tuple);
60817db96d56Sopenharmony_ci    return clone;
60827db96d56Sopenharmony_ci}
60837db96d56Sopenharmony_ci
60847db96d56Sopenharmony_cistatic PyObject *
60857db96d56Sopenharmony_cilocal_timezone_from_timestamp(time_t timestamp)
60867db96d56Sopenharmony_ci{
60877db96d56Sopenharmony_ci    PyObject *result = NULL;
60887db96d56Sopenharmony_ci    PyObject *delta;
60897db96d56Sopenharmony_ci    struct tm local_time_tm;
60907db96d56Sopenharmony_ci    PyObject *nameo = NULL;
60917db96d56Sopenharmony_ci    const char *zone = NULL;
60927db96d56Sopenharmony_ci
60937db96d56Sopenharmony_ci    if (_PyTime_localtime(timestamp, &local_time_tm) != 0)
60947db96d56Sopenharmony_ci        return NULL;
60957db96d56Sopenharmony_ci#ifdef HAVE_STRUCT_TM_TM_ZONE
60967db96d56Sopenharmony_ci    zone = local_time_tm.tm_zone;
60977db96d56Sopenharmony_ci    delta = new_delta(0, local_time_tm.tm_gmtoff, 0, 1);
60987db96d56Sopenharmony_ci#else /* HAVE_STRUCT_TM_TM_ZONE */
60997db96d56Sopenharmony_ci    {
61007db96d56Sopenharmony_ci        PyObject *local_time, *utc_time;
61017db96d56Sopenharmony_ci        struct tm utc_time_tm;
61027db96d56Sopenharmony_ci        char buf[100];
61037db96d56Sopenharmony_ci        strftime(buf, sizeof(buf), "%Z", &local_time_tm);
61047db96d56Sopenharmony_ci        zone = buf;
61057db96d56Sopenharmony_ci        local_time = new_datetime(local_time_tm.tm_year + 1900,
61067db96d56Sopenharmony_ci                                  local_time_tm.tm_mon + 1,
61077db96d56Sopenharmony_ci                                  local_time_tm.tm_mday,
61087db96d56Sopenharmony_ci                                  local_time_tm.tm_hour,
61097db96d56Sopenharmony_ci                                  local_time_tm.tm_min,
61107db96d56Sopenharmony_ci                                  local_time_tm.tm_sec, 0, Py_None, 0);
61117db96d56Sopenharmony_ci        if (local_time == NULL) {
61127db96d56Sopenharmony_ci            return NULL;
61137db96d56Sopenharmony_ci        }
61147db96d56Sopenharmony_ci        if (_PyTime_gmtime(timestamp, &utc_time_tm) != 0)
61157db96d56Sopenharmony_ci            return NULL;
61167db96d56Sopenharmony_ci        utc_time = new_datetime(utc_time_tm.tm_year + 1900,
61177db96d56Sopenharmony_ci                                utc_time_tm.tm_mon + 1,
61187db96d56Sopenharmony_ci                                utc_time_tm.tm_mday,
61197db96d56Sopenharmony_ci                                utc_time_tm.tm_hour,
61207db96d56Sopenharmony_ci                                utc_time_tm.tm_min,
61217db96d56Sopenharmony_ci                                utc_time_tm.tm_sec, 0, Py_None, 0);
61227db96d56Sopenharmony_ci        if (utc_time == NULL) {
61237db96d56Sopenharmony_ci            Py_DECREF(local_time);
61247db96d56Sopenharmony_ci            return NULL;
61257db96d56Sopenharmony_ci        }
61267db96d56Sopenharmony_ci        delta = datetime_subtract(local_time, utc_time);
61277db96d56Sopenharmony_ci        Py_DECREF(local_time);
61287db96d56Sopenharmony_ci        Py_DECREF(utc_time);
61297db96d56Sopenharmony_ci    }
61307db96d56Sopenharmony_ci#endif /* HAVE_STRUCT_TM_TM_ZONE */
61317db96d56Sopenharmony_ci    if (delta == NULL) {
61327db96d56Sopenharmony_ci            return NULL;
61337db96d56Sopenharmony_ci    }
61347db96d56Sopenharmony_ci    if (zone != NULL) {
61357db96d56Sopenharmony_ci        nameo = PyUnicode_DecodeLocale(zone, "surrogateescape");
61367db96d56Sopenharmony_ci        if (nameo == NULL)
61377db96d56Sopenharmony_ci            goto error;
61387db96d56Sopenharmony_ci    }
61397db96d56Sopenharmony_ci    result = new_timezone(delta, nameo);
61407db96d56Sopenharmony_ci    Py_XDECREF(nameo);
61417db96d56Sopenharmony_ci  error:
61427db96d56Sopenharmony_ci    Py_DECREF(delta);
61437db96d56Sopenharmony_ci    return result;
61447db96d56Sopenharmony_ci}
61457db96d56Sopenharmony_ci
61467db96d56Sopenharmony_cistatic PyObject *
61477db96d56Sopenharmony_cilocal_timezone(PyDateTime_DateTime *utc_time)
61487db96d56Sopenharmony_ci{
61497db96d56Sopenharmony_ci    time_t timestamp;
61507db96d56Sopenharmony_ci    PyObject *delta;
61517db96d56Sopenharmony_ci    PyObject *one_second;
61527db96d56Sopenharmony_ci    PyObject *seconds;
61537db96d56Sopenharmony_ci
61547db96d56Sopenharmony_ci    delta = datetime_subtract((PyObject *)utc_time, PyDateTime_Epoch);
61557db96d56Sopenharmony_ci    if (delta == NULL)
61567db96d56Sopenharmony_ci        return NULL;
61577db96d56Sopenharmony_ci    one_second = new_delta(0, 1, 0, 0);
61587db96d56Sopenharmony_ci    if (one_second == NULL) {
61597db96d56Sopenharmony_ci        Py_DECREF(delta);
61607db96d56Sopenharmony_ci        return NULL;
61617db96d56Sopenharmony_ci    }
61627db96d56Sopenharmony_ci    seconds = divide_timedelta_timedelta((PyDateTime_Delta *)delta,
61637db96d56Sopenharmony_ci                                         (PyDateTime_Delta *)one_second);
61647db96d56Sopenharmony_ci    Py_DECREF(one_second);
61657db96d56Sopenharmony_ci    Py_DECREF(delta);
61667db96d56Sopenharmony_ci    if (seconds == NULL)
61677db96d56Sopenharmony_ci        return NULL;
61687db96d56Sopenharmony_ci    timestamp = _PyLong_AsTime_t(seconds);
61697db96d56Sopenharmony_ci    Py_DECREF(seconds);
61707db96d56Sopenharmony_ci    if (timestamp == -1 && PyErr_Occurred())
61717db96d56Sopenharmony_ci        return NULL;
61727db96d56Sopenharmony_ci    return local_timezone_from_timestamp(timestamp);
61737db96d56Sopenharmony_ci}
61747db96d56Sopenharmony_ci
61757db96d56Sopenharmony_cistatic long long
61767db96d56Sopenharmony_cilocal_to_seconds(int year, int month, int day,
61777db96d56Sopenharmony_ci                 int hour, int minute, int second, int fold);
61787db96d56Sopenharmony_ci
61797db96d56Sopenharmony_cistatic PyObject *
61807db96d56Sopenharmony_cilocal_timezone_from_local(PyDateTime_DateTime *local_dt)
61817db96d56Sopenharmony_ci{
61827db96d56Sopenharmony_ci    long long seconds;
61837db96d56Sopenharmony_ci    time_t timestamp;
61847db96d56Sopenharmony_ci    seconds = local_to_seconds(GET_YEAR(local_dt),
61857db96d56Sopenharmony_ci                               GET_MONTH(local_dt),
61867db96d56Sopenharmony_ci                               GET_DAY(local_dt),
61877db96d56Sopenharmony_ci                               DATE_GET_HOUR(local_dt),
61887db96d56Sopenharmony_ci                               DATE_GET_MINUTE(local_dt),
61897db96d56Sopenharmony_ci                               DATE_GET_SECOND(local_dt),
61907db96d56Sopenharmony_ci                               DATE_GET_FOLD(local_dt));
61917db96d56Sopenharmony_ci    if (seconds == -1)
61927db96d56Sopenharmony_ci        return NULL;
61937db96d56Sopenharmony_ci    /* XXX: add bounds check */
61947db96d56Sopenharmony_ci    timestamp = seconds - epoch;
61957db96d56Sopenharmony_ci    return local_timezone_from_timestamp(timestamp);
61967db96d56Sopenharmony_ci}
61977db96d56Sopenharmony_ci
61987db96d56Sopenharmony_cistatic PyDateTime_DateTime *
61997db96d56Sopenharmony_cidatetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
62007db96d56Sopenharmony_ci{
62017db96d56Sopenharmony_ci    PyDateTime_DateTime *result;
62027db96d56Sopenharmony_ci    PyObject *offset;
62037db96d56Sopenharmony_ci    PyObject *temp;
62047db96d56Sopenharmony_ci    PyObject *self_tzinfo;
62057db96d56Sopenharmony_ci    PyObject *tzinfo = Py_None;
62067db96d56Sopenharmony_ci    static char *keywords[] = {"tz", NULL};
62077db96d56Sopenharmony_ci
62087db96d56Sopenharmony_ci    if (! PyArg_ParseTupleAndKeywords(args, kw, "|O:astimezone", keywords,
62097db96d56Sopenharmony_ci                                      &tzinfo))
62107db96d56Sopenharmony_ci        return NULL;
62117db96d56Sopenharmony_ci
62127db96d56Sopenharmony_ci    if (check_tzinfo_subclass(tzinfo) == -1)
62137db96d56Sopenharmony_ci        return NULL;
62147db96d56Sopenharmony_ci
62157db96d56Sopenharmony_ci    if (!HASTZINFO(self) || self->tzinfo == Py_None) {
62167db96d56Sopenharmony_ci  naive:
62177db96d56Sopenharmony_ci        self_tzinfo = local_timezone_from_local(self);
62187db96d56Sopenharmony_ci        if (self_tzinfo == NULL)
62197db96d56Sopenharmony_ci            return NULL;
62207db96d56Sopenharmony_ci    } else {
62217db96d56Sopenharmony_ci        self_tzinfo = self->tzinfo;
62227db96d56Sopenharmony_ci        Py_INCREF(self_tzinfo);
62237db96d56Sopenharmony_ci    }
62247db96d56Sopenharmony_ci
62257db96d56Sopenharmony_ci    /* Conversion to self's own time zone is a NOP. */
62267db96d56Sopenharmony_ci    if (self_tzinfo == tzinfo) {
62277db96d56Sopenharmony_ci        Py_DECREF(self_tzinfo);
62287db96d56Sopenharmony_ci        Py_INCREF(self);
62297db96d56Sopenharmony_ci        return self;
62307db96d56Sopenharmony_ci    }
62317db96d56Sopenharmony_ci
62327db96d56Sopenharmony_ci    /* Convert self to UTC. */
62337db96d56Sopenharmony_ci    offset = call_utcoffset(self_tzinfo, (PyObject *)self);
62347db96d56Sopenharmony_ci    Py_DECREF(self_tzinfo);
62357db96d56Sopenharmony_ci    if (offset == NULL)
62367db96d56Sopenharmony_ci        return NULL;
62377db96d56Sopenharmony_ci    else if(offset == Py_None) {
62387db96d56Sopenharmony_ci        Py_DECREF(offset);
62397db96d56Sopenharmony_ci        goto naive;
62407db96d56Sopenharmony_ci    }
62417db96d56Sopenharmony_ci    else if (!PyDelta_Check(offset)) {
62427db96d56Sopenharmony_ci        Py_DECREF(offset);
62437db96d56Sopenharmony_ci        PyErr_Format(PyExc_TypeError, "utcoffset() returned %.200s,"
62447db96d56Sopenharmony_ci                     " expected timedelta or None", Py_TYPE(offset)->tp_name);
62457db96d56Sopenharmony_ci        return NULL;
62467db96d56Sopenharmony_ci    }
62477db96d56Sopenharmony_ci    /* result = self - offset */
62487db96d56Sopenharmony_ci    result = (PyDateTime_DateTime *)add_datetime_timedelta(self,
62497db96d56Sopenharmony_ci                                       (PyDateTime_Delta *)offset, -1);
62507db96d56Sopenharmony_ci    Py_DECREF(offset);
62517db96d56Sopenharmony_ci    if (result == NULL)
62527db96d56Sopenharmony_ci        return NULL;
62537db96d56Sopenharmony_ci
62547db96d56Sopenharmony_ci    /* Make sure result is aware and UTC. */
62557db96d56Sopenharmony_ci    if (!HASTZINFO(result)) {
62567db96d56Sopenharmony_ci        temp = (PyObject *)result;
62577db96d56Sopenharmony_ci        result = (PyDateTime_DateTime *)
62587db96d56Sopenharmony_ci                   new_datetime_ex2(GET_YEAR(result),
62597db96d56Sopenharmony_ci                                    GET_MONTH(result),
62607db96d56Sopenharmony_ci                                    GET_DAY(result),
62617db96d56Sopenharmony_ci                                    DATE_GET_HOUR(result),
62627db96d56Sopenharmony_ci                                    DATE_GET_MINUTE(result),
62637db96d56Sopenharmony_ci                                    DATE_GET_SECOND(result),
62647db96d56Sopenharmony_ci                                    DATE_GET_MICROSECOND(result),
62657db96d56Sopenharmony_ci                                    PyDateTime_TimeZone_UTC,
62667db96d56Sopenharmony_ci                                    DATE_GET_FOLD(result),
62677db96d56Sopenharmony_ci                                    Py_TYPE(result));
62687db96d56Sopenharmony_ci        Py_DECREF(temp);
62697db96d56Sopenharmony_ci        if (result == NULL)
62707db96d56Sopenharmony_ci            return NULL;
62717db96d56Sopenharmony_ci    }
62727db96d56Sopenharmony_ci    else {
62737db96d56Sopenharmony_ci        /* Result is already aware - just replace tzinfo. */
62747db96d56Sopenharmony_ci        temp = result->tzinfo;
62757db96d56Sopenharmony_ci        result->tzinfo = PyDateTime_TimeZone_UTC;
62767db96d56Sopenharmony_ci        Py_INCREF(result->tzinfo);
62777db96d56Sopenharmony_ci        Py_DECREF(temp);
62787db96d56Sopenharmony_ci    }
62797db96d56Sopenharmony_ci
62807db96d56Sopenharmony_ci    /* Attach new tzinfo and let fromutc() do the rest. */
62817db96d56Sopenharmony_ci    temp = result->tzinfo;
62827db96d56Sopenharmony_ci    if (tzinfo == Py_None) {
62837db96d56Sopenharmony_ci        tzinfo = local_timezone(result);
62847db96d56Sopenharmony_ci        if (tzinfo == NULL) {
62857db96d56Sopenharmony_ci            Py_DECREF(result);
62867db96d56Sopenharmony_ci            return NULL;
62877db96d56Sopenharmony_ci        }
62887db96d56Sopenharmony_ci    }
62897db96d56Sopenharmony_ci    else
62907db96d56Sopenharmony_ci      Py_INCREF(tzinfo);
62917db96d56Sopenharmony_ci    result->tzinfo = tzinfo;
62927db96d56Sopenharmony_ci    Py_DECREF(temp);
62937db96d56Sopenharmony_ci
62947db96d56Sopenharmony_ci    temp = (PyObject *)result;
62957db96d56Sopenharmony_ci    result = (PyDateTime_DateTime *)
62967db96d56Sopenharmony_ci        _PyObject_CallMethodIdOneArg(tzinfo, &PyId_fromutc, temp);
62977db96d56Sopenharmony_ci    Py_DECREF(temp);
62987db96d56Sopenharmony_ci
62997db96d56Sopenharmony_ci    return result;
63007db96d56Sopenharmony_ci}
63017db96d56Sopenharmony_ci
63027db96d56Sopenharmony_cistatic PyObject *
63037db96d56Sopenharmony_cidatetime_timetuple(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
63047db96d56Sopenharmony_ci{
63057db96d56Sopenharmony_ci    int dstflag = -1;
63067db96d56Sopenharmony_ci
63077db96d56Sopenharmony_ci    if (HASTZINFO(self) && self->tzinfo != Py_None) {
63087db96d56Sopenharmony_ci        PyObject * dst;
63097db96d56Sopenharmony_ci
63107db96d56Sopenharmony_ci        dst = call_dst(self->tzinfo, (PyObject *)self);
63117db96d56Sopenharmony_ci        if (dst == NULL)
63127db96d56Sopenharmony_ci            return NULL;
63137db96d56Sopenharmony_ci
63147db96d56Sopenharmony_ci        if (dst != Py_None)
63157db96d56Sopenharmony_ci            dstflag = delta_bool((PyDateTime_Delta *)dst);
63167db96d56Sopenharmony_ci        Py_DECREF(dst);
63177db96d56Sopenharmony_ci    }
63187db96d56Sopenharmony_ci    return build_struct_time(GET_YEAR(self),
63197db96d56Sopenharmony_ci                             GET_MONTH(self),
63207db96d56Sopenharmony_ci                             GET_DAY(self),
63217db96d56Sopenharmony_ci                             DATE_GET_HOUR(self),
63227db96d56Sopenharmony_ci                             DATE_GET_MINUTE(self),
63237db96d56Sopenharmony_ci                             DATE_GET_SECOND(self),
63247db96d56Sopenharmony_ci                             dstflag);
63257db96d56Sopenharmony_ci}
63267db96d56Sopenharmony_ci
63277db96d56Sopenharmony_cistatic long long
63287db96d56Sopenharmony_cilocal_to_seconds(int year, int month, int day,
63297db96d56Sopenharmony_ci                 int hour, int minute, int second, int fold)
63307db96d56Sopenharmony_ci{
63317db96d56Sopenharmony_ci    long long t, a, b, u1, u2, t1, t2, lt;
63327db96d56Sopenharmony_ci    t = utc_to_seconds(year, month, day, hour, minute, second);
63337db96d56Sopenharmony_ci    /* Our goal is to solve t = local(u) for u. */
63347db96d56Sopenharmony_ci    lt = local(t);
63357db96d56Sopenharmony_ci    if (lt == -1)
63367db96d56Sopenharmony_ci        return -1;
63377db96d56Sopenharmony_ci    a = lt - t;
63387db96d56Sopenharmony_ci    u1 = t - a;
63397db96d56Sopenharmony_ci    t1 = local(u1);
63407db96d56Sopenharmony_ci    if (t1 == -1)
63417db96d56Sopenharmony_ci        return -1;
63427db96d56Sopenharmony_ci    if (t1 == t) {
63437db96d56Sopenharmony_ci        /* We found one solution, but it may not be the one we need.
63447db96d56Sopenharmony_ci         * Look for an earlier solution (if `fold` is 0), or a
63457db96d56Sopenharmony_ci         * later one (if `fold` is 1). */
63467db96d56Sopenharmony_ci        if (fold)
63477db96d56Sopenharmony_ci            u2 = u1 + max_fold_seconds;
63487db96d56Sopenharmony_ci        else
63497db96d56Sopenharmony_ci            u2 = u1 - max_fold_seconds;
63507db96d56Sopenharmony_ci        lt = local(u2);
63517db96d56Sopenharmony_ci        if (lt == -1)
63527db96d56Sopenharmony_ci            return -1;
63537db96d56Sopenharmony_ci        b = lt - u2;
63547db96d56Sopenharmony_ci        if (a == b)
63557db96d56Sopenharmony_ci            return u1;
63567db96d56Sopenharmony_ci    }
63577db96d56Sopenharmony_ci    else {
63587db96d56Sopenharmony_ci        b = t1 - u1;
63597db96d56Sopenharmony_ci        assert(a != b);
63607db96d56Sopenharmony_ci    }
63617db96d56Sopenharmony_ci    u2 = t - b;
63627db96d56Sopenharmony_ci    t2 = local(u2);
63637db96d56Sopenharmony_ci    if (t2 == -1)
63647db96d56Sopenharmony_ci        return -1;
63657db96d56Sopenharmony_ci    if (t2 == t)
63667db96d56Sopenharmony_ci        return u2;
63677db96d56Sopenharmony_ci    if (t1 == t)
63687db96d56Sopenharmony_ci        return u1;
63697db96d56Sopenharmony_ci    /* We have found both offsets a and b, but neither t - a nor t - b is
63707db96d56Sopenharmony_ci     * a solution.  This means t is in the gap. */
63717db96d56Sopenharmony_ci    return fold?Py_MIN(u1, u2):Py_MAX(u1, u2);
63727db96d56Sopenharmony_ci}
63737db96d56Sopenharmony_ci
63747db96d56Sopenharmony_ci/* date(1970,1,1).toordinal() == 719163 */
63757db96d56Sopenharmony_ci#define EPOCH_SECONDS (719163LL * 24 * 60 * 60)
63767db96d56Sopenharmony_ci
63777db96d56Sopenharmony_cistatic PyObject *
63787db96d56Sopenharmony_cidatetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
63797db96d56Sopenharmony_ci{
63807db96d56Sopenharmony_ci    PyObject *result;
63817db96d56Sopenharmony_ci
63827db96d56Sopenharmony_ci    if (HASTZINFO(self) && self->tzinfo != Py_None) {
63837db96d56Sopenharmony_ci        PyObject *delta;
63847db96d56Sopenharmony_ci        delta = datetime_subtract((PyObject *)self, PyDateTime_Epoch);
63857db96d56Sopenharmony_ci        if (delta == NULL)
63867db96d56Sopenharmony_ci            return NULL;
63877db96d56Sopenharmony_ci        result = delta_total_seconds(delta, NULL);
63887db96d56Sopenharmony_ci        Py_DECREF(delta);
63897db96d56Sopenharmony_ci    }
63907db96d56Sopenharmony_ci    else {
63917db96d56Sopenharmony_ci        long long seconds;
63927db96d56Sopenharmony_ci        seconds = local_to_seconds(GET_YEAR(self),
63937db96d56Sopenharmony_ci                                   GET_MONTH(self),
63947db96d56Sopenharmony_ci                                   GET_DAY(self),
63957db96d56Sopenharmony_ci                                   DATE_GET_HOUR(self),
63967db96d56Sopenharmony_ci                                   DATE_GET_MINUTE(self),
63977db96d56Sopenharmony_ci                                   DATE_GET_SECOND(self),
63987db96d56Sopenharmony_ci                                   DATE_GET_FOLD(self));
63997db96d56Sopenharmony_ci        if (seconds == -1)
64007db96d56Sopenharmony_ci            return NULL;
64017db96d56Sopenharmony_ci        result = PyFloat_FromDouble(seconds - EPOCH_SECONDS +
64027db96d56Sopenharmony_ci                                    DATE_GET_MICROSECOND(self) / 1e6);
64037db96d56Sopenharmony_ci    }
64047db96d56Sopenharmony_ci    return result;
64057db96d56Sopenharmony_ci}
64067db96d56Sopenharmony_ci
64077db96d56Sopenharmony_cistatic PyObject *
64087db96d56Sopenharmony_cidatetime_getdate(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
64097db96d56Sopenharmony_ci{
64107db96d56Sopenharmony_ci    return new_date(GET_YEAR(self),
64117db96d56Sopenharmony_ci                    GET_MONTH(self),
64127db96d56Sopenharmony_ci                    GET_DAY(self));
64137db96d56Sopenharmony_ci}
64147db96d56Sopenharmony_ci
64157db96d56Sopenharmony_cistatic PyObject *
64167db96d56Sopenharmony_cidatetime_gettime(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
64177db96d56Sopenharmony_ci{
64187db96d56Sopenharmony_ci    return new_time(DATE_GET_HOUR(self),
64197db96d56Sopenharmony_ci                    DATE_GET_MINUTE(self),
64207db96d56Sopenharmony_ci                    DATE_GET_SECOND(self),
64217db96d56Sopenharmony_ci                    DATE_GET_MICROSECOND(self),
64227db96d56Sopenharmony_ci                    Py_None,
64237db96d56Sopenharmony_ci                    DATE_GET_FOLD(self));
64247db96d56Sopenharmony_ci}
64257db96d56Sopenharmony_ci
64267db96d56Sopenharmony_cistatic PyObject *
64277db96d56Sopenharmony_cidatetime_gettimetz(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
64287db96d56Sopenharmony_ci{
64297db96d56Sopenharmony_ci    return new_time(DATE_GET_HOUR(self),
64307db96d56Sopenharmony_ci                    DATE_GET_MINUTE(self),
64317db96d56Sopenharmony_ci                    DATE_GET_SECOND(self),
64327db96d56Sopenharmony_ci                    DATE_GET_MICROSECOND(self),
64337db96d56Sopenharmony_ci                    GET_DT_TZINFO(self),
64347db96d56Sopenharmony_ci                    DATE_GET_FOLD(self));
64357db96d56Sopenharmony_ci}
64367db96d56Sopenharmony_ci
64377db96d56Sopenharmony_cistatic PyObject *
64387db96d56Sopenharmony_cidatetime_utctimetuple(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored))
64397db96d56Sopenharmony_ci{
64407db96d56Sopenharmony_ci    int y, m, d, hh, mm, ss;
64417db96d56Sopenharmony_ci    PyObject *tzinfo;
64427db96d56Sopenharmony_ci    PyDateTime_DateTime *utcself;
64437db96d56Sopenharmony_ci
64447db96d56Sopenharmony_ci    tzinfo = GET_DT_TZINFO(self);
64457db96d56Sopenharmony_ci    if (tzinfo == Py_None) {
64467db96d56Sopenharmony_ci        utcself = self;
64477db96d56Sopenharmony_ci        Py_INCREF(utcself);
64487db96d56Sopenharmony_ci    }
64497db96d56Sopenharmony_ci    else {
64507db96d56Sopenharmony_ci        PyObject *offset;
64517db96d56Sopenharmony_ci        offset = call_utcoffset(tzinfo, (PyObject *)self);
64527db96d56Sopenharmony_ci        if (offset == NULL)
64537db96d56Sopenharmony_ci            return NULL;
64547db96d56Sopenharmony_ci        if (offset == Py_None) {
64557db96d56Sopenharmony_ci            Py_DECREF(offset);
64567db96d56Sopenharmony_ci            utcself = self;
64577db96d56Sopenharmony_ci            Py_INCREF(utcself);
64587db96d56Sopenharmony_ci        }
64597db96d56Sopenharmony_ci        else {
64607db96d56Sopenharmony_ci            utcself = (PyDateTime_DateTime *)add_datetime_timedelta(self,
64617db96d56Sopenharmony_ci                                                (PyDateTime_Delta *)offset, -1);
64627db96d56Sopenharmony_ci            Py_DECREF(offset);
64637db96d56Sopenharmony_ci            if (utcself == NULL)
64647db96d56Sopenharmony_ci                return NULL;
64657db96d56Sopenharmony_ci        }
64667db96d56Sopenharmony_ci    }
64677db96d56Sopenharmony_ci    y = GET_YEAR(utcself);
64687db96d56Sopenharmony_ci    m = GET_MONTH(utcself);
64697db96d56Sopenharmony_ci    d = GET_DAY(utcself);
64707db96d56Sopenharmony_ci    hh = DATE_GET_HOUR(utcself);
64717db96d56Sopenharmony_ci    mm = DATE_GET_MINUTE(utcself);
64727db96d56Sopenharmony_ci    ss = DATE_GET_SECOND(utcself);
64737db96d56Sopenharmony_ci
64747db96d56Sopenharmony_ci    Py_DECREF(utcself);
64757db96d56Sopenharmony_ci    return build_struct_time(y, m, d, hh, mm, ss, 0);
64767db96d56Sopenharmony_ci}
64777db96d56Sopenharmony_ci
64787db96d56Sopenharmony_ci/* Pickle support, a simple use of __reduce__. */
64797db96d56Sopenharmony_ci
64807db96d56Sopenharmony_ci/* Let basestate be the non-tzinfo data string.
64817db96d56Sopenharmony_ci * If tzinfo is None, this returns (basestate,), else (basestate, tzinfo).
64827db96d56Sopenharmony_ci * So it's a tuple in any (non-error) case.
64837db96d56Sopenharmony_ci * __getstate__ isn't exposed.
64847db96d56Sopenharmony_ci */
64857db96d56Sopenharmony_cistatic PyObject *
64867db96d56Sopenharmony_cidatetime_getstate(PyDateTime_DateTime *self, int proto)
64877db96d56Sopenharmony_ci{
64887db96d56Sopenharmony_ci    PyObject *basestate;
64897db96d56Sopenharmony_ci    PyObject *result = NULL;
64907db96d56Sopenharmony_ci
64917db96d56Sopenharmony_ci    basestate = PyBytes_FromStringAndSize((char *)self->data,
64927db96d56Sopenharmony_ci                                           _PyDateTime_DATETIME_DATASIZE);
64937db96d56Sopenharmony_ci    if (basestate != NULL) {
64947db96d56Sopenharmony_ci        if (proto > 3 && DATE_GET_FOLD(self))
64957db96d56Sopenharmony_ci            /* Set the first bit of the third byte */
64967db96d56Sopenharmony_ci            PyBytes_AS_STRING(basestate)[2] |= (1 << 7);
64977db96d56Sopenharmony_ci        if (! HASTZINFO(self) || self->tzinfo == Py_None)
64987db96d56Sopenharmony_ci            result = PyTuple_Pack(1, basestate);
64997db96d56Sopenharmony_ci        else
65007db96d56Sopenharmony_ci            result = PyTuple_Pack(2, basestate, self->tzinfo);
65017db96d56Sopenharmony_ci        Py_DECREF(basestate);
65027db96d56Sopenharmony_ci    }
65037db96d56Sopenharmony_ci    return result;
65047db96d56Sopenharmony_ci}
65057db96d56Sopenharmony_ci
65067db96d56Sopenharmony_cistatic PyObject *
65077db96d56Sopenharmony_cidatetime_reduce_ex(PyDateTime_DateTime *self, PyObject *args)
65087db96d56Sopenharmony_ci{
65097db96d56Sopenharmony_ci    int proto;
65107db96d56Sopenharmony_ci    if (!PyArg_ParseTuple(args, "i:__reduce_ex__", &proto))
65117db96d56Sopenharmony_ci        return NULL;
65127db96d56Sopenharmony_ci
65137db96d56Sopenharmony_ci    return Py_BuildValue("(ON)", Py_TYPE(self), datetime_getstate(self, proto));
65147db96d56Sopenharmony_ci}
65157db96d56Sopenharmony_ci
65167db96d56Sopenharmony_cistatic PyObject *
65177db96d56Sopenharmony_cidatetime_reduce(PyDateTime_DateTime *self, PyObject *arg)
65187db96d56Sopenharmony_ci{
65197db96d56Sopenharmony_ci    return Py_BuildValue("(ON)", Py_TYPE(self), datetime_getstate(self, 2));
65207db96d56Sopenharmony_ci}
65217db96d56Sopenharmony_ci
65227db96d56Sopenharmony_cistatic PyMethodDef datetime_methods[] = {
65237db96d56Sopenharmony_ci
65247db96d56Sopenharmony_ci    /* Class methods: */
65257db96d56Sopenharmony_ci
65267db96d56Sopenharmony_ci    DATETIME_DATETIME_NOW_METHODDEF
65277db96d56Sopenharmony_ci
65287db96d56Sopenharmony_ci    {"utcnow",         (PyCFunction)datetime_utcnow,
65297db96d56Sopenharmony_ci     METH_NOARGS | METH_CLASS,
65307db96d56Sopenharmony_ci     PyDoc_STR("Return a new datetime representing UTC day and time.")},
65317db96d56Sopenharmony_ci
65327db96d56Sopenharmony_ci    {"fromtimestamp", _PyCFunction_CAST(datetime_fromtimestamp),
65337db96d56Sopenharmony_ci     METH_VARARGS | METH_KEYWORDS | METH_CLASS,
65347db96d56Sopenharmony_ci     PyDoc_STR("timestamp[, tz] -> tz's local time from POSIX timestamp.")},
65357db96d56Sopenharmony_ci
65367db96d56Sopenharmony_ci    {"utcfromtimestamp", (PyCFunction)datetime_utcfromtimestamp,
65377db96d56Sopenharmony_ci     METH_VARARGS | METH_CLASS,
65387db96d56Sopenharmony_ci     PyDoc_STR("Construct a naive UTC datetime from a POSIX timestamp.")},
65397db96d56Sopenharmony_ci
65407db96d56Sopenharmony_ci    {"strptime", (PyCFunction)datetime_strptime,
65417db96d56Sopenharmony_ci     METH_VARARGS | METH_CLASS,
65427db96d56Sopenharmony_ci     PyDoc_STR("string, format -> new datetime parsed from a string "
65437db96d56Sopenharmony_ci               "(like time.strptime()).")},
65447db96d56Sopenharmony_ci
65457db96d56Sopenharmony_ci    {"combine", _PyCFunction_CAST(datetime_combine),
65467db96d56Sopenharmony_ci     METH_VARARGS | METH_KEYWORDS | METH_CLASS,
65477db96d56Sopenharmony_ci     PyDoc_STR("date, time -> datetime with same date and time fields")},
65487db96d56Sopenharmony_ci
65497db96d56Sopenharmony_ci    {"fromisoformat", (PyCFunction)datetime_fromisoformat,
65507db96d56Sopenharmony_ci     METH_O | METH_CLASS,
65517db96d56Sopenharmony_ci     PyDoc_STR("string -> datetime from a string in most ISO 8601 formats")},
65527db96d56Sopenharmony_ci
65537db96d56Sopenharmony_ci    /* Instance methods: */
65547db96d56Sopenharmony_ci
65557db96d56Sopenharmony_ci    {"date",   (PyCFunction)datetime_getdate, METH_NOARGS,
65567db96d56Sopenharmony_ci     PyDoc_STR("Return date object with same year, month and day.")},
65577db96d56Sopenharmony_ci
65587db96d56Sopenharmony_ci    {"time",   (PyCFunction)datetime_gettime, METH_NOARGS,
65597db96d56Sopenharmony_ci     PyDoc_STR("Return time object with same time but with tzinfo=None.")},
65607db96d56Sopenharmony_ci
65617db96d56Sopenharmony_ci    {"timetz",   (PyCFunction)datetime_gettimetz, METH_NOARGS,
65627db96d56Sopenharmony_ci     PyDoc_STR("Return time object with same time and tzinfo.")},
65637db96d56Sopenharmony_ci
65647db96d56Sopenharmony_ci    {"ctime",       (PyCFunction)datetime_ctime,        METH_NOARGS,
65657db96d56Sopenharmony_ci     PyDoc_STR("Return ctime() style string.")},
65667db96d56Sopenharmony_ci
65677db96d56Sopenharmony_ci    {"timetuple",   (PyCFunction)datetime_timetuple, METH_NOARGS,
65687db96d56Sopenharmony_ci     PyDoc_STR("Return time tuple, compatible with time.localtime().")},
65697db96d56Sopenharmony_ci
65707db96d56Sopenharmony_ci    {"timestamp",   (PyCFunction)datetime_timestamp, METH_NOARGS,
65717db96d56Sopenharmony_ci     PyDoc_STR("Return POSIX timestamp as float.")},
65727db96d56Sopenharmony_ci
65737db96d56Sopenharmony_ci    {"utctimetuple",   (PyCFunction)datetime_utctimetuple, METH_NOARGS,
65747db96d56Sopenharmony_ci     PyDoc_STR("Return UTC time tuple, compatible with time.localtime().")},
65757db96d56Sopenharmony_ci
65767db96d56Sopenharmony_ci    {"isoformat",   _PyCFunction_CAST(datetime_isoformat), METH_VARARGS | METH_KEYWORDS,
65777db96d56Sopenharmony_ci     PyDoc_STR("[sep] -> string in ISO 8601 format, "
65787db96d56Sopenharmony_ci               "YYYY-MM-DDT[HH[:MM[:SS[.mmm[uuu]]]]][+HH:MM].\n"
65797db96d56Sopenharmony_ci               "sep is used to separate the year from the time, and "
65807db96d56Sopenharmony_ci               "defaults to 'T'.\n"
65817db96d56Sopenharmony_ci               "The optional argument timespec specifies the number "
65827db96d56Sopenharmony_ci               "of additional terms\nof the time to include. Valid "
65837db96d56Sopenharmony_ci               "options are 'auto', 'hours', 'minutes',\n'seconds', "
65847db96d56Sopenharmony_ci               "'milliseconds' and 'microseconds'.\n")},
65857db96d56Sopenharmony_ci
65867db96d56Sopenharmony_ci    {"utcoffset",       (PyCFunction)datetime_utcoffset, METH_NOARGS,
65877db96d56Sopenharmony_ci     PyDoc_STR("Return self.tzinfo.utcoffset(self).")},
65887db96d56Sopenharmony_ci
65897db96d56Sopenharmony_ci    {"tzname",          (PyCFunction)datetime_tzname,   METH_NOARGS,
65907db96d56Sopenharmony_ci     PyDoc_STR("Return self.tzinfo.tzname(self).")},
65917db96d56Sopenharmony_ci
65927db96d56Sopenharmony_ci    {"dst",             (PyCFunction)datetime_dst, METH_NOARGS,
65937db96d56Sopenharmony_ci     PyDoc_STR("Return self.tzinfo.dst(self).")},
65947db96d56Sopenharmony_ci
65957db96d56Sopenharmony_ci    {"replace",     _PyCFunction_CAST(datetime_replace),      METH_VARARGS | METH_KEYWORDS,
65967db96d56Sopenharmony_ci     PyDoc_STR("Return datetime with new specified fields.")},
65977db96d56Sopenharmony_ci
65987db96d56Sopenharmony_ci    {"astimezone",  _PyCFunction_CAST(datetime_astimezone), METH_VARARGS | METH_KEYWORDS,
65997db96d56Sopenharmony_ci     PyDoc_STR("tz -> convert to local time in new timezone tz\n")},
66007db96d56Sopenharmony_ci
66017db96d56Sopenharmony_ci    {"__reduce_ex__", (PyCFunction)datetime_reduce_ex,     METH_VARARGS,
66027db96d56Sopenharmony_ci     PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")},
66037db96d56Sopenharmony_ci
66047db96d56Sopenharmony_ci    {"__reduce__", (PyCFunction)datetime_reduce,     METH_NOARGS,
66057db96d56Sopenharmony_ci     PyDoc_STR("__reduce__() -> (cls, state)")},
66067db96d56Sopenharmony_ci
66077db96d56Sopenharmony_ci    {NULL,      NULL}
66087db96d56Sopenharmony_ci};
66097db96d56Sopenharmony_ci
66107db96d56Sopenharmony_cistatic const char datetime_doc[] =
66117db96d56Sopenharmony_ciPyDoc_STR("datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])\n\
66127db96d56Sopenharmony_ci\n\
66137db96d56Sopenharmony_ciThe year, month and day arguments are required. tzinfo may be None, or an\n\
66147db96d56Sopenharmony_ciinstance of a tzinfo subclass. The remaining arguments may be ints.\n");
66157db96d56Sopenharmony_ci
66167db96d56Sopenharmony_cistatic PyNumberMethods datetime_as_number = {
66177db96d56Sopenharmony_ci    datetime_add,                               /* nb_add */
66187db96d56Sopenharmony_ci    datetime_subtract,                          /* nb_subtract */
66197db96d56Sopenharmony_ci    0,                                          /* nb_multiply */
66207db96d56Sopenharmony_ci    0,                                          /* nb_remainder */
66217db96d56Sopenharmony_ci    0,                                          /* nb_divmod */
66227db96d56Sopenharmony_ci    0,                                          /* nb_power */
66237db96d56Sopenharmony_ci    0,                                          /* nb_negative */
66247db96d56Sopenharmony_ci    0,                                          /* nb_positive */
66257db96d56Sopenharmony_ci    0,                                          /* nb_absolute */
66267db96d56Sopenharmony_ci    0,                                          /* nb_bool */
66277db96d56Sopenharmony_ci};
66287db96d56Sopenharmony_ci
66297db96d56Sopenharmony_cistatic PyTypeObject PyDateTime_DateTimeType = {
66307db96d56Sopenharmony_ci    PyVarObject_HEAD_INIT(NULL, 0)
66317db96d56Sopenharmony_ci    "datetime.datetime",                        /* tp_name */
66327db96d56Sopenharmony_ci    sizeof(PyDateTime_DateTime),                /* tp_basicsize */
66337db96d56Sopenharmony_ci    0,                                          /* tp_itemsize */
66347db96d56Sopenharmony_ci    (destructor)datetime_dealloc,               /* tp_dealloc */
66357db96d56Sopenharmony_ci    0,                                          /* tp_vectorcall_offset */
66367db96d56Sopenharmony_ci    0,                                          /* tp_getattr */
66377db96d56Sopenharmony_ci    0,                                          /* tp_setattr */
66387db96d56Sopenharmony_ci    0,                                          /* tp_as_async */
66397db96d56Sopenharmony_ci    (reprfunc)datetime_repr,                    /* tp_repr */
66407db96d56Sopenharmony_ci    &datetime_as_number,                        /* tp_as_number */
66417db96d56Sopenharmony_ci    0,                                          /* tp_as_sequence */
66427db96d56Sopenharmony_ci    0,                                          /* tp_as_mapping */
66437db96d56Sopenharmony_ci    (hashfunc)datetime_hash,                    /* tp_hash */
66447db96d56Sopenharmony_ci    0,                                          /* tp_call */
66457db96d56Sopenharmony_ci    (reprfunc)datetime_str,                     /* tp_str */
66467db96d56Sopenharmony_ci    PyObject_GenericGetAttr,                    /* tp_getattro */
66477db96d56Sopenharmony_ci    0,                                          /* tp_setattro */
66487db96d56Sopenharmony_ci    0,                                          /* tp_as_buffer */
66497db96d56Sopenharmony_ci    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
66507db96d56Sopenharmony_ci    datetime_doc,                               /* tp_doc */
66517db96d56Sopenharmony_ci    0,                                          /* tp_traverse */
66527db96d56Sopenharmony_ci    0,                                          /* tp_clear */
66537db96d56Sopenharmony_ci    datetime_richcompare,                       /* tp_richcompare */
66547db96d56Sopenharmony_ci    0,                                          /* tp_weaklistoffset */
66557db96d56Sopenharmony_ci    0,                                          /* tp_iter */
66567db96d56Sopenharmony_ci    0,                                          /* tp_iternext */
66577db96d56Sopenharmony_ci    datetime_methods,                           /* tp_methods */
66587db96d56Sopenharmony_ci    0,                                          /* tp_members */
66597db96d56Sopenharmony_ci    datetime_getset,                            /* tp_getset */
66607db96d56Sopenharmony_ci    0,                                          /* tp_base; filled in
66617db96d56Sopenharmony_ci                                                   PyInit__datetime */
66627db96d56Sopenharmony_ci    0,                                          /* tp_dict */
66637db96d56Sopenharmony_ci    0,                                          /* tp_descr_get */
66647db96d56Sopenharmony_ci    0,                                          /* tp_descr_set */
66657db96d56Sopenharmony_ci    0,                                          /* tp_dictoffset */
66667db96d56Sopenharmony_ci    0,                                          /* tp_init */
66677db96d56Sopenharmony_ci    datetime_alloc,                             /* tp_alloc */
66687db96d56Sopenharmony_ci    datetime_new,                               /* tp_new */
66697db96d56Sopenharmony_ci    0,                                          /* tp_free */
66707db96d56Sopenharmony_ci};
66717db96d56Sopenharmony_ci
66727db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
66737db96d56Sopenharmony_ci * Module methods and initialization.
66747db96d56Sopenharmony_ci */
66757db96d56Sopenharmony_ci
66767db96d56Sopenharmony_cistatic PyMethodDef module_methods[] = {
66777db96d56Sopenharmony_ci    {NULL, NULL}
66787db96d56Sopenharmony_ci};
66797db96d56Sopenharmony_ci
66807db96d56Sopenharmony_ci/* Get a new C API by calling this function.
66817db96d56Sopenharmony_ci * Clients get at C API via PyDateTime_IMPORT, defined in datetime.h.
66827db96d56Sopenharmony_ci */
66837db96d56Sopenharmony_cistatic inline PyDateTime_CAPI *
66847db96d56Sopenharmony_ciget_datetime_capi(void)
66857db96d56Sopenharmony_ci{
66867db96d56Sopenharmony_ci    PyDateTime_CAPI *capi = PyMem_Malloc(sizeof(PyDateTime_CAPI));
66877db96d56Sopenharmony_ci    if (capi == NULL) {
66887db96d56Sopenharmony_ci        PyErr_NoMemory();
66897db96d56Sopenharmony_ci        return NULL;
66907db96d56Sopenharmony_ci    }
66917db96d56Sopenharmony_ci    capi->DateType = &PyDateTime_DateType;
66927db96d56Sopenharmony_ci    capi->DateTimeType = &PyDateTime_DateTimeType;
66937db96d56Sopenharmony_ci    capi->TimeType = &PyDateTime_TimeType;
66947db96d56Sopenharmony_ci    capi->DeltaType = &PyDateTime_DeltaType;
66957db96d56Sopenharmony_ci    capi->TZInfoType = &PyDateTime_TZInfoType;
66967db96d56Sopenharmony_ci    capi->Date_FromDate = new_date_ex;
66977db96d56Sopenharmony_ci    capi->DateTime_FromDateAndTime = new_datetime_ex;
66987db96d56Sopenharmony_ci    capi->Time_FromTime = new_time_ex;
66997db96d56Sopenharmony_ci    capi->Delta_FromDelta = new_delta_ex;
67007db96d56Sopenharmony_ci    capi->TimeZone_FromTimeZone = new_timezone;
67017db96d56Sopenharmony_ci    capi->DateTime_FromTimestamp = datetime_fromtimestamp;
67027db96d56Sopenharmony_ci    capi->Date_FromTimestamp = datetime_date_fromtimestamp_capi;
67037db96d56Sopenharmony_ci    capi->DateTime_FromDateAndTimeAndFold = new_datetime_ex2;
67047db96d56Sopenharmony_ci    capi->Time_FromTimeAndFold = new_time_ex2;
67057db96d56Sopenharmony_ci    // Make sure this function is called after PyDateTime_TimeZone_UTC has
67067db96d56Sopenharmony_ci    // been initialized.
67077db96d56Sopenharmony_ci    assert(PyDateTime_TimeZone_UTC != NULL);
67087db96d56Sopenharmony_ci    capi->TimeZone_UTC = PyDateTime_TimeZone_UTC; // borrowed ref
67097db96d56Sopenharmony_ci    return capi;
67107db96d56Sopenharmony_ci}
67117db96d56Sopenharmony_ci
67127db96d56Sopenharmony_cistatic void
67137db96d56Sopenharmony_cidatetime_destructor(PyObject *op)
67147db96d56Sopenharmony_ci{
67157db96d56Sopenharmony_ci    void *ptr = PyCapsule_GetPointer(op, PyDateTime_CAPSULE_NAME);
67167db96d56Sopenharmony_ci    PyMem_Free(ptr);
67177db96d56Sopenharmony_ci}
67187db96d56Sopenharmony_ci
67197db96d56Sopenharmony_cistatic int
67207db96d56Sopenharmony_ci_datetime_exec(PyObject *module)
67217db96d56Sopenharmony_ci{
67227db96d56Sopenharmony_ci    // `&...` is not a constant expression according to a strict reading
67237db96d56Sopenharmony_ci    // of C standards. Fill tp_base at run-time rather than statically.
67247db96d56Sopenharmony_ci    // See https://bugs.python.org/issue40777
67257db96d56Sopenharmony_ci    PyDateTime_IsoCalendarDateType.tp_base = &PyTuple_Type;
67267db96d56Sopenharmony_ci    PyDateTime_TimeZoneType.tp_base = &PyDateTime_TZInfoType;
67277db96d56Sopenharmony_ci    PyDateTime_DateTimeType.tp_base = &PyDateTime_DateType;
67287db96d56Sopenharmony_ci
67297db96d56Sopenharmony_ci    PyTypeObject *types[] = {
67307db96d56Sopenharmony_ci        &PyDateTime_DateType,
67317db96d56Sopenharmony_ci        &PyDateTime_DateTimeType,
67327db96d56Sopenharmony_ci        &PyDateTime_TimeType,
67337db96d56Sopenharmony_ci        &PyDateTime_DeltaType,
67347db96d56Sopenharmony_ci        &PyDateTime_TZInfoType,
67357db96d56Sopenharmony_ci        &PyDateTime_TimeZoneType,
67367db96d56Sopenharmony_ci    };
67377db96d56Sopenharmony_ci
67387db96d56Sopenharmony_ci    for (size_t i = 0; i < Py_ARRAY_LENGTH(types); i++) {
67397db96d56Sopenharmony_ci        if (PyModule_AddType(module, types[i]) < 0) {
67407db96d56Sopenharmony_ci            return -1;
67417db96d56Sopenharmony_ci        }
67427db96d56Sopenharmony_ci    }
67437db96d56Sopenharmony_ci
67447db96d56Sopenharmony_ci    if (PyType_Ready(&PyDateTime_IsoCalendarDateType) < 0) {
67457db96d56Sopenharmony_ci        return -1;
67467db96d56Sopenharmony_ci    }
67477db96d56Sopenharmony_ci
67487db96d56Sopenharmony_ci#define DATETIME_ADD_MACRO(dict, c, value_expr)         \
67497db96d56Sopenharmony_ci    do {                                                \
67507db96d56Sopenharmony_ci        PyObject *value = (value_expr);                 \
67517db96d56Sopenharmony_ci        if (value == NULL) {                            \
67527db96d56Sopenharmony_ci            return -1;                                  \
67537db96d56Sopenharmony_ci        }                                               \
67547db96d56Sopenharmony_ci        if (PyDict_SetItemString(dict, c, value) < 0) { \
67557db96d56Sopenharmony_ci            Py_DECREF(value);                           \
67567db96d56Sopenharmony_ci            return -1;                                  \
67577db96d56Sopenharmony_ci        }                                               \
67587db96d56Sopenharmony_ci        Py_DECREF(value);                               \
67597db96d56Sopenharmony_ci    } while(0)
67607db96d56Sopenharmony_ci
67617db96d56Sopenharmony_ci    /* timedelta values */
67627db96d56Sopenharmony_ci    PyObject *d = PyDateTime_DeltaType.tp_dict;
67637db96d56Sopenharmony_ci    DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
67647db96d56Sopenharmony_ci    DATETIME_ADD_MACRO(d, "min", new_delta(-MAX_DELTA_DAYS, 0, 0, 0));
67657db96d56Sopenharmony_ci    DATETIME_ADD_MACRO(d, "max",
67667db96d56Sopenharmony_ci                       new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0));
67677db96d56Sopenharmony_ci
67687db96d56Sopenharmony_ci    /* date values */
67697db96d56Sopenharmony_ci    d = PyDateTime_DateType.tp_dict;
67707db96d56Sopenharmony_ci    DATETIME_ADD_MACRO(d, "min", new_date(1, 1, 1));
67717db96d56Sopenharmony_ci    DATETIME_ADD_MACRO(d, "max", new_date(MAXYEAR, 12, 31));
67727db96d56Sopenharmony_ci    DATETIME_ADD_MACRO(d, "resolution", new_delta(1, 0, 0, 0));
67737db96d56Sopenharmony_ci
67747db96d56Sopenharmony_ci    /* time values */
67757db96d56Sopenharmony_ci    d = PyDateTime_TimeType.tp_dict;
67767db96d56Sopenharmony_ci    DATETIME_ADD_MACRO(d, "min", new_time(0, 0, 0, 0, Py_None, 0));
67777db96d56Sopenharmony_ci    DATETIME_ADD_MACRO(d, "max", new_time(23, 59, 59, 999999, Py_None, 0));
67787db96d56Sopenharmony_ci    DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
67797db96d56Sopenharmony_ci
67807db96d56Sopenharmony_ci    /* datetime values */
67817db96d56Sopenharmony_ci    d = PyDateTime_DateTimeType.tp_dict;
67827db96d56Sopenharmony_ci    DATETIME_ADD_MACRO(d, "min",
67837db96d56Sopenharmony_ci                       new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None, 0));
67847db96d56Sopenharmony_ci    DATETIME_ADD_MACRO(d, "max", new_datetime(MAXYEAR, 12, 31, 23, 59, 59,
67857db96d56Sopenharmony_ci                                              999999, Py_None, 0));
67867db96d56Sopenharmony_ci    DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
67877db96d56Sopenharmony_ci
67887db96d56Sopenharmony_ci    /* timezone values */
67897db96d56Sopenharmony_ci    d = PyDateTime_TimeZoneType.tp_dict;
67907db96d56Sopenharmony_ci    PyObject *delta = new_delta(0, 0, 0, 0);
67917db96d56Sopenharmony_ci    if (delta == NULL) {
67927db96d56Sopenharmony_ci        return -1;
67937db96d56Sopenharmony_ci    }
67947db96d56Sopenharmony_ci
67957db96d56Sopenharmony_ci    PyObject *x = create_timezone(delta, NULL);
67967db96d56Sopenharmony_ci    Py_DECREF(delta);
67977db96d56Sopenharmony_ci    if (x == NULL) {
67987db96d56Sopenharmony_ci        return -1;
67997db96d56Sopenharmony_ci    }
68007db96d56Sopenharmony_ci    if (PyDict_SetItemString(d, "utc", x) < 0) {
68017db96d56Sopenharmony_ci        Py_DECREF(x);
68027db96d56Sopenharmony_ci        return -1;
68037db96d56Sopenharmony_ci    }
68047db96d56Sopenharmony_ci
68057db96d56Sopenharmony_ci    PyDateTime_TimeZone_UTC = x;
68067db96d56Sopenharmony_ci
68077db96d56Sopenharmony_ci    /* bpo-37642: These attributes are rounded to the nearest minute for backwards
68087db96d56Sopenharmony_ci     * compatibility, even though the constructor will accept a wider range of
68097db96d56Sopenharmony_ci     * values. This may change in the future.*/
68107db96d56Sopenharmony_ci    delta = new_delta(-1, 60, 0, 1); /* -23:59 */
68117db96d56Sopenharmony_ci    if (delta == NULL) {
68127db96d56Sopenharmony_ci        return -1;
68137db96d56Sopenharmony_ci    }
68147db96d56Sopenharmony_ci
68157db96d56Sopenharmony_ci    x = create_timezone(delta, NULL);
68167db96d56Sopenharmony_ci    Py_DECREF(delta);
68177db96d56Sopenharmony_ci    DATETIME_ADD_MACRO(d, "min", x);
68187db96d56Sopenharmony_ci
68197db96d56Sopenharmony_ci    delta = new_delta(0, (23 * 60 + 59) * 60, 0, 0); /* +23:59 */
68207db96d56Sopenharmony_ci    if (delta == NULL) {
68217db96d56Sopenharmony_ci        return -1;
68227db96d56Sopenharmony_ci    }
68237db96d56Sopenharmony_ci
68247db96d56Sopenharmony_ci    x = create_timezone(delta, NULL);
68257db96d56Sopenharmony_ci    Py_DECREF(delta);
68267db96d56Sopenharmony_ci    DATETIME_ADD_MACRO(d, "max", x);
68277db96d56Sopenharmony_ci
68287db96d56Sopenharmony_ci    /* Epoch */
68297db96d56Sopenharmony_ci    PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0,
68307db96d56Sopenharmony_ci                                    PyDateTime_TimeZone_UTC, 0);
68317db96d56Sopenharmony_ci    if (PyDateTime_Epoch == NULL) {
68327db96d56Sopenharmony_ci        return -1;
68337db96d56Sopenharmony_ci    }
68347db96d56Sopenharmony_ci
68357db96d56Sopenharmony_ci    /* module initialization */
68367db96d56Sopenharmony_ci    if (PyModule_AddIntMacro(module, MINYEAR) < 0) {
68377db96d56Sopenharmony_ci        return -1;
68387db96d56Sopenharmony_ci    }
68397db96d56Sopenharmony_ci    if (PyModule_AddIntMacro(module, MAXYEAR) < 0) {
68407db96d56Sopenharmony_ci        return -1;
68417db96d56Sopenharmony_ci    }
68427db96d56Sopenharmony_ci
68437db96d56Sopenharmony_ci    PyDateTime_CAPI *capi = get_datetime_capi();
68447db96d56Sopenharmony_ci    if (capi == NULL) {
68457db96d56Sopenharmony_ci        return -1;
68467db96d56Sopenharmony_ci    }
68477db96d56Sopenharmony_ci    x = PyCapsule_New(capi, PyDateTime_CAPSULE_NAME, datetime_destructor);
68487db96d56Sopenharmony_ci    if (x == NULL) {
68497db96d56Sopenharmony_ci        PyMem_Free(capi);
68507db96d56Sopenharmony_ci        return -1;
68517db96d56Sopenharmony_ci    }
68527db96d56Sopenharmony_ci
68537db96d56Sopenharmony_ci    if (PyModule_AddObject(module, "datetime_CAPI", x) < 0) {
68547db96d56Sopenharmony_ci        Py_DECREF(x);
68557db96d56Sopenharmony_ci        return -1;
68567db96d56Sopenharmony_ci    }
68577db96d56Sopenharmony_ci
68587db96d56Sopenharmony_ci    if (PyModule_AddObjectRef(module, "UTC", PyDateTime_TimeZone_UTC) < 0) {
68597db96d56Sopenharmony_ci        return -1;
68607db96d56Sopenharmony_ci    }
68617db96d56Sopenharmony_ci
68627db96d56Sopenharmony_ci    /* A 4-year cycle has an extra leap day over what we'd get from
68637db96d56Sopenharmony_ci     * pasting together 4 single years.
68647db96d56Sopenharmony_ci     */
68657db96d56Sopenharmony_ci    static_assert(DI4Y == 4 * 365 + 1, "DI4Y");
68667db96d56Sopenharmony_ci    assert(DI4Y == days_before_year(4+1));
68677db96d56Sopenharmony_ci
68687db96d56Sopenharmony_ci    /* Similarly, a 400-year cycle has an extra leap day over what we'd
68697db96d56Sopenharmony_ci     * get from pasting together 4 100-year cycles.
68707db96d56Sopenharmony_ci     */
68717db96d56Sopenharmony_ci    static_assert(DI400Y == 4 * DI100Y + 1, "DI400Y");
68727db96d56Sopenharmony_ci    assert(DI400Y == days_before_year(400+1));
68737db96d56Sopenharmony_ci
68747db96d56Sopenharmony_ci    /* OTOH, a 100-year cycle has one fewer leap day than we'd get from
68757db96d56Sopenharmony_ci     * pasting together 25 4-year cycles.
68767db96d56Sopenharmony_ci     */
68777db96d56Sopenharmony_ci    static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y");
68787db96d56Sopenharmony_ci    assert(DI100Y == days_before_year(100+1));
68797db96d56Sopenharmony_ci
68807db96d56Sopenharmony_ci    us_per_ms = PyLong_FromLong(1000);
68817db96d56Sopenharmony_ci    us_per_second = PyLong_FromLong(1000000);
68827db96d56Sopenharmony_ci    us_per_minute = PyLong_FromLong(60000000);
68837db96d56Sopenharmony_ci    seconds_per_day = PyLong_FromLong(24 * 3600);
68847db96d56Sopenharmony_ci    if (us_per_ms == NULL || us_per_second == NULL ||
68857db96d56Sopenharmony_ci        us_per_minute == NULL || seconds_per_day == NULL) {
68867db96d56Sopenharmony_ci        return -1;
68877db96d56Sopenharmony_ci    }
68887db96d56Sopenharmony_ci
68897db96d56Sopenharmony_ci    /* The rest are too big for 32-bit ints, but even
68907db96d56Sopenharmony_ci     * us_per_week fits in 40 bits, so doubles should be exact.
68917db96d56Sopenharmony_ci     */
68927db96d56Sopenharmony_ci    us_per_hour = PyLong_FromDouble(3600000000.0);
68937db96d56Sopenharmony_ci    us_per_day = PyLong_FromDouble(86400000000.0);
68947db96d56Sopenharmony_ci    us_per_week = PyLong_FromDouble(604800000000.0);
68957db96d56Sopenharmony_ci    if (us_per_hour == NULL || us_per_day == NULL || us_per_week == NULL) {
68967db96d56Sopenharmony_ci        return -1;
68977db96d56Sopenharmony_ci    }
68987db96d56Sopenharmony_ci    return 0;
68997db96d56Sopenharmony_ci}
69007db96d56Sopenharmony_ci
69017db96d56Sopenharmony_cistatic struct PyModuleDef datetimemodule = {
69027db96d56Sopenharmony_ci    PyModuleDef_HEAD_INIT,
69037db96d56Sopenharmony_ci    .m_name = "_datetime",
69047db96d56Sopenharmony_ci    .m_doc = "Fast implementation of the datetime type.",
69057db96d56Sopenharmony_ci    .m_size = -1,
69067db96d56Sopenharmony_ci    .m_methods = module_methods,
69077db96d56Sopenharmony_ci};
69087db96d56Sopenharmony_ci
69097db96d56Sopenharmony_ciPyMODINIT_FUNC
69107db96d56Sopenharmony_ciPyInit__datetime(void)
69117db96d56Sopenharmony_ci{
69127db96d56Sopenharmony_ci    PyObject *mod = PyModule_Create(&datetimemodule);
69137db96d56Sopenharmony_ci    if (mod == NULL)
69147db96d56Sopenharmony_ci        return NULL;
69157db96d56Sopenharmony_ci
69167db96d56Sopenharmony_ci    if (_datetime_exec(mod) < 0) {
69177db96d56Sopenharmony_ci        Py_DECREF(mod);
69187db96d56Sopenharmony_ci        return NULL;
69197db96d56Sopenharmony_ci    }
69207db96d56Sopenharmony_ci
69217db96d56Sopenharmony_ci    return mod;
69227db96d56Sopenharmony_ci}
69237db96d56Sopenharmony_ci
69247db96d56Sopenharmony_ci/* ---------------------------------------------------------------------------
69257db96d56Sopenharmony_ciSome time zone algebra.  For a datetime x, let
69267db96d56Sopenharmony_ci    x.n = x stripped of its timezone -- its naive time.
69277db96d56Sopenharmony_ci    x.o = x.utcoffset(), and assuming that doesn't raise an exception or
69287db96d56Sopenharmony_ci      return None
69297db96d56Sopenharmony_ci    x.d = x.dst(), and assuming that doesn't raise an exception or
69307db96d56Sopenharmony_ci      return None
69317db96d56Sopenharmony_ci    x.s = x's standard offset, x.o - x.d
69327db96d56Sopenharmony_ci
69337db96d56Sopenharmony_ciNow some derived rules, where k is a duration (timedelta).
69347db96d56Sopenharmony_ci
69357db96d56Sopenharmony_ci1. x.o = x.s + x.d
69367db96d56Sopenharmony_ci   This follows from the definition of x.s.
69377db96d56Sopenharmony_ci
69387db96d56Sopenharmony_ci2. If x and y have the same tzinfo member, x.s = y.s.
69397db96d56Sopenharmony_ci   This is actually a requirement, an assumption we need to make about
69407db96d56Sopenharmony_ci   sane tzinfo classes.
69417db96d56Sopenharmony_ci
69427db96d56Sopenharmony_ci3. The naive UTC time corresponding to x is x.n - x.o.
69437db96d56Sopenharmony_ci   This is again a requirement for a sane tzinfo class.
69447db96d56Sopenharmony_ci
69457db96d56Sopenharmony_ci4. (x+k).s = x.s
69467db96d56Sopenharmony_ci   This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
69477db96d56Sopenharmony_ci
69487db96d56Sopenharmony_ci5. (x+k).n = x.n + k
69497db96d56Sopenharmony_ci   Again follows from how arithmetic is defined.
69507db96d56Sopenharmony_ci
69517db96d56Sopenharmony_ciNow we can explain tz.fromutc(x).  Let's assume it's an interesting case
69527db96d56Sopenharmony_ci(meaning that the various tzinfo methods exist, and don't blow up or return
69537db96d56Sopenharmony_ciNone when called).
69547db96d56Sopenharmony_ci
69557db96d56Sopenharmony_ciThe function wants to return a datetime y with timezone tz, equivalent to x.
69567db96d56Sopenharmony_cix is already in UTC.
69577db96d56Sopenharmony_ci
69587db96d56Sopenharmony_ciBy #3, we want
69597db96d56Sopenharmony_ci
69607db96d56Sopenharmony_ci    y.n - y.o = x.n                             [1]
69617db96d56Sopenharmony_ci
69627db96d56Sopenharmony_ciThe algorithm starts by attaching tz to x.n, and calling that y.  So
69637db96d56Sopenharmony_cix.n = y.n at the start.  Then it wants to add a duration k to y, so that [1]
69647db96d56Sopenharmony_cibecomes true; in effect, we want to solve [2] for k:
69657db96d56Sopenharmony_ci
69667db96d56Sopenharmony_ci   (y+k).n - (y+k).o = x.n                      [2]
69677db96d56Sopenharmony_ci
69687db96d56Sopenharmony_ciBy #1, this is the same as
69697db96d56Sopenharmony_ci
69707db96d56Sopenharmony_ci   (y+k).n - ((y+k).s + (y+k).d) = x.n          [3]
69717db96d56Sopenharmony_ci
69727db96d56Sopenharmony_ciBy #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start.
69737db96d56Sopenharmony_ciSubstituting that into [3],
69747db96d56Sopenharmony_ci
69757db96d56Sopenharmony_ci   x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving
69767db96d56Sopenharmony_ci   k - (y+k).s - (y+k).d = 0; rearranging,
69777db96d56Sopenharmony_ci   k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so
69787db96d56Sopenharmony_ci   k = y.s - (y+k).d
69797db96d56Sopenharmony_ci
69807db96d56Sopenharmony_ciOn the RHS, (y+k).d can't be computed directly, but y.s can be, and we
69817db96d56Sopenharmony_ciapproximate k by ignoring the (y+k).d term at first.  Note that k can't be
69827db96d56Sopenharmony_civery large, since all offset-returning methods return a duration of magnitude
69837db96d56Sopenharmony_ciless than 24 hours.  For that reason, if y is firmly in std time, (y+k).d must
69847db96d56Sopenharmony_cibe 0, so ignoring it has no consequence then.
69857db96d56Sopenharmony_ci
69867db96d56Sopenharmony_ciIn any case, the new value is
69877db96d56Sopenharmony_ci
69887db96d56Sopenharmony_ci    z = y + y.s                                 [4]
69897db96d56Sopenharmony_ci
69907db96d56Sopenharmony_ciIt's helpful to step back at look at [4] from a higher level:  it's simply
69917db96d56Sopenharmony_cimapping from UTC to tz's standard time.
69927db96d56Sopenharmony_ci
69937db96d56Sopenharmony_ciAt this point, if
69947db96d56Sopenharmony_ci
69957db96d56Sopenharmony_ci    z.n - z.o = x.n                             [5]
69967db96d56Sopenharmony_ci
69977db96d56Sopenharmony_ciwe have an equivalent time, and are almost done.  The insecurity here is
69987db96d56Sopenharmony_ciat the start of daylight time.  Picture US Eastern for concreteness.  The wall
69997db96d56Sopenharmony_citime jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good
70007db96d56Sopenharmony_cisense then.  The docs ask that an Eastern tzinfo class consider such a time to
70017db96d56Sopenharmony_cibe EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST
70027db96d56Sopenharmony_cion the day DST starts.  We want to return the 1:MM EST spelling because that's
70037db96d56Sopenharmony_cithe only spelling that makes sense on the local wall clock.
70047db96d56Sopenharmony_ci
70057db96d56Sopenharmony_ciIn fact, if [5] holds at this point, we do have the standard-time spelling,
70067db96d56Sopenharmony_cibut that takes a bit of proof.  We first prove a stronger result.  What's the
70077db96d56Sopenharmony_cidifference between the LHS and RHS of [5]?  Let
70087db96d56Sopenharmony_ci
70097db96d56Sopenharmony_ci    diff = x.n - (z.n - z.o)                    [6]
70107db96d56Sopenharmony_ci
70117db96d56Sopenharmony_ciNow
70127db96d56Sopenharmony_ci    z.n =                       by [4]
70137db96d56Sopenharmony_ci    (y + y.s).n =               by #5
70147db96d56Sopenharmony_ci    y.n + y.s =                 since y.n = x.n
70157db96d56Sopenharmony_ci    x.n + y.s =                 since z and y are have the same tzinfo member,
70167db96d56Sopenharmony_ci                                    y.s = z.s by #2
70177db96d56Sopenharmony_ci    x.n + z.s
70187db96d56Sopenharmony_ci
70197db96d56Sopenharmony_ciPlugging that back into [6] gives
70207db96d56Sopenharmony_ci
70217db96d56Sopenharmony_ci    diff =
70227db96d56Sopenharmony_ci    x.n - ((x.n + z.s) - z.o) =     expanding
70237db96d56Sopenharmony_ci    x.n - x.n - z.s + z.o =         cancelling
70247db96d56Sopenharmony_ci    - z.s + z.o =                   by #2
70257db96d56Sopenharmony_ci    z.d
70267db96d56Sopenharmony_ci
70277db96d56Sopenharmony_ciSo diff = z.d.
70287db96d56Sopenharmony_ci
70297db96d56Sopenharmony_ciIf [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time
70307db96d56Sopenharmony_cispelling we wanted in the endcase described above.  We're done.  Contrarily,
70317db96d56Sopenharmony_ciif z.d = 0, then we have a UTC equivalent, and are also done.
70327db96d56Sopenharmony_ci
70337db96d56Sopenharmony_ciIf [5] is not true now, diff = z.d != 0, and z.d is the offset we need to
70347db96d56Sopenharmony_ciadd to z (in effect, z is in tz's standard time, and we need to shift the
70357db96d56Sopenharmony_cilocal clock into tz's daylight time).
70367db96d56Sopenharmony_ci
70377db96d56Sopenharmony_ciLet
70387db96d56Sopenharmony_ci
70397db96d56Sopenharmony_ci    z' = z + z.d = z + diff                     [7]
70407db96d56Sopenharmony_ci
70417db96d56Sopenharmony_ciand we can again ask whether
70427db96d56Sopenharmony_ci
70437db96d56Sopenharmony_ci    z'.n - z'.o = x.n                           [8]
70447db96d56Sopenharmony_ci
70457db96d56Sopenharmony_ciIf so, we're done.  If not, the tzinfo class is insane, according to the
70467db96d56Sopenharmony_ciassumptions we've made.  This also requires a bit of proof.  As before, let's
70477db96d56Sopenharmony_cicompute the difference between the LHS and RHS of [8] (and skipping some of
70487db96d56Sopenharmony_cithe justifications for the kinds of substitutions we've done several times
70497db96d56Sopenharmony_cialready):
70507db96d56Sopenharmony_ci
70517db96d56Sopenharmony_ci    diff' = x.n - (z'.n - z'.o) =           replacing z'.n via [7]
70527db96d56Sopenharmony_ci        x.n  - (z.n + diff - z'.o) =    replacing diff via [6]
70537db96d56Sopenharmony_ci        x.n - (z.n + x.n - (z.n - z.o) - z'.o) =
70547db96d56Sopenharmony_ci        x.n - z.n - x.n + z.n - z.o + z'.o =    cancel x.n
70557db96d56Sopenharmony_ci        - z.n + z.n - z.o + z'.o =              cancel z.n
70567db96d56Sopenharmony_ci        - z.o + z'.o =                      #1 twice
70577db96d56Sopenharmony_ci        -z.s - z.d + z'.s + z'.d =          z and z' have same tzinfo
70587db96d56Sopenharmony_ci        z'.d - z.d
70597db96d56Sopenharmony_ci
70607db96d56Sopenharmony_ciSo z' is UTC-equivalent to x iff z'.d = z.d at this point.  If they are equal,
70617db96d56Sopenharmony_ciwe've found the UTC-equivalent so are done.  In fact, we stop with [7] and
70627db96d56Sopenharmony_cireturn z', not bothering to compute z'.d.
70637db96d56Sopenharmony_ci
70647db96d56Sopenharmony_ciHow could z.d and z'd differ?  z' = z + z.d [7], so merely moving z' by
70657db96d56Sopenharmony_cia dst() offset, and starting *from* a time already in DST (we know z.d != 0),
70667db96d56Sopenharmony_ciwould have to change the result dst() returns:  we start in DST, and moving
70677db96d56Sopenharmony_cia little further into it takes us out of DST.
70687db96d56Sopenharmony_ci
70697db96d56Sopenharmony_ciThere isn't a sane case where this can happen.  The closest it gets is at
70707db96d56Sopenharmony_cithe end of DST, where there's an hour in UTC with no spelling in a hybrid
70717db96d56Sopenharmony_citzinfo class.  In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT.  During
70727db96d56Sopenharmony_cithat hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM
70737db96d56Sopenharmony_ciUTC) because the docs insist on that, but 0:MM is taken as being in daylight
70747db96d56Sopenharmony_citime (4:MM UTC).  There is no local time mapping to 5:MM UTC.  The local
70757db96d56Sopenharmony_ciclock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in
70767db96d56Sopenharmony_cistandard time.  Since that's what the local clock *does*, we want to map both
70777db96d56Sopenharmony_ciUTC hours 5:MM and 6:MM to 1:MM Eastern.  The result is ambiguous
70787db96d56Sopenharmony_ciin local time, but so it goes -- it's the way the local clock works.
70797db96d56Sopenharmony_ci
70807db96d56Sopenharmony_ciWhen x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0,
70817db96d56Sopenharmony_ciso z=0:MM.  z.d=60 (minutes) then, so [5] doesn't hold and we keep going.
70827db96d56Sopenharmony_ciz' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8]
70837db96d56Sopenharmony_ci(correctly) concludes that z' is not UTC-equivalent to x.
70847db96d56Sopenharmony_ci
70857db96d56Sopenharmony_ciBecause we know z.d said z was in daylight time (else [5] would have held and
70867db96d56Sopenharmony_ciwe would have stopped then), and we know z.d != z'.d (else [8] would have held
70877db96d56Sopenharmony_ciand we would have stopped then), and there are only 2 possible values dst() can
70887db96d56Sopenharmony_cireturn in Eastern, it follows that z'.d must be 0 (which it is in the example,
70897db96d56Sopenharmony_cibut the reasoning doesn't depend on the example -- it depends on there being
70907db96d56Sopenharmony_citwo possible dst() outcomes, one zero and the other non-zero).  Therefore
70917db96d56Sopenharmony_ciz' must be in standard time, and is the spelling we want in this case.
70927db96d56Sopenharmony_ci
70937db96d56Sopenharmony_ciNote again that z' is not UTC-equivalent as far as the hybrid tzinfo class is
70947db96d56Sopenharmony_ciconcerned (because it takes z' as being in standard time rather than the
70957db96d56Sopenharmony_cidaylight time we intend here), but returning it gives the real-life "local
70967db96d56Sopenharmony_ciclock repeats an hour" behavior when mapping the "unspellable" UTC hour into
70977db96d56Sopenharmony_citz.
70987db96d56Sopenharmony_ci
70997db96d56Sopenharmony_ciWhen the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with
71007db96d56Sopenharmony_cithe 1:MM standard time spelling we want.
71017db96d56Sopenharmony_ci
71027db96d56Sopenharmony_ciSo how can this break?  One of the assumptions must be violated.  Two
71037db96d56Sopenharmony_cipossibilities:
71047db96d56Sopenharmony_ci
71057db96d56Sopenharmony_ci1) [2] effectively says that y.s is invariant across all y belong to a given
71067db96d56Sopenharmony_ci   time zone.  This isn't true if, for political reasons or continental drift,
71077db96d56Sopenharmony_ci   a region decides to change its base offset from UTC.
71087db96d56Sopenharmony_ci
71097db96d56Sopenharmony_ci2) There may be versions of "double daylight" time where the tail end of
71107db96d56Sopenharmony_ci   the analysis gives up a step too early.  I haven't thought about that
71117db96d56Sopenharmony_ci   enough to say.
71127db96d56Sopenharmony_ci
71137db96d56Sopenharmony_ciIn any case, it's clear that the default fromutc() is strong enough to handle
71147db96d56Sopenharmony_ci"almost all" time zones:  so long as the standard offset is invariant, it
71157db96d56Sopenharmony_cidoesn't matter if daylight time transition points change from year to year, or
71167db96d56Sopenharmony_ciif daylight time is skipped in some years; it doesn't matter how large or
71177db96d56Sopenharmony_cismall dst() may get within its bounds; and it doesn't even matter if some
71187db96d56Sopenharmony_ciperverse time zone returns a negative dst()).  So a breaking case must be
71197db96d56Sopenharmony_cipretty bizarre, and a tzinfo subclass can override fromutc() if it is.
71207db96d56Sopenharmony_ci--------------------------------------------------------------------------- */
7121