summaryrefslogtreecommitdiff
path: root/Modules/_datetimemodule.c
diff options
context:
space:
mode:
authorMariatta Wijaya <mariatta.wijaya@gmail.com>2017-02-06 20:16:58 -0800
committerMariatta Wijaya <mariatta.wijaya@gmail.com>2017-02-06 20:16:58 -0800
commitda79bcf8ac7ae72218ab023e1ed54390bc1a3a27 (patch)
tree74845e2dbd9521d9748b9c32f1922f4123083bf3 /Modules/_datetimemodule.c
parente3c7e835bdfc97750eb9b7fc0ad2493108c2d438 (diff)
parent1fe806ac56f8b83694d24ab604eb695d00bc8497 (diff)
downloadcpython-da79bcf8ac7ae72218ab023e1ed54390bc1a3a27.tar.gz
Issue #29371: merge with 3.5
Diffstat (limited to 'Modules/_datetimemodule.c')
-rw-r--r--Modules/_datetimemodule.c1075
1 files changed, 743 insertions, 332 deletions
diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c
index f419cb22ef..291920dc0f 100644
--- a/Modules/_datetimemodule.c
+++ b/Modules/_datetimemodule.c
@@ -56,6 +56,7 @@ class datetime.datetime "PyDateTime_DateTime *" "&PyDateTime_DateTimeType"
#define DATE_GET_MINUTE PyDateTime_DATE_GET_MINUTE
#define DATE_GET_SECOND PyDateTime_DATE_GET_SECOND
#define DATE_GET_MICROSECOND PyDateTime_DATE_GET_MICROSECOND
+#define DATE_GET_FOLD PyDateTime_DATE_GET_FOLD
/* Date accessors for date and datetime. */
#define SET_YEAR(o, v) (((o)->data[0] = ((v) & 0xff00) >> 8), \
@@ -71,12 +72,14 @@ class datetime.datetime "PyDateTime_DateTime *" "&PyDateTime_DateTimeType"
(((o)->data[7] = ((v) & 0xff0000) >> 16), \
((o)->data[8] = ((v) & 0x00ff00) >> 8), \
((o)->data[9] = ((v) & 0x0000ff)))
+#define DATE_SET_FOLD(o, v) (PyDateTime_DATE_GET_FOLD(o) = (v))
/* Time accessors for time. */
#define TIME_GET_HOUR PyDateTime_TIME_GET_HOUR
#define TIME_GET_MINUTE PyDateTime_TIME_GET_MINUTE
#define TIME_GET_SECOND PyDateTime_TIME_GET_SECOND
#define TIME_GET_MICROSECOND PyDateTime_TIME_GET_MICROSECOND
+#define TIME_GET_FOLD PyDateTime_TIME_GET_FOLD
#define TIME_SET_HOUR(o, v) (PyDateTime_TIME_GET_HOUR(o) = (v))
#define TIME_SET_MINUTE(o, v) (PyDateTime_TIME_GET_MINUTE(o) = (v))
#define TIME_SET_SECOND(o, v) (PyDateTime_TIME_GET_SECOND(o) = (v))
@@ -84,6 +87,7 @@ class datetime.datetime "PyDateTime_DateTime *" "&PyDateTime_DateTimeType"
(((o)->data[3] = ((v) & 0xff0000) >> 16), \
((o)->data[4] = ((v) & 0x00ff00) >> 8), \
((o)->data[5] = ((v) & 0x0000ff)))
+#define TIME_SET_FOLD(o, v) (PyDateTime_TIME_GET_FOLD(o) = (v))
/* Delta accessors for timedelta. */
#define GET_TD_DAYS(o) (((PyDateTime_Delta *)(o))->days)
@@ -184,12 +188,12 @@ divide_nearest(PyObject *m, PyObject *n)
* and the number of days before that month in the same year. These
* are correct for non-leap years only.
*/
-static int _days_in_month[] = {
+static const int _days_in_month[] = {
0, /* unused; this vector uses 1-based indexing */
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
-static int _days_before_month[] = {
+static const int _days_before_month[] = {
0, /* unused; this vector uses 1-based indexing */
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
};
@@ -417,7 +421,7 @@ check_date_args(int year, int month, int day)
* aren't, raise ValueError and return -1.
*/
static int
-check_time_args(int h, int m, int s, int us)
+check_time_args(int h, int m, int s, int us, int fold)
{
if (h < 0 || h > 23) {
PyErr_SetString(PyExc_ValueError,
@@ -439,6 +443,11 @@ check_time_args(int h, int m, int s, int us)
"microsecond must be in 0..999999");
return -1;
}
+ if (fold != 0 && fold != 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "fold must be either 0 or 1");
+ return -1;
+ }
return 0;
}
@@ -674,8 +683,8 @@ new_date_ex(int year, int month, int day, PyTypeObject *type)
/* Create a datetime instance with no range checking. */
static PyObject *
-new_datetime_ex(int year, int month, int day, int hour, int minute,
- int second, int usecond, PyObject *tzinfo, PyTypeObject *type)
+new_datetime_ex2(int year, int month, int day, int hour, int minute,
+ int second, int usecond, PyObject *tzinfo, int fold, PyTypeObject *type)
{
PyDateTime_DateTime *self;
char aware = tzinfo != Py_None;
@@ -692,18 +701,27 @@ new_datetime_ex(int year, int month, int day, int hour, int minute,
Py_INCREF(tzinfo);
self->tzinfo = tzinfo;
}
+ DATE_SET_FOLD(self, fold);
}
return (PyObject *)self;
}
-#define new_datetime(y, m, d, hh, mm, ss, us, tzinfo) \
- new_datetime_ex(y, m, d, hh, mm, ss, us, tzinfo, \
+static PyObject *
+new_datetime_ex(int year, int month, int day, int hour, int minute,
+ int second, int usecond, PyObject *tzinfo, PyTypeObject *type)
+{
+ return new_datetime_ex2(year, month, day, hour, minute, second, usecond,
+ tzinfo, 0, type);
+}
+
+#define new_datetime(y, m, d, hh, mm, ss, us, tzinfo, fold) \
+ new_datetime_ex2(y, m, d, hh, mm, ss, us, tzinfo, fold, \
&PyDateTime_DateTimeType)
/* Create a time instance with no range checking. */
static PyObject *
-new_time_ex(int hour, int minute, int second, int usecond,
- PyObject *tzinfo, PyTypeObject *type)
+new_time_ex2(int hour, int minute, int second, int usecond,
+ PyObject *tzinfo, int fold, PyTypeObject *type)
{
PyDateTime_Time *self;
char aware = tzinfo != Py_None;
@@ -720,12 +738,20 @@ new_time_ex(int hour, int minute, int second, int usecond,
Py_INCREF(tzinfo);
self->tzinfo = tzinfo;
}
+ TIME_SET_FOLD(self, fold);
}
return (PyObject *)self;
}
-#define new_time(hh, mm, ss, us, tzinfo) \
- new_time_ex(hh, mm, ss, us, tzinfo, &PyDateTime_TimeType)
+static PyObject *
+new_time_ex(int hour, int minute, int second, int usecond,
+ PyObject *tzinfo, PyTypeObject *type)
+{
+ return new_time_ex2(hour, minute, second, usecond, tzinfo, 0, type);
+}
+
+#define new_time(hh, mm, ss, us, tzinfo, fold) \
+ new_time_ex2(hh, mm, ss, us, tzinfo, fold, &PyDateTime_TimeType)
/* Create a timedelta instance. Normalize the members iff normalize is
* true. Passing false is a speed optimization, if you know for sure
@@ -873,7 +899,7 @@ get_tzinfo_member(PyObject *self)
* this returns NULL. Else result is returned.
*/
static PyObject *
-call_tzinfo_method(PyObject *tzinfo, char *name, PyObject *tzinfoarg)
+call_tzinfo_method(PyObject *tzinfo, const char *name, PyObject *tzinfoarg)
{
PyObject *offset;
@@ -887,10 +913,10 @@ call_tzinfo_method(PyObject *tzinfo, char *name, PyObject *tzinfoarg)
if (offset == Py_None || offset == NULL)
return offset;
if (PyDelta_Check(offset)) {
- if (GET_TD_MICROSECONDS(offset) != 0 || GET_TD_SECONDS(offset) % 60 != 0) {
+ if (GET_TD_MICROSECONDS(offset) != 0) {
Py_DECREF(offset);
PyErr_Format(PyExc_ValueError, "offset must be a timedelta"
- " representing a whole number of minutes");
+ " representing a whole number of seconds");
return NULL;
}
if ((GET_TD_DAYS(offset) == -1 && GET_TD_SECONDS(offset) == 0) ||
@@ -1002,6 +1028,30 @@ append_keyword_tzinfo(PyObject *repr, PyObject *tzinfo)
return repr;
}
+/* repr is like "someclass(arg1, arg2)". If fold isn't 0,
+ * stuff
+ * ", fold=" + repr(tzinfo)
+ * before the closing ")".
+ */
+static PyObject *
+append_keyword_fold(PyObject *repr, int fold)
+{
+ PyObject *temp;
+
+ assert(PyUnicode_Check(repr));
+ if (fold == 0)
+ return repr;
+ /* Get rid of the trailing ')'. */
+ assert(PyUnicode_READ_CHAR(repr, PyUnicode_GET_LENGTH(repr)-1) == ')');
+ temp = PyUnicode_Substring(repr, 0, PyUnicode_GET_LENGTH(repr) - 1);
+ Py_DECREF(repr);
+ if (temp == NULL)
+ return NULL;
+ repr = PyUnicode_FromFormat("%U, fold=%d)", temp, fold);
+ Py_DECREF(temp);
+ return repr;
+}
+
/* ---------------------------------------------------------------------------
* String format helpers.
*/
@@ -1009,10 +1059,10 @@ append_keyword_tzinfo(PyObject *repr, PyObject *tzinfo)
static PyObject *
format_ctime(PyDateTime_Date *date, int hours, int minutes, int seconds)
{
- static const char *DayNames[] = {
+ static const char * const DayNames[] = {
"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
};
- static const char *MonthNames[] = {
+ static const char * const MonthNames[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
@@ -1057,10 +1107,8 @@ format_utcoffset(char *buf, size_t buflen, const char *sep,
}
/* Offset is normalized, so it is negative if days < 0 */
if (GET_TD_DAYS(offset) < 0) {
- PyObject *temp = offset;
sign = '-';
- offset = delta_negative((PyDateTime_Delta *)offset);
- Py_DECREF(temp);
+ Py_SETREF(offset, delta_negative((PyDateTime_Delta *)offset));
if (offset == NULL)
return -1;
}
@@ -1072,10 +1120,11 @@ format_utcoffset(char *buf, size_t buflen, const char *sep,
Py_DECREF(offset);
minutes = divmod(seconds, 60, &seconds);
hours = divmod(minutes, 60, &minutes);
- assert(seconds == 0);
- /* XXX ignore sub-minute data, currently not allowed. */
- PyOS_snprintf(buf, buflen, "%c%02d%s%02d", sign, hours, sep, minutes);
-
+ if (seconds == 0)
+ PyOS_snprintf(buf, buflen, "%c%02d%s%02d", sign, hours, sep, minutes);
+ else
+ PyOS_snprintf(buf, buflen, "%c%02d%s%02d%s%02d", sign, hours,
+ sep, minutes, sep, seconds);
return 0;
}
@@ -1170,7 +1219,7 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
assert(object && format && timetuple);
assert(PyUnicode_Check(format));
/* Convert the input format to a C string and size */
- pin = _PyUnicode_AsStringAndSize(format, &flen);
+ pin = PyUnicode_AsUTF8AndSize(format, &flen);
if (!pin)
return NULL;
@@ -1238,7 +1287,7 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
}
assert(Zreplacement != NULL);
assert(PyUnicode_Check(Zreplacement));
- ptoappend = _PyUnicode_AsStringAndSize(Zreplacement,
+ ptoappend = PyUnicode_AsUTF8AndSize(Zreplacement,
&ntoappend);
if (ptoappend == NULL)
goto Done;
@@ -1323,7 +1372,7 @@ time_time(void)
if (time != NULL) {
_Py_IDENTIFIER(time);
- result = _PyObject_CallMethodId(time, &PyId_time, "()");
+ result = _PyObject_CallMethodId(time, &PyId_time, NULL);
Py_DECREF(time);
}
return result;
@@ -2307,7 +2356,7 @@ static PyMethodDef delta_methods[] = {
{NULL, NULL},
};
-static char delta_doc[] =
+static const char delta_doc[] =
PyDoc_STR("Difference between two datetime values.");
static PyNumberMethods delta_as_number = {
@@ -2462,27 +2511,19 @@ date_new(PyTypeObject *type, PyObject *args, PyObject *kw)
static PyObject *
date_local_from_object(PyObject *cls, PyObject *obj)
{
- struct tm *tm;
+ struct tm tm;
time_t t;
if (_PyTime_ObjectToTime_t(obj, &t, _PyTime_ROUND_FLOOR) == -1)
return NULL;
- tm = localtime(&t);
- if (tm == NULL) {
- /* unconvertible time */
-#ifdef EINVAL
- if (errno == 0)
- errno = EINVAL;
-#endif
- PyErr_SetFromErrno(PyExc_OSError);
+ if (_PyTime_localtime(t, &tm) != 0)
return NULL;
- }
return PyObject_CallFunction(cls, "iii",
- tm->tm_year + 1900,
- tm->tm_mon + 1,
- tm->tm_mday);
+ tm.tm_year + 1900,
+ tm.tm_mon + 1,
+ tm.tm_mday);
}
/* Return new date from current time.
@@ -2648,7 +2689,7 @@ date_isoformat(PyDateTime_Date *self)
static PyObject *
date_str(PyDateTime_Date *self)
{
- return _PyObject_CallMethodId((PyObject *)self, &PyId_isoformat, "()");
+ return _PyObject_CallMethodId((PyObject *)self, &PyId_isoformat, NULL);
}
@@ -2674,7 +2715,7 @@ date_strftime(PyDateTime_Date *self, PyObject *args, PyObject *kw)
&format))
return NULL;
- tuple = _PyObject_CallMethodId((PyObject *)self, &PyId_timetuple, "()");
+ tuple = _PyObject_CallMethodId((PyObject *)self, &PyId_timetuple, NULL);
if (tuple == NULL)
return NULL;
result = wrap_strftime((PyObject *)self, format, tuple,
@@ -2786,9 +2827,10 @@ static PyObject *date_getstate(PyDateTime_Date *self);
static Py_hash_t
date_hash(PyDateTime_Date *self)
{
- if (self->hashcode == -1)
+ if (self->hashcode == -1) {
self->hashcode = generic_hash(
(unsigned char *)self->data, _PyDateTime_DATE_DATASIZE);
+ }
return self->hashcode;
}
@@ -2886,7 +2928,7 @@ static PyMethodDef date_methods[] = {
{NULL, NULL}
};
-static char date_doc[] =
+static const char date_doc[] =
PyDoc_STR("date(year, month, day) --> date object");
static PyNumberMethods date_as_number = {
@@ -3047,10 +3089,8 @@ tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt)
if (dst == Py_None)
goto Inconsistent;
if (delta_bool((PyDateTime_Delta *)dst) != 0) {
- PyObject *temp = result;
- result = add_datetime_timedelta((PyDateTime_DateTime *)result,
- (PyDateTime_Delta *)dst, 1);
- Py_DECREF(temp);
+ Py_SETREF(result, add_datetime_timedelta((PyDateTime_DateTime *)result,
+ (PyDateTime_Delta *)dst, 1));
if (result == NULL)
goto Fail;
}
@@ -3080,37 +3120,34 @@ Fail:
static PyObject *
tzinfo_reduce(PyObject *self)
{
- PyObject *args, *state, *tmp;
+ PyObject *args, *state;
PyObject *getinitargs, *getstate;
_Py_IDENTIFIER(__getinitargs__);
_Py_IDENTIFIER(__getstate__);
- tmp = PyTuple_New(0);
- if (tmp == NULL)
- return NULL;
-
getinitargs = _PyObject_GetAttrId(self, &PyId___getinitargs__);
if (getinitargs != NULL) {
- args = PyObject_CallObject(getinitargs, tmp);
+ args = _PyObject_CallNoArg(getinitargs);
Py_DECREF(getinitargs);
if (args == NULL) {
- Py_DECREF(tmp);
return NULL;
}
}
else {
PyErr_Clear();
- args = tmp;
- Py_INCREF(args);
+
+ args = PyTuple_New(0);
+ if (args == NULL) {
+ return NULL;
+ }
}
getstate = _PyObject_GetAttrId(self, &PyId___getstate__);
if (getstate != NULL) {
- state = PyObject_CallObject(getstate, tmp);
+ state = _PyObject_CallNoArg(getstate);
Py_DECREF(getstate);
if (state == NULL) {
Py_DECREF(args);
- Py_DECREF(tmp);
return NULL;
}
}
@@ -3119,13 +3156,12 @@ tzinfo_reduce(PyObject *self)
PyErr_Clear();
state = Py_None;
dictptr = _PyObject_GetDictPtr(self);
- if (dictptr && *dictptr && PyDict_Size(*dictptr))
+ if (dictptr && *dictptr && PyDict_Size(*dictptr)) {
state = *dictptr;
+ }
Py_INCREF(state);
}
- Py_DECREF(tmp);
-
if (state == Py_None) {
Py_DECREF(state);
return Py_BuildValue("(ON)", Py_TYPE(self), args);
@@ -3155,7 +3191,7 @@ static PyMethodDef tzinfo_methods[] = {
{NULL, NULL}
};
-static char tzinfo_doc[] =
+static const char tzinfo_doc[] =
PyDoc_STR("Abstract base class for time zone info objects.");
static PyTypeObject PyDateTime_TZInfoType = {
@@ -3287,6 +3323,11 @@ timezone_str(PyDateTime_TimeZone *self)
Py_INCREF(self->name);
return self->name;
}
+ if ((PyObject *)self == PyDateTime_TimeZone_UTC ||
+ (GET_TD_DAYS(self->offset) == 0 &&
+ GET_TD_SECONDS(self->offset) == 0 &&
+ GET_TD_MICROSECONDS(self->offset) == 0))
+ return PyUnicode_FromString("UTC");
/* Offset is normalized, so it is negative if days < 0 */
if (GET_TD_DAYS(self->offset) < 0) {
sign = '-';
@@ -3382,7 +3423,7 @@ static PyMethodDef timezone_methods[] = {
{NULL, NULL}
};
-static char timezone_doc[] =
+static const char timezone_doc[] =
PyDoc_STR("Fixed offset from UTC implementation of tzinfo.");
static PyTypeObject PyDateTime_TimeZoneType = {
@@ -3466,12 +3507,19 @@ time_tzinfo(PyDateTime_Time *self, void *unused)
return result;
}
+static PyObject *
+time_fold(PyDateTime_Time *self, void *unused)
+{
+ return PyLong_FromLong(TIME_GET_FOLD(self));
+}
+
static PyGetSetDef time_getset[] = {
{"hour", (getter)time_hour},
{"minute", (getter)time_minute},
{"second", (getter)py_time_second},
{"microsecond", (getter)time_microsecond},
- {"tzinfo", (getter)time_tzinfo},
+ {"tzinfo", (getter)time_tzinfo},
+ {"fold", (getter)time_fold},
{NULL}
};
@@ -3480,7 +3528,7 @@ static PyGetSetDef time_getset[] = {
*/
static char *time_kws[] = {"hour", "minute", "second", "microsecond",
- "tzinfo", NULL};
+ "tzinfo", "fold", NULL};
static PyObject *
time_new(PyTypeObject *type, PyObject *args, PyObject *kw)
@@ -3492,13 +3540,14 @@ time_new(PyTypeObject *type, PyObject *args, PyObject *kw)
int second = 0;
int usecond = 0;
PyObject *tzinfo = Py_None;
+ int fold = 0;
/* Check for invocation from pickle with __getstate__ state */
if (PyTuple_GET_SIZE(args) >= 1 &&
PyTuple_GET_SIZE(args) <= 2 &&
PyBytes_Check(state = PyTuple_GET_ITEM(args, 0)) &&
PyBytes_GET_SIZE(state) == _PyDateTime_TIME_DATASIZE &&
- ((unsigned char) (PyBytes_AS_STRING(state)[0])) < 24)
+ (0x7F & ((unsigned char) (PyBytes_AS_STRING(state)[0]))) < 24)
{
PyDateTime_Time *me;
char aware;
@@ -3523,19 +3572,26 @@ time_new(PyTypeObject *type, PyObject *args, PyObject *kw)
Py_INCREF(tzinfo);
me->tzinfo = tzinfo;
}
+ if (pdata[0] & (1 << 7)) {
+ me->data[0] -= 128;
+ me->fold = 1;
+ }
+ else {
+ me->fold = 0;
+ }
}
return (PyObject *)me;
}
- if (PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO", time_kws,
+ if (PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO$i", time_kws,
&hour, &minute, &second, &usecond,
- &tzinfo)) {
- if (check_time_args(hour, minute, second, usecond) < 0)
+ &tzinfo, &fold)) {
+ if (check_time_args(hour, minute, second, usecond, fold) < 0)
return NULL;
if (check_tzinfo_subclass(tzinfo) < 0)
return NULL;
- self = new_time_ex(hour, minute, second, usecond, tzinfo,
- type);
+ self = new_time_ex2(hour, minute, second, usecond, tzinfo, fold,
+ type);
}
return self;
}
@@ -3585,6 +3641,7 @@ time_repr(PyDateTime_Time *self)
int m = TIME_GET_MINUTE(self);
int s = TIME_GET_SECOND(self);
int us = TIME_GET_MICROSECOND(self);
+ int fold = TIME_GET_FOLD(self);
PyObject *result = NULL;
if (us)
@@ -3597,33 +3654,68 @@ time_repr(PyDateTime_Time *self)
result = PyUnicode_FromFormat("%s(%d, %d)", type_name, h, m);
if (result != NULL && HASTZINFO(self))
result = append_keyword_tzinfo(result, self->tzinfo);
+ if (result != NULL && fold)
+ result = append_keyword_fold(result, fold);
return result;
}
static PyObject *
time_str(PyDateTime_Time *self)
{
- return _PyObject_CallMethodId((PyObject *)self, &PyId_isoformat, "()");
+ return _PyObject_CallMethodId((PyObject *)self, &PyId_isoformat, NULL);
}
static PyObject *
-time_isoformat(PyDateTime_Time *self, PyObject *unused)
+time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw)
{
char buf[100];
+ char *timespec = NULL;
+ static char *keywords[] = {"timespec", NULL};
PyObject *result;
int us = TIME_GET_MICROSECOND(self);
+ static char *specs[][2] = {
+ {"hours", "%02d"},
+ {"minutes", "%02d:%02d"},
+ {"seconds", "%02d:%02d:%02d"},
+ {"milliseconds", "%02d:%02d:%02d.%03d"},
+ {"microseconds", "%02d:%02d:%02d.%06d"},
+ };
+ size_t given_spec;
- if (us)
- result = PyUnicode_FromFormat("%02d:%02d:%02d.%06d",
- TIME_GET_HOUR(self),
- TIME_GET_MINUTE(self),
- TIME_GET_SECOND(self),
- us);
- else
- result = PyUnicode_FromFormat("%02d:%02d:%02d",
- TIME_GET_HOUR(self),
- TIME_GET_MINUTE(self),
- TIME_GET_SECOND(self));
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "|s:isoformat", keywords, &timespec))
+ return NULL;
+
+ if (timespec == NULL || strcmp(timespec, "auto") == 0) {
+ if (us == 0) {
+ /* seconds */
+ given_spec = 2;
+ }
+ else {
+ /* microseconds */
+ given_spec = 4;
+ }
+ }
+ else {
+ for (given_spec = 0; given_spec < Py_ARRAY_LENGTH(specs); given_spec++) {
+ if (strcmp(timespec, specs[given_spec][0]) == 0) {
+ if (given_spec == 3) {
+ /* milliseconds */
+ us = us / 1000;
+ }
+ break;
+ }
+ }
+ }
+
+ if (given_spec == Py_ARRAY_LENGTH(specs)) {
+ PyErr_Format(PyExc_ValueError, "Unknown timespec value");
+ return NULL;
+ }
+ else {
+ result = PyUnicode_FromFormat(specs[given_spec][1],
+ TIME_GET_HOUR(self), TIME_GET_MINUTE(self),
+ TIME_GET_SECOND(self), us);
+ }
if (result == NULL || !HASTZINFO(self) || self->tzinfo == Py_None)
return result;
@@ -3750,9 +3842,23 @@ static Py_hash_t
time_hash(PyDateTime_Time *self)
{
if (self->hashcode == -1) {
- PyObject *offset;
-
- offset = time_utcoffset((PyObject *)self, NULL);
+ PyObject *offset, *self0;
+ if (TIME_GET_FOLD(self)) {
+ self0 = new_time_ex2(TIME_GET_HOUR(self),
+ TIME_GET_MINUTE(self),
+ TIME_GET_SECOND(self),
+ TIME_GET_MICROSECOND(self),
+ HASTZINFO(self) ? self->tzinfo : Py_None,
+ 0, Py_TYPE(self));
+ if (self0 == NULL)
+ return -1;
+ }
+ else {
+ self0 = (PyObject *)self;
+ Py_INCREF(self0);
+ }
+ offset = time_utcoffset(self0, NULL);
+ Py_DECREF(self0);
if (offset == NULL)
return -1;
@@ -3798,15 +3904,24 @@ time_replace(PyDateTime_Time *self, PyObject *args, PyObject *kw)
int ss = TIME_GET_SECOND(self);
int us = TIME_GET_MICROSECOND(self);
PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None;
+ int fold = TIME_GET_FOLD(self);
- if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO:replace",
+ if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO$i:replace",
time_kws,
- &hh, &mm, &ss, &us, &tzinfo))
+ &hh, &mm, &ss, &us, &tzinfo, &fold))
return NULL;
tuple = Py_BuildValue("iiiiO", hh, mm, ss, us, tzinfo);
if (tuple == NULL)
return NULL;
clone = time_new(Py_TYPE(self), tuple, NULL);
+ if (clone != NULL) {
+ if (fold != 0 && fold != 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "fold must be either 0 or 1");
+ return NULL;
+ }
+ TIME_SET_FOLD(clone, fold);
+ }
Py_DECREF(tuple);
return clone;
}
@@ -3819,7 +3934,7 @@ time_replace(PyDateTime_Time *self, PyObject *args, PyObject *kw)
* __getstate__ isn't exposed.
*/
static PyObject *
-time_getstate(PyDateTime_Time *self)
+time_getstate(PyDateTime_Time *self, int proto)
{
PyObject *basestate;
PyObject *result = NULL;
@@ -3827,6 +3942,9 @@ time_getstate(PyDateTime_Time *self)
basestate = PyBytes_FromStringAndSize((char *)self->data,
_PyDateTime_TIME_DATASIZE);
if (basestate != NULL) {
+ if (proto > 3 && TIME_GET_FOLD(self))
+ /* Set the first bit of the first byte */
+ PyBytes_AS_STRING(basestate)[0] |= (1 << 7);
if (! HASTZINFO(self) || self->tzinfo == Py_None)
result = PyTuple_Pack(1, basestate);
else
@@ -3837,16 +3955,27 @@ time_getstate(PyDateTime_Time *self)
}
static PyObject *
+time_reduce_ex(PyDateTime_Time *self, PyObject *args)
+{
+ int proto;
+ if (!PyArg_ParseTuple(args, "i:__reduce_ex__", &proto))
+ return NULL;
+
+ return Py_BuildValue("(ON)", Py_TYPE(self), time_getstate(self, proto));
+}
+
+static PyObject *
time_reduce(PyDateTime_Time *self, PyObject *arg)
{
- return Py_BuildValue("(ON)", Py_TYPE(self), time_getstate(self));
+ return Py_BuildValue("(ON)", Py_TYPE(self), time_getstate(self, 2));
}
static PyMethodDef time_methods[] = {
- {"isoformat", (PyCFunction)time_isoformat, METH_NOARGS,
- PyDoc_STR("Return string in ISO 8601 format, HH:MM:SS[.mmmmmm]"
- "[+HH:MM].")},
+ {"isoformat", (PyCFunction)time_isoformat, METH_VARARGS | METH_KEYWORDS,
+ PyDoc_STR("Return string in ISO 8601 format, [HH[:MM[:SS[.mmm[uuu]]]]]"
+ "[+HH:MM].\n\n"
+ "timespec specifies what components of the time to include.\n")},
{"strftime", (PyCFunction)time_strftime, METH_VARARGS | METH_KEYWORDS,
PyDoc_STR("format -> strftime() style string.")},
@@ -3866,13 +3995,16 @@ static PyMethodDef time_methods[] = {
{"replace", (PyCFunction)time_replace, METH_VARARGS | METH_KEYWORDS,
PyDoc_STR("Return time with new specified fields.")},
+ {"__reduce_ex__", (PyCFunction)time_reduce_ex, METH_VARARGS,
+ PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")},
+
{"__reduce__", (PyCFunction)time_reduce, METH_NOARGS,
PyDoc_STR("__reduce__() -> (cls, state)")},
{NULL, NULL}
};
-static char time_doc[] =
+static const char time_doc[] =
PyDoc_STR("time([hour[, minute[, second[, microsecond[, tzinfo]]]]]) --> a time object\n\
\n\
All arguments are optional. tzinfo may be None, or an instance of\n\
@@ -3960,12 +4092,19 @@ datetime_tzinfo(PyDateTime_DateTime *self, void *unused)
return result;
}
+static PyObject *
+datetime_fold(PyDateTime_DateTime *self, void *unused)
+{
+ return PyLong_FromLong(DATE_GET_FOLD(self));
+}
+
static PyGetSetDef datetime_getset[] = {
{"hour", (getter)datetime_hour},
{"minute", (getter)datetime_minute},
{"second", (getter)datetime_second},
{"microsecond", (getter)datetime_microsecond},
- {"tzinfo", (getter)datetime_tzinfo},
+ {"tzinfo", (getter)datetime_tzinfo},
+ {"fold", (getter)datetime_fold},
{NULL}
};
@@ -3975,7 +4114,7 @@ static PyGetSetDef datetime_getset[] = {
static char *datetime_kws[] = {
"year", "month", "day", "hour", "minute", "second",
- "microsecond", "tzinfo", NULL
+ "microsecond", "tzinfo", "fold", NULL
};
static PyObject *
@@ -3990,6 +4129,7 @@ datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
int minute = 0;
int second = 0;
int usecond = 0;
+ int fold = 0;
PyObject *tzinfo = Py_None;
/* Check for invocation from pickle with __getstate__ state */
@@ -3997,7 +4137,7 @@ datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
PyTuple_GET_SIZE(args) <= 2 &&
PyBytes_Check(state = PyTuple_GET_ITEM(args, 0)) &&
PyBytes_GET_SIZE(state) == _PyDateTime_DATETIME_DATASIZE &&
- MONTH_IS_SANE(PyBytes_AS_STRING(state)[2]))
+ MONTH_IS_SANE(PyBytes_AS_STRING(state)[2] & 0x7F))
{
PyDateTime_DateTime *me;
char aware;
@@ -4022,28 +4162,73 @@ datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
Py_INCREF(tzinfo);
me->tzinfo = tzinfo;
}
+ if (pdata[2] & (1 << 7)) {
+ me->data[2] -= 128;
+ me->fold = 1;
+ }
+ else {
+ me->fold = 0;
+ }
}
return (PyObject *)me;
}
- if (PyArg_ParseTupleAndKeywords(args, kw, "iii|iiiiO", datetime_kws,
+ if (PyArg_ParseTupleAndKeywords(args, kw, "iii|iiiiO$i", datetime_kws,
&year, &month, &day, &hour, &minute,
- &second, &usecond, &tzinfo)) {
+ &second, &usecond, &tzinfo, &fold)) {
if (check_date_args(year, month, day) < 0)
return NULL;
- if (check_time_args(hour, minute, second, usecond) < 0)
+ if (check_time_args(hour, minute, second, usecond, fold) < 0)
return NULL;
if (check_tzinfo_subclass(tzinfo) < 0)
return NULL;
- self = new_datetime_ex(year, month, day,
+ self = new_datetime_ex2(year, month, day,
hour, minute, second, usecond,
- tzinfo, type);
+ tzinfo, fold, type);
}
return self;
}
-/* TM_FUNC is the shared type of localtime() and gmtime(). */
-typedef struct tm *(*TM_FUNC)(const time_t *timer);
+/* TM_FUNC is the shared type of _PyTime_localtime() and
+ * _PyTime_gmtime(). */
+typedef int (*TM_FUNC)(time_t timer, struct tm*);
+
+/* As of version 2015f max fold in IANA database is
+ * 23 hours at 1969-09-30 13:00:00 in Kwajalein. */
+static long long max_fold_seconds = 24 * 3600;
+/* NB: date(1970,1,1).toordinal() == 719163 */
+static long long epoch = 719163LL * 24 * 60 * 60;
+
+static long long
+utc_to_seconds(int year, int month, int day,
+ int hour, int minute, int second)
+{
+ long long ordinal = ymd_to_ord(year, month, day);
+ return ((ordinal * 24 + hour) * 60 + minute) * 60 + second;
+}
+
+static long long
+local(long long u)
+{
+ struct tm local_time;
+ time_t t;
+ u -= epoch;
+ t = u;
+ if (t != u) {
+ PyErr_SetString(PyExc_OverflowError,
+ "timestamp out of range for platform time_t");
+ return -1;
+ }
+ /* XXX: add bounds checking */
+ if (_PyTime_localtime(t, &local_time) != 0)
+ return -1;
+ return utc_to_seconds(local_time.tm_year + 1900,
+ local_time.tm_mon + 1,
+ local_time.tm_mday,
+ local_time.tm_hour,
+ local_time.tm_min,
+ local_time.tm_sec);
+}
/* Internal helper.
* Build datetime from a time_t and a distinct count of microseconds.
@@ -4053,72 +4238,46 @@ static PyObject *
datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us,
PyObject *tzinfo)
{
- struct tm *tm;
+ struct tm tm;
+ int year, month, day, hour, minute, second, fold = 0;
- tm = f(&timet);
- if (tm == NULL) {
-#ifdef EINVAL
- if (errno == 0)
- errno = EINVAL;
-#endif
- return PyErr_SetFromErrno(PyExc_OSError);
- }
+ if (f(timet, &tm) != 0)
+ return NULL;
+ year = tm.tm_year + 1900;
+ month = tm.tm_mon + 1;
+ day = tm.tm_mday;
+ hour = tm.tm_hour;
+ minute = tm.tm_min;
/* The platform localtime/gmtime may insert leap seconds,
- * indicated by tm->tm_sec > 59. We don't care about them,
+ * indicated by tm.tm_sec > 59. We don't care about them,
* except to the extent that passing them on to the datetime
* constructor would raise ValueError for a reason that
* made no sense to the user.
*/
- if (tm->tm_sec > 59)
- tm->tm_sec = 59;
- return PyObject_CallFunction(cls, "iiiiiiiO",
- tm->tm_year + 1900,
- tm->tm_mon + 1,
- tm->tm_mday,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec,
- us,
- tzinfo);
-}
-
-static time_t
-_PyTime_DoubleToTimet(double x)
-{
- time_t result;
- double diff;
-
- result = (time_t)x;
- /* How much info did we lose? time_t may be an integral or
- * floating type, and we don't know which. If it's integral,
- * we don't know whether C truncates, rounds, returns the floor,
- * etc. If we lost a second or more, the C rounding is
- * unreasonable, or the input just doesn't fit in a time_t;
- * call it an error regardless. Note that the original cast to
- * time_t can cause a C error too, but nothing we can do to
- * worm around that.
- */
- diff = x - (double)result;
- if (diff <= -1.0 || diff >= 1.0) {
- PyErr_SetString(PyExc_OverflowError,
- "timestamp out of range for platform time_t");
- result = (time_t)-1;
- }
- return result;
-}
+ second = Py_MIN(59, tm.tm_sec);
-/* Round a double to the nearest long. |x| must be small enough to fit
- * in a C long; this is not checked.
- */
-static double
-_PyTime_RoundHalfEven(double x)
-{
- double rounded = round(x);
- if (fabs(x-rounded) == 0.5)
- /* halfway case: round to even */
- rounded = 2.0*round(x/2.0);
- return rounded;
+ if (tzinfo == Py_None && f == _PyTime_localtime) {
+ long long probe_seconds, result_seconds, transition;
+
+ result_seconds = utc_to_seconds(year, month, day,
+ hour, minute, second);
+ /* Probe max_fold_seconds to detect a fold. */
+ probe_seconds = local(epoch + timet - max_fold_seconds);
+ if (probe_seconds == -1)
+ return NULL;
+ transition = result_seconds - probe_seconds - max_fold_seconds;
+ if (transition < 0) {
+ probe_seconds = local(epoch + timet + transition);
+ if (probe_seconds == -1)
+ return NULL;
+ if (probe_seconds == result_seconds)
+ fold = 1;
+ }
+ }
+ return new_datetime_ex2(year, month, day, hour,
+ minute, second, us, tzinfo, fold,
+ (PyTypeObject *)cls);
}
/* Internal helper.
@@ -4129,32 +4288,17 @@ _PyTime_RoundHalfEven(double x)
* to get that much precision (e.g., C time() isn't good enough).
*/
static PyObject *
-datetime_from_timestamp(PyObject *cls, TM_FUNC f, double timestamp,
+datetime_from_timestamp(PyObject *cls, TM_FUNC f, PyObject *timestamp,
PyObject *tzinfo)
{
time_t timet;
- double fraction;
- int us;
+ long us;
- timet = _PyTime_DoubleToTimet(timestamp);
- if (timet == (time_t)-1 && PyErr_Occurred())
+ if (_PyTime_ObjectToTimeval(timestamp,
+ &timet, &us, _PyTime_ROUND_HALF_EVEN) == -1)
return NULL;
- fraction = timestamp - (double)timet;
- us = (int)_PyTime_RoundHalfEven(fraction * 1e6);
- if (us < 0) {
- /* Truncation towards zero is not what we wanted
- for negative numbers (Python's mod semantics) */
- timet -= 1;
- us += 1000000;
- }
- /* If timestamp is less than one microsecond smaller than a
- * full second, round up. Otherwise, ValueErrors are raised
- * for some floats. */
- if (us == 1000000) {
- timet += 1;
- us = 0;
- }
- return datetime_from_timet_and_us(cls, f, timet, us, tzinfo);
+
+ return datetime_from_timet_and_us(cls, f, timet, (int)us, tzinfo);
}
/* Internal helper.
@@ -4201,14 +4345,12 @@ datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz)
return NULL;
self = datetime_best_possible((PyObject *)type,
- tz == Py_None ? localtime : gmtime,
+ tz == Py_None ? _PyTime_localtime :
+ _PyTime_gmtime,
tz);
if (self != NULL && tz != Py_None) {
/* Convert UTC to tzinfo's zone. */
- PyObject *temp = self;
-
- self = _PyObject_CallMethodId(tz, &PyId_fromutc, "O", self);
- Py_DECREF(temp);
+ self = _PyObject_CallMethodId(tz, &PyId_fromutc, "N", self);
}
return self;
}
@@ -4219,7 +4361,7 @@ datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz)
static PyObject *
datetime_utcnow(PyObject *cls, PyObject *dummy)
{
- return datetime_best_possible(cls, gmtime, Py_None);
+ return datetime_best_possible(cls, _PyTime_gmtime, Py_None);
}
/* Return new local datetime from timestamp (Python timestamp -- a double). */
@@ -4227,26 +4369,24 @@ static PyObject *
datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw)
{
PyObject *self;
- double timestamp;
+ PyObject *timestamp;
PyObject *tzinfo = Py_None;
static char *keywords[] = {"timestamp", "tz", NULL};
- if (! PyArg_ParseTupleAndKeywords(args, kw, "d|O:fromtimestamp",
+ if (! PyArg_ParseTupleAndKeywords(args, kw, "O|O:fromtimestamp",
keywords, &timestamp, &tzinfo))
return NULL;
if (check_tzinfo_subclass(tzinfo) < 0)
return NULL;
self = datetime_from_timestamp(cls,
- tzinfo == Py_None ? localtime : gmtime,
+ tzinfo == Py_None ? _PyTime_localtime :
+ _PyTime_gmtime,
timestamp,
tzinfo);
if (self != NULL && tzinfo != Py_None) {
/* Convert UTC to tzinfo's zone. */
- PyObject *temp = self;
-
- self = _PyObject_CallMethodId(tzinfo, &PyId_fromutc, "O", self);
- Py_DECREF(temp);
+ self = _PyObject_CallMethodId(tzinfo, &PyId_fromutc, "N", self);
}
return self;
}
@@ -4255,11 +4395,11 @@ datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw)
static PyObject *
datetime_utcfromtimestamp(PyObject *cls, PyObject *args)
{
- double timestamp;
+ PyObject *timestamp;
PyObject *result = NULL;
- if (PyArg_ParseTuple(args, "d:utcfromtimestamp", &timestamp))
- result = datetime_from_timestamp(cls, gmtime, timestamp,
+ if (PyArg_ParseTuple(args, "O:utcfromtimestamp", &timestamp))
+ result = datetime_from_timestamp(cls, _PyTime_gmtime, timestamp,
Py_None);
return result;
}
@@ -4288,27 +4428,32 @@ datetime_strptime(PyObject *cls, PyObject *args)
static PyObject *
datetime_combine(PyObject *cls, PyObject *args, PyObject *kw)
{
- static char *keywords[] = {"date", "time", NULL};
+ static char *keywords[] = {"date", "time", "tzinfo", NULL};
PyObject *date;
PyObject *time;
+ PyObject *tzinfo = NULL;
PyObject *result = NULL;
- if (PyArg_ParseTupleAndKeywords(args, kw, "O!O!:combine", keywords,
+ if (PyArg_ParseTupleAndKeywords(args, kw, "O!O!|O:combine", keywords,
&PyDateTime_DateType, &date,
- &PyDateTime_TimeType, &time)) {
- PyObject *tzinfo = Py_None;
-
- if (HASTZINFO(time))
- tzinfo = ((PyDateTime_Time *)time)->tzinfo;
+ &PyDateTime_TimeType, &time, &tzinfo)) {
+ if (tzinfo == NULL) {
+ if (HASTZINFO(time))
+ tzinfo = ((PyDateTime_Time *)time)->tzinfo;
+ else
+ tzinfo = Py_None;
+ }
result = PyObject_CallFunction(cls, "iiiiiiiO",
- GET_YEAR(date),
- GET_MONTH(date),
- GET_DAY(date),
- TIME_GET_HOUR(time),
- TIME_GET_MINUTE(time),
- TIME_GET_SECOND(time),
- TIME_GET_MICROSECOND(time),
- tzinfo);
+ GET_YEAR(date),
+ GET_MONTH(date),
+ GET_DAY(date),
+ TIME_GET_HOUR(time),
+ TIME_GET_MINUTE(time),
+ TIME_GET_SECOND(time),
+ TIME_GET_MICROSECOND(time),
+ tzinfo);
+ if (result)
+ DATE_SET_FOLD(result, TIME_GET_FOLD(time));
}
return result;
}
@@ -4376,7 +4521,7 @@ add_datetime_timedelta(PyDateTime_DateTime *date, PyDateTime_Delta *delta,
else
return new_datetime(year, month, day,
hour, minute, second, microsecond,
- HASTZINFO(date) ? date->tzinfo : Py_None);
+ HASTZINFO(date) ? date->tzinfo : Py_None, 0);
}
static PyObject *
@@ -4469,9 +4614,7 @@ datetime_subtract(PyObject *left, PyObject *right)
return NULL;
if (offdiff != NULL) {
- PyObject *temp = result;
- result = delta_subtract(result, offdiff);
- Py_DECREF(temp);
+ Py_SETREF(result, delta_subtract(result, offdiff));
Py_DECREF(offdiff);
}
}
@@ -4521,6 +4664,8 @@ datetime_repr(PyDateTime_DateTime *self)
GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
DATE_GET_HOUR(self), DATE_GET_MINUTE(self));
}
+ if (baserepr != NULL && DATE_GET_FOLD(self) != 0)
+ baserepr = append_keyword_fold(baserepr, DATE_GET_FOLD(self));
if (baserepr == NULL || ! HASTZINFO(self))
return baserepr;
return append_keyword_tzinfo(baserepr, self->tzinfo);
@@ -4536,25 +4681,55 @@ static PyObject *
datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
{
int sep = 'T';
- static char *keywords[] = {"sep", NULL};
+ char *timespec = NULL;
+ static char *keywords[] = {"sep", "timespec", NULL};
char buffer[100];
- PyObject *result;
+ PyObject *result = NULL;
int us = DATE_GET_MICROSECOND(self);
+ static char *specs[][2] = {
+ {"hours", "%04d-%02d-%02d%c%02d"},
+ {"minutes", "%04d-%02d-%02d%c%02d:%02d"},
+ {"seconds", "%04d-%02d-%02d%c%02d:%02d:%02d"},
+ {"milliseconds", "%04d-%02d-%02d%c%02d:%02d:%02d.%03d"},
+ {"microseconds", "%04d-%02d-%02d%c%02d:%02d:%02d.%06d"},
+ };
+ size_t given_spec;
- if (!PyArg_ParseTupleAndKeywords(args, kw, "|C:isoformat", keywords, &sep))
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "|Cs:isoformat", keywords, &sep, &timespec))
return NULL;
- if (us)
- result = PyUnicode_FromFormat("%04d-%02d-%02d%c%02d:%02d:%02d.%06d",
+
+ if (timespec == NULL || strcmp(timespec, "auto") == 0) {
+ if (us == 0) {
+ /* seconds */
+ given_spec = 2;
+ }
+ else {
+ /* microseconds */
+ given_spec = 4;
+ }
+ }
+ else {
+ for (given_spec = 0; given_spec < Py_ARRAY_LENGTH(specs); given_spec++) {
+ if (strcmp(timespec, specs[given_spec][0]) == 0) {
+ if (given_spec == 3) {
+ us = us / 1000;
+ }
+ break;
+ }
+ }
+ }
+
+ if (given_spec == Py_ARRAY_LENGTH(specs)) {
+ PyErr_Format(PyExc_ValueError, "Unknown timespec value");
+ return NULL;
+ }
+ else {
+ result = PyUnicode_FromFormat(specs[given_spec][1],
GET_YEAR(self), GET_MONTH(self),
GET_DAY(self), (int)sep,
DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
DATE_GET_SECOND(self), us);
- else
- result = PyUnicode_FromFormat("%04d-%02d-%02d%c%02d:%02d:%02d",
- GET_YEAR(self), GET_MONTH(self),
- GET_DAY(self), (int)sep,
- DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
- DATE_GET_SECOND(self));
+ }
if (!result || !HASTZINFO(self))
return result;
@@ -4581,6 +4756,70 @@ datetime_ctime(PyDateTime_DateTime *self)
/* Miscellaneous methods. */
static PyObject *
+flip_fold(PyObject *dt)
+{
+ return new_datetime_ex2(GET_YEAR(dt),
+ GET_MONTH(dt),
+ GET_DAY(dt),
+ DATE_GET_HOUR(dt),
+ DATE_GET_MINUTE(dt),
+ DATE_GET_SECOND(dt),
+ DATE_GET_MICROSECOND(dt),
+ HASTZINFO(dt) ?
+ ((PyDateTime_DateTime *)dt)->tzinfo : Py_None,
+ !DATE_GET_FOLD(dt),
+ Py_TYPE(dt));
+}
+
+static PyObject *
+get_flip_fold_offset(PyObject *dt)
+{
+ PyObject *result, *flip_dt;
+
+ flip_dt = flip_fold(dt);
+ if (flip_dt == NULL)
+ return NULL;
+ result = datetime_utcoffset(flip_dt, NULL);
+ Py_DECREF(flip_dt);
+ return result;
+}
+
+/* PEP 495 exception: Whenever one or both of the operands in
+ * inter-zone comparison is such that its utcoffset() depends
+ * on the value of its fold fold attribute, the result is False.
+ *
+ * Return 1 if exception applies, 0 if not, and -1 on error.
+ */
+static int
+pep495_eq_exception(PyObject *self, PyObject *other,
+ PyObject *offset_self, PyObject *offset_other)
+{
+ int result = 0;
+ PyObject *flip_offset;
+
+ flip_offset = get_flip_fold_offset(self);
+ if (flip_offset == NULL)
+ return -1;
+ if (flip_offset != offset_self &&
+ delta_cmp(flip_offset, offset_self))
+ {
+ result = 1;
+ goto done;
+ }
+ Py_DECREF(flip_offset);
+
+ flip_offset = get_flip_fold_offset(other);
+ if (flip_offset == NULL)
+ return -1;
+ if (flip_offset != offset_other &&
+ delta_cmp(flip_offset, offset_other))
+ result = 1;
+ done:
+ Py_DECREF(flip_offset);
+ return result;
+}
+
+static PyObject *
datetime_richcompare(PyObject *self, PyObject *other, int op)
{
PyObject *result = NULL;
@@ -4627,6 +4866,13 @@ datetime_richcompare(PyObject *self, PyObject *other, int op)
diff = memcmp(((PyDateTime_DateTime *)self)->data,
((PyDateTime_DateTime *)other)->data,
_PyDateTime_DATETIME_DATASIZE);
+ if ((op == Py_EQ || op == Py_NE) && diff == 0) {
+ int ex = pep495_eq_exception(self, other, offset1, offset2);
+ if (ex == -1)
+ goto done;
+ if (ex)
+ diff = 1;
+ }
result = diff_to_bool(diff, op);
}
else if (offset1 != Py_None && offset2 != Py_None) {
@@ -4642,6 +4888,13 @@ datetime_richcompare(PyObject *self, PyObject *other, int op)
diff = GET_TD_SECONDS(delta) |
GET_TD_MICROSECONDS(delta);
Py_DECREF(delta);
+ if ((op == Py_EQ || op == Py_NE) && diff == 0) {
+ int ex = pep495_eq_exception(self, other, offset1, offset2);
+ if (ex == -1)
+ goto done;
+ if (ex)
+ diff = 1;
+ }
result = diff_to_bool(diff, op);
}
else if (op == Py_EQ) {
@@ -4667,9 +4920,26 @@ static Py_hash_t
datetime_hash(PyDateTime_DateTime *self)
{
if (self->hashcode == -1) {
- PyObject *offset;
-
- offset = datetime_utcoffset((PyObject *)self, NULL);
+ PyObject *offset, *self0;
+ if (DATE_GET_FOLD(self)) {
+ self0 = new_datetime_ex2(GET_YEAR(self),
+ GET_MONTH(self),
+ GET_DAY(self),
+ DATE_GET_HOUR(self),
+ DATE_GET_MINUTE(self),
+ DATE_GET_SECOND(self),
+ DATE_GET_MICROSECOND(self),
+ HASTZINFO(self) ? self->tzinfo : Py_None,
+ 0, Py_TYPE(self));
+ if (self0 == NULL)
+ return -1;
+ }
+ else {
+ self0 = (PyObject *)self;
+ Py_INCREF(self0);
+ }
+ offset = datetime_utcoffset(self0, NULL);
+ Py_DECREF(self0);
if (offset == NULL)
return -1;
@@ -4723,76 +4993,80 @@ datetime_replace(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
int ss = DATE_GET_SECOND(self);
int us = DATE_GET_MICROSECOND(self);
PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None;
+ int fold = DATE_GET_FOLD(self);
- if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiiiiO:replace",
+ if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiiiiO$i:replace",
datetime_kws,
&y, &m, &d, &hh, &mm, &ss, &us,
- &tzinfo))
+ &tzinfo, &fold))
return NULL;
tuple = Py_BuildValue("iiiiiiiO", y, m, d, hh, mm, ss, us, tzinfo);
if (tuple == NULL)
return NULL;
clone = datetime_new(Py_TYPE(self), tuple, NULL);
+
+ if (clone != NULL) {
+ if (fold != 0 && fold != 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "fold must be either 0 or 1");
+ return NULL;
+ }
+ DATE_SET_FOLD(clone, fold);
+ }
Py_DECREF(tuple);
return clone;
}
static PyObject *
-local_timezone(PyDateTime_DateTime *utc_time)
+local_timezone_from_timestamp(time_t timestamp)
{
PyObject *result = NULL;
- struct tm *timep;
- time_t timestamp;
PyObject *delta;
- PyObject *one_second;
- PyObject *seconds;
+ struct tm local_time_tm;
PyObject *nameo = NULL;
const char *zone = NULL;
- delta = new_delta(ymd_to_ord(GET_YEAR(utc_time), GET_MONTH(utc_time),
- GET_DAY(utc_time)) - 719163,
- 60 * (60 * DATE_GET_HOUR(utc_time) +
- DATE_GET_MINUTE(utc_time)) +
- DATE_GET_SECOND(utc_time),
- 0, 0);
- if (delta == NULL)
+ if (_PyTime_localtime(timestamp, &local_time_tm) != 0)
return NULL;
- one_second = new_delta(0, 1, 0, 0);
- if (one_second == NULL)
- goto error;
- seconds = divide_timedelta_timedelta((PyDateTime_Delta *)delta,
- (PyDateTime_Delta *)one_second);
- Py_DECREF(one_second);
- if (seconds == NULL)
- goto error;
- Py_DECREF(delta);
- timestamp = PyLong_AsLong(seconds);
- Py_DECREF(seconds);
- if (timestamp == -1 && PyErr_Occurred())
- return NULL;
- timep = localtime(&timestamp);
#ifdef HAVE_STRUCT_TM_TM_ZONE
- zone = timep->tm_zone;
- delta = new_delta(0, timep->tm_gmtoff, 0, 1);
+ zone = local_time_tm.tm_zone;
+ delta = new_delta(0, local_time_tm.tm_gmtoff, 0, 1);
#else /* HAVE_STRUCT_TM_TM_ZONE */
{
- PyObject *local_time;
- local_time = new_datetime(timep->tm_year + 1900, timep->tm_mon + 1,
- timep->tm_mday, timep->tm_hour, timep->tm_min,
- timep->tm_sec, DATE_GET_MICROSECOND(utc_time),
- utc_time->tzinfo);
- if (local_time == NULL)
- goto error;
- delta = datetime_subtract(local_time, (PyObject*)utc_time);
- /* XXX: before relying on tzname, we should compare delta
- to the offset implied by timezone/altzone */
- if (daylight && timep->tm_isdst >= 0)
- zone = tzname[timep->tm_isdst % 2];
- else
- zone = tzname[0];
+ PyObject *local_time, *utc_time;
+ struct tm utc_time_tm;
+ char buf[100];
+ strftime(buf, sizeof(buf), "%Z", &local_time_tm);
+ zone = buf;
+ local_time = new_datetime(local_time_tm.tm_year + 1900,
+ local_time_tm.tm_mon + 1,
+ local_time_tm.tm_mday,
+ local_time_tm.tm_hour,
+ local_time_tm.tm_min,
+ local_time_tm.tm_sec, 0, Py_None, 0);
+ if (local_time == NULL) {
+ return NULL;
+ }
+ if (_PyTime_gmtime(timestamp, &utc_time_tm) != 0)
+ return NULL;
+ utc_time = new_datetime(utc_time_tm.tm_year + 1900,
+ utc_time_tm.tm_mon + 1,
+ utc_time_tm.tm_mday,
+ utc_time_tm.tm_hour,
+ utc_time_tm.tm_min,
+ utc_time_tm.tm_sec, 0, Py_None, 0);
+ if (utc_time == NULL) {
+ Py_DECREF(local_time);
+ return NULL;
+ }
+ delta = datetime_subtract(local_time, utc_time);
Py_DECREF(local_time);
+ Py_DECREF(utc_time);
}
#endif /* HAVE_STRUCT_TM_TM_ZONE */
+ if (delta == NULL) {
+ return NULL;
+ }
if (zone != NULL) {
nameo = PyUnicode_DecodeLocale(zone, "surrogateescape");
if (nameo == NULL)
@@ -4805,12 +5079,65 @@ local_timezone(PyDateTime_DateTime *utc_time)
return result;
}
+static PyObject *
+local_timezone(PyDateTime_DateTime *utc_time)
+{
+ time_t timestamp;
+ PyObject *delta;
+ PyObject *one_second;
+ PyObject *seconds;
+
+ delta = datetime_subtract((PyObject *)utc_time, PyDateTime_Epoch);
+ if (delta == NULL)
+ return NULL;
+ one_second = new_delta(0, 1, 0, 0);
+ if (one_second == NULL) {
+ Py_DECREF(delta);
+ return NULL;
+ }
+ seconds = divide_timedelta_timedelta((PyDateTime_Delta *)delta,
+ (PyDateTime_Delta *)one_second);
+ Py_DECREF(one_second);
+ Py_DECREF(delta);
+ if (seconds == NULL)
+ return NULL;
+ timestamp = _PyLong_AsTime_t(seconds);
+ Py_DECREF(seconds);
+ if (timestamp == -1 && PyErr_Occurred())
+ return NULL;
+ return local_timezone_from_timestamp(timestamp);
+}
+
+static long long
+local_to_seconds(int year, int month, int day,
+ int hour, int minute, int second, int fold);
+
+static PyObject *
+local_timezone_from_local(PyDateTime_DateTime *local_dt)
+{
+ long long seconds;
+ time_t timestamp;
+ seconds = local_to_seconds(GET_YEAR(local_dt),
+ GET_MONTH(local_dt),
+ GET_DAY(local_dt),
+ DATE_GET_HOUR(local_dt),
+ DATE_GET_MINUTE(local_dt),
+ DATE_GET_SECOND(local_dt),
+ DATE_GET_FOLD(local_dt));
+ if (seconds == -1)
+ return NULL;
+ /* XXX: add bounds check */
+ timestamp = seconds - epoch;
+ return local_timezone_from_timestamp(timestamp);
+}
+
static PyDateTime_DateTime *
datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
{
PyDateTime_DateTime *result;
PyObject *offset;
PyObject *temp;
+ PyObject *self_tzinfo;
PyObject *tzinfo = Py_None;
static char *keywords[] = {"tz", NULL};
@@ -4821,27 +5148,27 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
if (check_tzinfo_subclass(tzinfo) == -1)
return NULL;
- if (!HASTZINFO(self) || self->tzinfo == Py_None)
- goto NeedAware;
+ if (!HASTZINFO(self) || self->tzinfo == Py_None) {
+ self_tzinfo = local_timezone_from_local(self);
+ if (self_tzinfo == NULL)
+ return NULL;
+ } else {
+ self_tzinfo = self->tzinfo;
+ Py_INCREF(self_tzinfo);
+ }
/* Conversion to self's own time zone is a NOP. */
- if (self->tzinfo == tzinfo) {
+ if (self_tzinfo == tzinfo) {
+ Py_DECREF(self_tzinfo);
Py_INCREF(self);
return self;
}
/* Convert self to UTC. */
- offset = datetime_utcoffset((PyObject *)self, NULL);
+ offset = call_utcoffset(self_tzinfo, (PyObject *)self);
+ Py_DECREF(self_tzinfo);
if (offset == NULL)
return NULL;
- if (offset == Py_None) {
- Py_DECREF(offset);
- NeedAware:
- PyErr_SetString(PyExc_ValueError, "astimezone() cannot be applied to "
- "a naive datetime");
- return NULL;
- }
-
/* result = self - offset */
result = (PyDateTime_DateTime *)add_datetime_timedelta(self,
(PyDateTime_Delta *)offset, -1);
@@ -4849,6 +5176,32 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
if (result == NULL)
return NULL;
+ /* Make sure result is aware and UTC. */
+ if (!HASTZINFO(result)) {
+ temp = (PyObject *)result;
+ result = (PyDateTime_DateTime *)
+ new_datetime_ex2(GET_YEAR(result),
+ GET_MONTH(result),
+ GET_DAY(result),
+ DATE_GET_HOUR(result),
+ DATE_GET_MINUTE(result),
+ DATE_GET_SECOND(result),
+ DATE_GET_MICROSECOND(result),
+ PyDateTime_TimeZone_UTC,
+ DATE_GET_FOLD(result),
+ Py_TYPE(result));
+ Py_DECREF(temp);
+ if (result == NULL)
+ return NULL;
+ }
+ else {
+ /* Result is already aware - just replace tzinfo. */
+ temp = result->tzinfo;
+ result->tzinfo = PyDateTime_TimeZone_UTC;
+ Py_INCREF(result->tzinfo);
+ Py_DECREF(temp);
+ }
+
/* Attach new tzinfo and let fromutc() do the rest. */
temp = result->tzinfo;
if (tzinfo == Py_None) {
@@ -4896,6 +5249,56 @@ datetime_timetuple(PyDateTime_DateTime *self)
dstflag);
}
+static long long
+local_to_seconds(int year, int month, int day,
+ int hour, int minute, int second, int fold)
+{
+ long long t, a, b, u1, u2, t1, t2, lt;
+ t = utc_to_seconds(year, month, day, hour, minute, second);
+ /* Our goal is to solve t = local(u) for u. */
+ lt = local(t);
+ if (lt == -1)
+ return -1;
+ a = lt - t;
+ u1 = t - a;
+ t1 = local(u1);
+ if (t1 == -1)
+ return -1;
+ if (t1 == t) {
+ /* We found one solution, but it may not be the one we need.
+ * Look for an earlier solution (if `fold` is 0), or a
+ * later one (if `fold` is 1). */
+ if (fold)
+ u2 = u1 + max_fold_seconds;
+ else
+ u2 = u1 - max_fold_seconds;
+ lt = local(u2);
+ if (lt == -1)
+ return -1;
+ b = lt - u2;
+ if (a == b)
+ return u1;
+ }
+ else {
+ b = t1 - u1;
+ assert(a != b);
+ }
+ u2 = t - b;
+ t2 = local(u2);
+ if (t2 == -1)
+ return -1;
+ if (t2 == t)
+ return u2;
+ if (t1 == t)
+ return u1;
+ /* We have found both offsets a and b, but neither t - a nor t - b is
+ * a solution. This means t is in the gap. */
+ return fold?Py_MIN(u1, u2):Py_MAX(u1, u2);
+}
+
+/* date(1970,1,1).toordinal() == 719163 */
+#define EPOCH_SECONDS (719163LL * 24 * 60 * 60)
+
static PyObject *
datetime_timestamp(PyDateTime_DateTime *self)
{
@@ -4910,33 +5313,18 @@ datetime_timestamp(PyDateTime_DateTime *self)
Py_DECREF(delta);
}
else {
- struct tm time;
- time_t timestamp;
- memset((void *) &time, '\0', sizeof(struct tm));
- time.tm_year = GET_YEAR(self) - 1900;
- time.tm_mon = GET_MONTH(self) - 1;
- time.tm_mday = GET_DAY(self);
- time.tm_hour = DATE_GET_HOUR(self);
- time.tm_min = DATE_GET_MINUTE(self);
- time.tm_sec = DATE_GET_SECOND(self);
- time.tm_wday = -1;
- time.tm_isdst = -1;
- timestamp = mktime(&time);
- if (timestamp == (time_t)(-1)
-#ifndef _AIX
- /* Return value of -1 does not necessarily mean an error,
- * but tm_wday cannot remain set to -1 if mktime succeeded. */
- && time.tm_wday == -1
-#else
- /* on AIX, tm_wday is always sets, even on error */
-#endif
- )
- {
- PyErr_SetString(PyExc_OverflowError,
- "timestamp out of range");
+ long long seconds;
+ seconds = local_to_seconds(GET_YEAR(self),
+ GET_MONTH(self),
+ GET_DAY(self),
+ DATE_GET_HOUR(self),
+ DATE_GET_MINUTE(self),
+ DATE_GET_SECOND(self),
+ DATE_GET_FOLD(self));
+ if (seconds == -1)
return NULL;
- }
- result = PyFloat_FromDouble(timestamp + DATE_GET_MICROSECOND(self) / 1e6);
+ result = PyFloat_FromDouble(seconds - EPOCH_SECONDS +
+ DATE_GET_MICROSECOND(self) / 1e6);
}
return result;
}
@@ -4956,7 +5344,8 @@ datetime_gettime(PyDateTime_DateTime *self)
DATE_GET_MINUTE(self),
DATE_GET_SECOND(self),
DATE_GET_MICROSECOND(self),
- Py_None);
+ Py_None,
+ DATE_GET_FOLD(self));
}
static PyObject *
@@ -4966,7 +5355,8 @@ datetime_gettimetz(PyDateTime_DateTime *self)
DATE_GET_MINUTE(self),
DATE_GET_SECOND(self),
DATE_GET_MICROSECOND(self),
- GET_DT_TZINFO(self));
+ GET_DT_TZINFO(self),
+ DATE_GET_FOLD(self));
}
static PyObject *
@@ -5018,7 +5408,7 @@ datetime_utctimetuple(PyDateTime_DateTime *self)
* __getstate__ isn't exposed.
*/
static PyObject *
-datetime_getstate(PyDateTime_DateTime *self)
+datetime_getstate(PyDateTime_DateTime *self, int proto)
{
PyObject *basestate;
PyObject *result = NULL;
@@ -5026,6 +5416,9 @@ datetime_getstate(PyDateTime_DateTime *self)
basestate = PyBytes_FromStringAndSize((char *)self->data,
_PyDateTime_DATETIME_DATASIZE);
if (basestate != NULL) {
+ if (proto > 3 && DATE_GET_FOLD(self))
+ /* Set the first bit of the third byte */
+ PyBytes_AS_STRING(basestate)[2] |= (1 << 7);
if (! HASTZINFO(self) || self->tzinfo == Py_None)
result = PyTuple_Pack(1, basestate);
else
@@ -5036,9 +5429,19 @@ datetime_getstate(PyDateTime_DateTime *self)
}
static PyObject *
+datetime_reduce_ex(PyDateTime_DateTime *self, PyObject *args)
+{
+ int proto;
+ if (!PyArg_ParseTuple(args, "i:__reduce_ex__", &proto))
+ return NULL;
+
+ return Py_BuildValue("(ON)", Py_TYPE(self), datetime_getstate(self, proto));
+}
+
+static PyObject *
datetime_reduce(PyDateTime_DateTime *self, PyObject *arg)
{
- return Py_BuildValue("(ON)", Py_TYPE(self), datetime_getstate(self));
+ return Py_BuildValue("(ON)", Py_TYPE(self), datetime_getstate(self, 2));
}
static PyMethodDef datetime_methods[] = {
@@ -5093,9 +5496,12 @@ static PyMethodDef datetime_methods[] = {
{"isoformat", (PyCFunction)datetime_isoformat, METH_VARARGS | METH_KEYWORDS,
PyDoc_STR("[sep] -> string in ISO 8601 format, "
- "YYYY-MM-DDTHH:MM:SS[.mmmmmm][+HH:MM].\n\n"
+ "YYYY-MM-DDT[HH[:MM[:SS[.mmm[uuu]]]]][+HH:MM].\n"
"sep is used to separate the year from the time, and "
- "defaults to 'T'.")},
+ "defaults to 'T'.\n"
+ "timespec specifies what components of the time to include"
+ " (allowed values are 'auto', 'hours', 'minutes', 'seconds',"
+ " 'milliseconds', and 'microseconds').\n")},
{"utcoffset", (PyCFunction)datetime_utcoffset, METH_NOARGS,
PyDoc_STR("Return self.tzinfo.utcoffset(self).")},
@@ -5112,13 +5518,16 @@ static PyMethodDef datetime_methods[] = {
{"astimezone", (PyCFunction)datetime_astimezone, METH_VARARGS | METH_KEYWORDS,
PyDoc_STR("tz -> convert to local time in new timezone tz\n")},
+ {"__reduce_ex__", (PyCFunction)datetime_reduce_ex, METH_VARARGS,
+ PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")},
+
{"__reduce__", (PyCFunction)datetime_reduce, METH_NOARGS,
PyDoc_STR("__reduce__() -> (cls, state)")},
{NULL, NULL}
};
-static char datetime_doc[] =
+static const char datetime_doc[] =
PyDoc_STR("datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])\n\
\n\
The year, month and day arguments are required. tzinfo may be None, or an\n\
@@ -5201,7 +5610,9 @@ static PyDateTime_CAPI CAPI = {
new_time_ex,
new_delta_ex,
datetime_fromtimestamp,
- date_fromtimestamp
+ date_fromtimestamp,
+ new_datetime_ex2,
+ new_time_ex2
};
@@ -5282,12 +5693,12 @@ PyInit__datetime(void)
/* time values */
d = PyDateTime_TimeType.tp_dict;
- x = new_time(0, 0, 0, 0, Py_None);
+ x = new_time(0, 0, 0, 0, Py_None, 0);
if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
return NULL;
Py_DECREF(x);
- x = new_time(23, 59, 59, 999999, Py_None);
+ x = new_time(23, 59, 59, 999999, Py_None, 0);
if (x == NULL || PyDict_SetItemString(d, "max", x) < 0)
return NULL;
Py_DECREF(x);
@@ -5300,12 +5711,12 @@ PyInit__datetime(void)
/* datetime values */
d = PyDateTime_DateTimeType.tp_dict;
- x = new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None);
+ x = new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None, 0);
if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
return NULL;
Py_DECREF(x);
- x = new_datetime(MAXYEAR, 12, 31, 23, 59, 59, 999999, Py_None);
+ x = new_datetime(MAXYEAR, 12, 31, 23, 59, 59, 999999, Py_None, 0);
if (x == NULL || PyDict_SetItemString(d, "max", x) < 0)
return NULL;
Py_DECREF(x);
@@ -5347,7 +5758,7 @@ PyInit__datetime(void)
/* Epoch */
PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0,
- PyDateTime_TimeZone_UTC);
+ PyDateTime_TimeZone_UTC, 0);
if (PyDateTime_Epoch == NULL)
return NULL;
@@ -5382,19 +5793,19 @@ PyInit__datetime(void)
/* A 4-year cycle has an extra leap day over what we'd get from
* pasting together 4 single years.
*/
- assert(DI4Y == 4 * 365 + 1);
+ Py_BUILD_ASSERT(DI4Y == 4 * 365 + 1);
assert(DI4Y == days_before_year(4+1));
/* Similarly, a 400-year cycle has an extra leap day over what we'd
* get from pasting together 4 100-year cycles.
*/
- assert(DI400Y == 4 * DI100Y + 1);
+ Py_BUILD_ASSERT(DI400Y == 4 * DI100Y + 1);
assert(DI400Y == days_before_year(400+1));
/* OTOH, a 100-year cycle has one fewer leap day than we'd get from
* pasting together 25 4-year cycles.
*/
- assert(DI100Y == 25 * DI4Y - 1);
+ Py_BUILD_ASSERT(DI100Y == 25 * DI4Y - 1);
assert(DI100Y == days_before_year(100+1));
one = PyLong_FromLong(1);