diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -55,6 +55,54 @@ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/* This wrapper encapsulates a time_t value that can also be "not set". + Typically, an unset value is understood to refer to the current time + as returned by time(NULL). + + (The maybe prefix refers to the similar Haskell datatype) +*/ +typedef struct { + int is_nothing; + time_t value; +} maybe_time_t; +#define MAYBE_TIME_T_DEFAULT {1, 0} + +/* Return encapsulated value or, if not set, current time */ +time_t unwrap_maybe_time_t(maybe_time_t when) +{ + if(when.is_nothing) + return time(NULL); + else + return when.value; +} + +/* C Converter for argument clinic */ +static int +PyObject_to_maybe_time_t(PyObject *obj, maybe_time_t *when) +{ + if (obj == NULL || obj == Py_None) { + when->is_nothing = 1; + } + else { + if (_PyTime_ObjectToTime_t(obj, &(when->value)) == -1) + return 0; + when->is_nothing = 0; + } + return 1; +} + + +/*[python input] +class maybe_time_t_converter(CConverter): + type = 'maybe_time_t' + converter = 'PyObject_to_maybe_time_t' + + def converter_init(self): + if self.default is None: + self.c_default = 'MAYBE_TIME_T_DEFAULT' +[python start generated code]*/ +/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + /*[clinic input] time.time @@ -491,40 +539,57 @@ return v; } -/* Parse arg tuple that can contain an optional float-or-None value; - format needs to be "|O:name". - Returns non-zero on success (parallels PyArg_ParseTuple). -*/ -static int -parse_time_t_args(PyObject *args, char *format, time_t *pwhen) + +/*[clinic input] +time.gmtime + + seconds: maybe_time_t=None + / + +Convert seconds since the Epoch to a time tuple expressing UTC. + +When 'seconds' is not passed in, convert the current time instead. If +the platform supports the tm_gmtoff and tm_zone, they are available as +attributes only. +[clinic start generated code]*/ + +PyDoc_STRVAR(time_gmtime__doc__, +"gmtime(module, seconds=None)\n" +"Convert seconds since the Epoch to a time tuple expressing UTC.\n" +"\n" +"When \'seconds\' is not passed in, convert the current time instead. If\n" +"the platform supports the tm_gmtoff and tm_zone, they are available as\n" +"attributes only."); + +#define TIME_GMTIME_METHODDEF \ + {"gmtime", (PyCFunction)time_gmtime, METH_VARARGS, time_gmtime__doc__}, + +static PyObject * +time_gmtime_impl(PyModuleDef *module, maybe_time_t seconds); + +static PyObject * +time_gmtime(PyModuleDef *module, PyObject *args) { - PyObject *ot = NULL; - time_t whent; + PyObject *return_value = NULL; + maybe_time_t seconds = MAYBE_TIME_T_DEFAULT; - if (!PyArg_ParseTuple(args, format, &ot)) - return 0; - if (ot == NULL || ot == Py_None) { - whent = time(NULL); - } - else { - if (_PyTime_ObjectToTime_t(ot, &whent) == -1) - return 0; - } - *pwhen = whent; - return 1; + if (!PyArg_ParseTuple(args, + "|O&:gmtime", + PyObject_to_maybe_time_t, &seconds)) + goto exit; + return_value = time_gmtime_impl(module, seconds); + +exit: + return return_value; } -/* AC 3.5: No Python value available that gives same behavior - as when not specifying parameter */ static PyObject * -time_gmtime(PyObject *self, PyObject *args) +time_gmtime_impl(PyModuleDef *module, maybe_time_t seconds) +/*[clinic end generated code: checksum=374137d43bf5de6c8dfe4cc7ef2ca8b6589dfddf]*/ { - time_t when; struct tm buf, *local; - - if (!parse_time_t_args(args, "|O:gmtime", &when)) - return NULL; - + time_t when = unwrap_maybe_time_t(seconds); + errno = 0; local = gmtime(&when); if (local == NULL) { @@ -538,15 +603,6 @@ return tmtotuple(&buf); } -PyDoc_STRVAR(gmtime_doc, -"gmtime([seconds]) -> (tm_year, tm_mon, tm_mday, tm_hour, tm_min,\n\ - tm_sec, tm_wday, tm_yday, tm_isdst)\n\ -\n\ -Convert seconds since the Epoch to a time tuple expressing UTC (a.k.a.\n\ -GMT). When 'seconds' is not passed in, convert the current time instead.\n\ -\n\ -If the platform supports the tm_gmtoff and tm_zone, they are available as\n\ -attributes only."); static int pylocaltime(time_t *timep, struct tm *result) @@ -568,27 +624,57 @@ return 0; } -/* AC 3.5: No Python value available that gives same behavior - as when not specifying parameter */ +/*[clinic input] +time.localtime + + seconds: maybe_time_t=None + / + +Convert seconds since the Epoch to a time tuple expressing local time. + +When 'seconds' is not passed in, convert the current time instead. If +[clinic start generated code]*/ + +PyDoc_STRVAR(time_localtime__doc__, +"localtime(module, seconds=None)\n" +"Convert seconds since the Epoch to a time tuple expressing local time.\n" +"\n" +"When \'seconds\' is not passed in, convert the current time instead. If"); + +#define TIME_LOCALTIME_METHODDEF \ + {"localtime", (PyCFunction)time_localtime, METH_VARARGS, time_localtime__doc__}, + static PyObject * -time_localtime(PyObject *self, PyObject *args) +time_localtime_impl(PyModuleDef *module, maybe_time_t seconds); + +static PyObject * +time_localtime(PyModuleDef *module, PyObject *args) { - time_t when; + PyObject *return_value = NULL; + maybe_time_t seconds = MAYBE_TIME_T_DEFAULT; + + if (!PyArg_ParseTuple(args, + "|O&:localtime", + PyObject_to_maybe_time_t, &seconds)) + goto exit; + return_value = time_localtime_impl(module, seconds); + +exit: + return return_value; +} + +static PyObject * +time_localtime_impl(PyModuleDef *module, maybe_time_t seconds) +/*[clinic end generated code: checksum=65ef92be6406823f42469f88aa5d2b132f14fede]*/ +{ struct tm buf; + time_t when = unwrap_maybe_time_t(seconds); - if (!parse_time_t_args(args, "|O:localtime", &when)) - return NULL; if (pylocaltime(&when, &buf) == -1) return NULL; return tmtotuple(&buf); } -PyDoc_STRVAR(localtime_doc, -"localtime([seconds]) -> (tm_year,tm_mon,tm_mday,tm_hour,tm_min,\n\ - tm_sec,tm_wday,tm_yday,tm_isdst)\n\ -\n\ -Convert seconds since the Epoch to a time tuple expressing local time.\n\ -When 'seconds' is not passed in, convert the current time instead."); /* Convert 9-item tuple to tm structure. Return 1 on success, set * an exception and return 0 on error. @@ -703,26 +789,7 @@ /* wcsftime() doesn't format correctly time zones, see issue #10653 */ # undef HAVE_WCSFTIME #endif -#define STRFTIME_FORMAT_CODES \ -"Commonly used format codes:\n\ -\n\ -%Y Year with century as a decimal number.\n\ -%m Month as a decimal number [01,12].\n\ -%d Day of the month as a decimal number [01,31].\n\ -%H Hour (24-hour clock) as a decimal number [00,23].\n\ -%M Minute as a decimal number [00,59].\n\ -%S Second as a decimal number [00,61].\n\ -%z Time zone offset from UTC.\n\ -%a Locale's abbreviated weekday name.\n\ -%A Locale's full weekday name.\n\ -%b Locale's abbreviated month name.\n\ -%B Locale's full month name.\n\ -%c Locale's appropriate date and time representation.\n\ -%I Hour (12-hour clock) as a decimal number [01,12].\n\ -%p Locale's equivalent of either AM or PM.\n\ -\n\ -Other codes may be available on your platform. See documentation for\n\ -the C library strftime function.\n" + #ifdef HAVE_STRFTIME #ifdef HAVE_WCSFTIME @@ -735,12 +802,95 @@ #define time_strlen strlen #endif -/* AC 3.5: No Python value available that gives same behavior - as when not specifying parameter */ +/*[clinic input] +time.strftime + + format_arg: unicode + tup: object=NULL + / + +Convert a time tuple to a string according to a format specification. + +When the time tuple is not present, current time as returned by +localtime() is used. + +Commonly used format codes are: + +%Y Year with century as a decimal number. +%m Month as a decimal number [01,12]. +%d Day of the month as a decimal number [01,31]. +%H Hour (24-hour clock) as a decimal number [00,23]. +%M Minute as a decimal number [00,59]. +%S Second as a decimal number [00,61]. +%z Time zone offset from UTC. +%a Locale's abbreviated weekday name. +%A Locale's full weekday name. +%b Locale's abbreviated month name. +%B Locale's full month name. +%c Locale's appropriate date and time representation. +%I Hour (12-hour clock) as a decimal number [01,12]. +%p Locale's equivalent of either AM or PM. + +For the full list of format codes, see the library reference manual +and the documentation for the C library strftime function on your +platform. +[clinic start generated code]*/ + +PyDoc_STRVAR(time_strftime__doc__, +"strftime(module, format_arg, tup=None)\n" +"Convert a time tuple to a string according to a format specification.\n" +"\n" +"When the time tuple is not present, current time as returned by\n" +"localtime() is used.\n" +"\n" +"Commonly used format codes are:\n" +"\n" +"%Y Year with century as a decimal number.\n" +"%m Month as a decimal number [01,12].\n" +"%d Day of the month as a decimal number [01,31].\n" +"%H Hour (24-hour clock) as a decimal number [00,23].\n" +"%M Minute as a decimal number [00,59].\n" +"%S Second as a decimal number [00,61].\n" +"%z Time zone offset from UTC.\n" +"%a Locale\'s abbreviated weekday name.\n" +"%A Locale\'s full weekday name.\n" +"%b Locale\'s abbreviated month name.\n" +"%B Locale\'s full month name.\n" +"%c Locale\'s appropriate date and time representation.\n" +"%I Hour (12-hour clock) as a decimal number [01,12].\n" +"%p Locale\'s equivalent of either AM or PM.\n" +"\n" +"For the full list of format codes, see the library reference manual\n" +"and the documentation for the C library strftime function on your\n" +"platform."); + +#define TIME_STRFTIME_METHODDEF \ + {"strftime", (PyCFunction)time_strftime, METH_VARARGS, time_strftime__doc__}, + static PyObject * -time_strftime(PyObject *self, PyObject *args) +time_strftime_impl(PyModuleDef *module, PyObject *format_arg, PyObject *tup); + +static PyObject * +time_strftime(PyModuleDef *module, PyObject *args) { + PyObject *return_value = NULL; + PyObject *format_arg; PyObject *tup = NULL; + + if (!PyArg_ParseTuple(args, + "U|O:strftime", + &format_arg, &tup)) + goto exit; + return_value = time_strftime_impl(module, format_arg, tup); + +exit: + return return_value; +} + +static PyObject * +time_strftime_impl(PyModuleDef *module, PyObject *format_arg, PyObject *tup) +/*[clinic end generated code: checksum=27ba5a127d00ac4fb0b7280276fd8ea5a9196ed9]*/ +{ struct tm buf; const time_char *fmt; #ifdef HAVE_WCSFTIME @@ -748,7 +898,6 @@ #else PyObject *format; #endif - PyObject *format_arg; size_t fmtlen, buflen; time_char *outbuf = NULL; size_t i; @@ -756,12 +905,6 @@ memset((void *) &buf, '\0', sizeof(buf)); - /* Will always expect a unicode string to be passed as format. - Given that there's no str type anymore in py3k this seems safe. - */ - if (!PyArg_ParseTuple(args, "U|O:strftime", &format_arg, &tup)) - return NULL; - if (tup == NULL) { time_t tt = time(NULL); if (pylocaltime(&tt, &buf) == -1) @@ -889,20 +1032,13 @@ #undef time_char #undef format_time -PyDoc_STRVAR(strftime_doc, -"strftime(format[, tuple]) -> string\n\ -\n\ -Convert a time tuple to a string according to a format specification.\n\ -See the library reference manual for formatting codes. When the time tuple\n\ -is not present, current time as returned by localtime() is used.\n\ -\n" STRFTIME_FORMAT_CODES); #endif /* HAVE_STRFTIME */ /*[clinic input] time.strptime string: str - format: str + format: str="%a %b %d %H:%M:%S %Y" / Parse a string to a time tuple according to a format specification. @@ -930,7 +1066,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(time_strptime__doc__, -"strptime(module, string, format)\n" +"strptime(module, string, format=\'%a %b %d %H:%M:%S %Y\')\n" "Parse a string to a time tuple according to a format specification.\n" "\n" "For the full list of format codes, see the library reference manual\n" @@ -965,10 +1101,10 @@ { PyObject *return_value = NULL; const char *string; - const char *format; + const char *format = "%a %b %d %H:%M:%S %Y"; if (!PyArg_ParseTuple(args, - "ss:strptime", + "s|s:strptime", &string, &format)) goto exit; return_value = time_strptime_impl(module, string, format); @@ -979,7 +1115,7 @@ static PyObject * time_strptime_impl(PyModuleDef *module, const char *string, const char *format) -/*[clinic end generated code: checksum=0cd895d8b59fa74977f682c933cb12030496a0c9]*/ +/*[clinic end generated code: checksum=d3d2583590c0ea7724d2b72538f5e7cde4aec2a8]*/ { PyObject *strptime_module = PyImport_ImportModule("_strptime"); PyObject *strptime_result; @@ -1023,16 +1159,53 @@ 1900 + timeptr->tm_year); } -/* AC 3.5: No Python value available that gives same behavior - as when not specifying parameter */ +/*[clinic input] +time.asctime + + tup: object=NULL + / + +Convert a time tuple to a string, e.g. 'Sat Jun 06 16:26:11 1998'. + +When the *tup* is None, current time as returned by localtime() is +used. +[clinic start generated code]*/ + +PyDoc_STRVAR(time_asctime__doc__, +"asctime(module, tup=None)\n" +"Convert a time tuple to a string, e.g. \'Sat Jun 06 16:26:11 1998\'.\n" +"\n" +"When the *tup* is None, current time as returned by localtime() is\n" +"used."); + +#define TIME_ASCTIME_METHODDEF \ + {"asctime", (PyCFunction)time_asctime, METH_VARARGS, time_asctime__doc__}, + static PyObject * -time_asctime(PyObject *self, PyObject *args) +time_asctime_impl(PyModuleDef *module, PyObject *tup); + +static PyObject * +time_asctime(PyModuleDef *module, PyObject *args) { + PyObject *return_value = NULL; PyObject *tup = NULL; + + if (!PyArg_UnpackTuple(args, "asctime", + 0, 1, + &tup)) + goto exit; + return_value = time_asctime_impl(module, tup); + +exit: + return return_value; +} + +static PyObject * +time_asctime_impl(PyModuleDef *module, PyObject *tup) +/*[clinic end generated code: checksum=5a972155e8c9449b3f4fc12a4ff42ea7fbd51e60]*/ +{ struct tm buf; - if (!PyArg_UnpackTuple(args, "asctime", 0, 1, &tup)) - return NULL; if (tup == NULL) { time_t tt = time(NULL); if (pylocaltime(&tt, &buf) == -1) @@ -1043,36 +1216,62 @@ return _asctime(&buf); } -PyDoc_STRVAR(asctime_doc, -"asctime([tuple]) -> string\n\ -\n\ -Convert a time tuple to a string, e.g. 'Sat Jun 06 16:26:11 1998'.\n\ -When the time tuple is not present, current time as returned by localtime()\n\ -is used."); -/* AC 3.5: No Python value available that gives same behavior - as when not specifying parameter */ +/*[clinic input] +time.ctime + + seconds: maybe_time_t=None + / + +Convert a time in seconds since the Epoch to a string in local time. + +This is equivalent to asctime(localtime(seconds)). When the time tuple is +not present, current time as returned by localtime() is used. +[clinic start generated code]*/ + +PyDoc_STRVAR(time_ctime__doc__, +"ctime(module, seconds=None)\n" +"Convert a time in seconds since the Epoch to a string in local time.\n" +"\n" +"This is equivalent to asctime(localtime(seconds)). When the time tuple is\n" +"not present, current time as returned by localtime() is used."); + +#define TIME_CTIME_METHODDEF \ + {"ctime", (PyCFunction)time_ctime, METH_VARARGS, time_ctime__doc__}, + static PyObject * -time_ctime(PyObject *self, PyObject *args) +time_ctime_impl(PyModuleDef *module, maybe_time_t seconds); + +static PyObject * +time_ctime(PyModuleDef *module, PyObject *args) { - time_t tt; + PyObject *return_value = NULL; + maybe_time_t seconds = MAYBE_TIME_T_DEFAULT; + + if (!PyArg_ParseTuple(args, + "|O&:ctime", + PyObject_to_maybe_time_t, &seconds)) + goto exit; + return_value = time_ctime_impl(module, seconds); + +exit: + return return_value; +} + +static PyObject * +time_ctime_impl(PyModuleDef *module, maybe_time_t seconds) +/*[clinic end generated code: checksum=788d7c030e7a227cb4fc259b112b9d52751b0f75]*/ +{ struct tm buf; - if (!parse_time_t_args(args, "|O:ctime", &tt)) - return NULL; - if (pylocaltime(&tt, &buf) == -1) + time_t when = unwrap_maybe_time_t(seconds); + + if (pylocaltime(&when, &buf) == -1) return NULL; return _asctime(&buf); } -PyDoc_STRVAR(ctime_doc, -"ctime(seconds) -> string\n\ -\n\ -Convert a time in seconds since the Epoch to a string in local time.\n\ -This is equivalent to asctime(localtime(seconds)). When the time tuple is\n\ -not present, current time as returned by localtime() is used."); #ifdef HAVE_MKTIME -/* AC 3.4: Not sure how to do this without excessive code duplication */ static PyObject * time_mktime(PyObject *self, PyObject *tup) { @@ -1795,15 +1994,15 @@ TIME_CLOCK_GETRES_METHODDEF #endif TIME_SLEEP_METHODDEF - {"gmtime", time_gmtime, METH_VARARGS, gmtime_doc}, - {"localtime", time_localtime, METH_VARARGS, localtime_doc}, - {"asctime", time_asctime, METH_VARARGS, asctime_doc}, - {"ctime", time_ctime, METH_VARARGS, ctime_doc}, + TIME_GMTIME_METHODDEF + TIME_LOCALTIME_METHODDEF + TIME_ASCTIME_METHODDEF + TIME_CTIME_METHODDEF #ifdef HAVE_MKTIME {"mktime", time_mktime, METH_O, mktime_doc}, #endif #ifdef HAVE_STRFTIME - {"strftime", time_strftime, METH_VARARGS, strftime_doc}, + TIME_STRFTIME_METHODDEF #endif TIME_STRPTIME_METHODDEF #ifdef HAVE_WORKING_TZSET