Skip to content

Commit 57327ab

Browse files
committed
add C implementation
1 parent 2078eb4 commit 57327ab

File tree

1 file changed

+58
-22
lines changed

1 file changed

+58
-22
lines changed

Modules/_datetimemodule.c

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3471,10 +3471,15 @@ date_repr(PyDateTime_Date *self)
34713471
}
34723472

34733473
static PyObject *
3474-
date_isoformat(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored))
3474+
date_isoformat(PyDateTime_Date *self, PyObject *args, PyObject *kw)
34753475
{
3476-
return PyUnicode_FromFormat("%04d-%02d-%02d",
3477-
GET_YEAR(self), GET_MONTH(self), GET_DAY(self));
3476+
int basic = 0;
3477+
static char *keywords[] = {"basic", NULL};
3478+
if (!PyArg_ParseTupleAndKeywords(args, kw, "|p:isoformat", keywords, &basic)) {
3479+
return NULL;
3480+
}
3481+
const char *format = basic ? "%04d%02d%02d" : "%04d-%02d-%02d";
3482+
return PyUnicode_FromFormat(format, GET_YEAR(self), GET_MONTH(self), GET_DAY(self));
34783483
}
34793484

34803485
/* str() calls the appropriate isoformat() method. */
@@ -3868,8 +3873,9 @@ static PyMethodDef date_methods[] = {
38683873
PyDoc_STR("Return a named tuple containing ISO year, week number, and "
38693874
"weekday.")},
38703875

3871-
{"isoformat", (PyCFunction)date_isoformat, METH_NOARGS,
3872-
PyDoc_STR("Return string in ISO 8601 format, YYYY-MM-DD.")},
3876+
{"isoformat", (PyCFunction)date_isoformat, METH_VARARGS | METH_KEYWORDS,
3877+
PyDoc_STR("Return string in ISO 8601 format, YYYY-MM-DD.\n"
3878+
"If basic is true, uses the basic format, YYYYMMDD.")},
38733879

38743880
{"isoweekday", (PyCFunction)date_isoweekday, METH_NOARGS,
38753881
PyDoc_STR("Return the day of the week represented by the date.\n"
@@ -4654,20 +4660,33 @@ time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw)
46544660
{
46554661
char buf[100];
46564662
const char *timespec = NULL;
4657-
static char *keywords[] = {"timespec", NULL};
4663+
int basic = 0;
4664+
static char *keywords[] = {"timespec", "basic", NULL};
46584665
PyObject *result;
46594666
int us = TIME_GET_MICROSECOND(self);
4660-
static const char *specs[][2] = {
4667+
static const char *specs_extended[][2] = {
46614668
{"hours", "%02d"},
46624669
{"minutes", "%02d:%02d"},
46634670
{"seconds", "%02d:%02d:%02d"},
46644671
{"milliseconds", "%02d:%02d:%02d.%03d"},
46654672
{"microseconds", "%02d:%02d:%02d.%06d"},
46664673
};
4667-
size_t given_spec;
4674+
static const char *specs_basic[][2] = {
4675+
{"hours", "%02d"},
4676+
{"minutes", "%02d%02d"},
4677+
{"seconds", "%02d%02d%02d"},
4678+
{"milliseconds", "%02d%02d%02d.%03d"},
4679+
{"microseconds", "%02d%02d%02d.%06d"},
4680+
};
46684681

4669-
if (!PyArg_ParseTupleAndKeywords(args, kw, "|s:isoformat", keywords, &timespec))
4682+
if (!PyArg_ParseTupleAndKeywords(args, kw, "|sp:isoformat", keywords, &timespec, &basic)) {
46704683
return NULL;
4684+
}
4685+
4686+
const char *(*specs)[2] = basic ? specs_basic : specs_extended;
4687+
// due to array decaying, Py_ARRAY_LENGTH(specs) would return 0
4688+
size_t specs_count = basic ? Py_ARRAY_LENGTH(specs_basic) : Py_ARRAY_LENGTH(specs_extended);
4689+
size_t given_spec;
46714690

46724691
if (timespec == NULL || strcmp(timespec, "auto") == 0) {
46734692
if (us == 0) {
@@ -4680,7 +4699,7 @@ time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw)
46804699
}
46814700
}
46824701
else {
4683-
for (given_spec = 0; given_spec < Py_ARRAY_LENGTH(specs); given_spec++) {
4702+
for (given_spec = 0; given_spec < specs_count; given_spec++) {
46844703
if (strcmp(timespec, specs[given_spec][0]) == 0) {
46854704
if (given_spec == 3) {
46864705
/* milliseconds */
@@ -4691,7 +4710,7 @@ time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw)
46914710
}
46924711
}
46934712

4694-
if (given_spec == Py_ARRAY_LENGTH(specs)) {
4713+
if (given_spec == specs_count) {
46954714
PyErr_Format(PyExc_ValueError, "Unknown timespec value");
46964715
return NULL;
46974716
}
@@ -4705,8 +4724,8 @@ time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw)
47054724
return result;
47064725

47074726
/* We need to append the UTC offset. */
4708-
if (format_utcoffset(buf, sizeof(buf), ":", self->tzinfo,
4709-
Py_None) < 0) {
4727+
const char *offset_sep = basic ? "" : ":";
4728+
if (format_utcoffset(buf, sizeof(buf), offset_sep, self->tzinfo, Py_None) < 0) {
47104729
Py_DECREF(result);
47114730
return NULL;
47124731
}
@@ -5006,6 +5025,8 @@ static PyMethodDef time_methods[] = {
50065025
{"isoformat", _PyCFunction_CAST(time_isoformat), METH_VARARGS | METH_KEYWORDS,
50075026
PyDoc_STR("Return string in ISO 8601 format, [HH[:MM[:SS[.mmm[uuu]]]]]"
50085027
"[+HH:MM].\n\n"
5028+
"If basic is true, separators ':' are removed "
5029+
"from the output (e.g., HHMMSS).\n"
50095030
"The optional argument timespec specifies the number "
50105031
"of additional terms\nof the time to include. Valid "
50115032
"options are 'auto', 'hours', 'minutes',\n'seconds', "
@@ -6045,21 +6066,34 @@ datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
60456066
{
60466067
int sep = 'T';
60476068
char *timespec = NULL;
6048-
static char *keywords[] = {"sep", "timespec", NULL};
6069+
int basic = 0;
6070+
static char *keywords[] = {"sep", "timespec", "basic", NULL};
60496071
char buffer[100];
60506072
PyObject *result = NULL;
60516073
int us = DATE_GET_MICROSECOND(self);
6052-
static const char *specs[][2] = {
6074+
static const char *specs_extended[][2] = {
60536075
{"hours", "%04d-%02d-%02d%c%02d"},
60546076
{"minutes", "%04d-%02d-%02d%c%02d:%02d"},
60556077
{"seconds", "%04d-%02d-%02d%c%02d:%02d:%02d"},
60566078
{"milliseconds", "%04d-%02d-%02d%c%02d:%02d:%02d.%03d"},
60576079
{"microseconds", "%04d-%02d-%02d%c%02d:%02d:%02d.%06d"},
60586080
};
6059-
size_t given_spec;
6081+
static const char *specs_basic[][2] = {
6082+
{"hours", "%04d%02d%02d%c%02d"},
6083+
{"minutes", "%04d%02d%02d%c%02d%02d"},
6084+
{"seconds", "%04d%02d%02d%c%02d%02d%02d"},
6085+
{"milliseconds", "%04d%02d%02d%c%02d%02d%02d.%03d"},
6086+
{"microseconds", "%04d%02d%02d%c%02d%02d%02d.%06d"},
6087+
};
60606088

6061-
if (!PyArg_ParseTupleAndKeywords(args, kw, "|Cs:isoformat", keywords, &sep, &timespec))
6089+
if (!PyArg_ParseTupleAndKeywords(args, kw, "|Csp:isoformat", keywords, &sep, &timespec, &basic)) {
60626090
return NULL;
6091+
}
6092+
6093+
const char *(*specs)[2] = basic ? specs_basic : specs_extended;
6094+
// due to array decaying, Py_ARRAY_LENGTH(specs) would return 0
6095+
size_t specs_count = basic ? Py_ARRAY_LENGTH(specs_basic) : Py_ARRAY_LENGTH(specs_extended);
6096+
size_t given_spec;
60636097

60646098
if (timespec == NULL || strcmp(timespec, "auto") == 0) {
60656099
if (us == 0) {
@@ -6072,7 +6106,7 @@ datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
60726106
}
60736107
}
60746108
else {
6075-
for (given_spec = 0; given_spec < Py_ARRAY_LENGTH(specs); given_spec++) {
6109+
for (given_spec = 0; given_spec < specs_count; given_spec++) {
60766110
if (strcmp(timespec, specs[given_spec][0]) == 0) {
60776111
if (given_spec == 3) {
60786112
us = us / 1000;
@@ -6082,7 +6116,7 @@ datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
60826116
}
60836117
}
60846118

6085-
if (given_spec == Py_ARRAY_LENGTH(specs)) {
6119+
if (given_spec == specs_count) {
60866120
PyErr_Format(PyExc_ValueError, "Unknown timespec value");
60876121
return NULL;
60886122
}
@@ -6098,8 +6132,8 @@ datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)
60986132
return result;
60996133

61006134
/* We need to append the UTC offset. */
6101-
if (format_utcoffset(buffer, sizeof(buffer), ":", self->tzinfo,
6102-
(PyObject *)self) < 0) {
6135+
const char *offset_sep = basic ? "" : ":";
6136+
if (format_utcoffset(buffer, sizeof(buffer), offset_sep, self->tzinfo, (PyObject *)self) < 0) {
61036137
Py_DECREF(result);
61046138
return NULL;
61056139
}
@@ -6863,9 +6897,11 @@ static PyMethodDef datetime_methods[] = {
68636897

68646898
{"isoformat", _PyCFunction_CAST(datetime_isoformat), METH_VARARGS | METH_KEYWORDS,
68656899
PyDoc_STR("[sep] -> string in ISO 8601 format, "
6866-
"YYYY-MM-DDT[HH[:MM[:SS[.mmm[uuu]]]]][+HH:MM].\n"
6900+
"YYYY-MM-DDT[HH[:MM[:SS[.mmm[uuu]]]]][+HH:MM].\n\n"
68676901
"sep is used to separate the year from the time, and "
68686902
"defaults to 'T'.\n"
6903+
"If basic is true, separators ':' and '-' are removed "
6904+
"from the output (e.g., YYYYMMDDTHHMMSS).\n"
68696905
"The optional argument timespec specifies the number "
68706906
"of additional terms\nof the time to include. Valid "
68716907
"options are 'auto', 'hours', 'minutes',\n'seconds', "

0 commit comments

Comments
 (0)