Index: py3k/Doc/library/datetime.rst =================================================================== --- py3k/Doc/library/datetime.rst (revision 81033) +++ py3k/Doc/library/datetime.rst (working copy) @@ -1003,6 +1003,21 @@ '2002-12-25 00:00:00-06:39' +.. method:: datetime.rfcformat(default_utcoffset='-00:00') + + Return a string representing the date and time in RFC 3339 format, + YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM or, if :attr:`microsecond` is 0, + YYYY-MM-DDTHH:MM:SS+HH:MM + + This method differs from :meth:`isoformat` in that the separator is + always 'T', and the string always contains the UTC offset. For + naive instances the default UTC offset is *default_utcoffset*. + For example, + + >>> datetime(2010, 4, 12).rfcformat() + '2010-04-12T00:00:00-00:00' + + .. method:: datetime.__str__() For a :class:`datetime` instance *d*, ``str(d)`` is equivalent to Index: py3k/Lib/test/test_datetime.py =================================================================== --- py3k/Lib/test/test_datetime.py (revision 81033) +++ py3k/Lib/test/test_datetime.py (working copy) @@ -1243,6 +1243,34 @@ # str is ISO format with the separator forced to a blank. self.assertEqual(str(t), "0002-03-02 00:00:00") + def test_rfcformat(self): + t = self.theclass(2, 3, 2, 4, 5, 1, 123) + self.assertEqual(t.rfcformat(), "0002-03-02T04:05:01.000123-00:00") + + t = self.theclass(2, 3, 2, 4, 5, 1, 0) + self.assertEqual(t.rfcformat(), "0002-03-02T04:05:01-00:00") + + t = self.theclass(2, 3, 2) + self.assertEqual(t.rfcformat(), "0002-03-02T00:00:00-00:00") + + # with default UTC offset argument: + self.assertEqual(t.rfcformat("Z"), "0002-03-02T00:00:00Z") + self.assertEqual(t.rfcformat("+00:00"), "0002-03-02T00:00:00+00:00") + self.assertEqual(t.rfcformat(default_utcoffset="Z"), + "0002-03-02T00:00:00Z") + self.assertEqual(t.rfcformat(default_utcoffset="+00:00"), + "0002-03-02T00:00:00+00:00") + + # with tzinfo: + t = self.theclass(2, 3, 2, 4, 5, 1, 123, FixedOffset(0, "UTC")) + self.assertEqual(t.rfcformat(), "0002-03-02T04:05:01.000123+00:00") + + t = self.theclass(2, 3, 2, 4, 5, 1, 123, FixedOffset(77, "77min")) + self.assertEqual(t.rfcformat(), "0002-03-02T04:05:01.000123+01:17") + + # with default UTC offset argument (shouldn't use the default): + self.assertEqual(t.rfcformat("Z"), "0002-03-02T04:05:01.000123+01:17") + def test_format(self): dt = self.theclass(2007, 9, 10, 4, 5, 1, 123) self.assertEqual(dt.__format__(''), str(dt)) Index: py3k/Modules/datetimemodule.c =================================================================== --- py3k/Modules/datetimemodule.c (revision 81033) +++ py3k/Modules/datetimemodule.c (working copy) @@ -4342,6 +4342,58 @@ } static PyObject * +datetime_rfcformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) +{ + char buffer[100]; + PyObject *result; + int us = DATE_GET_MICROSECOND(self); + PyObject *utcoffset = NULL; + static char *keywords[] = {"default_utcoffset", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "|U:rfcformat", keywords, + &utcoffset)) + return NULL; + + /* If we know the UTC offset, set to that: */ + if (HASTZINFO(self)) { + if (format_utcoffset(buffer, sizeof(buffer), ":", self->tzinfo, + (PyObject *)self) < 0) { + return NULL; + } + else { + utcoffset = PyUnicode_FromString(buffer); + } + } + /* Else set to the default: */ + else { + if (utcoffset == NULL) { + /* We didn't got the default from the caller, use "-00:00": */ + utcoffset = PyUnicode_FromString("-00:00"); + } + else { + /* We got the default from the caller, use it: */ + Py_INCREF(utcoffset); + } + } + + if (us) + result = PyUnicode_FromFormat("%04d-%02d-%02dT%02d:%02d:%02d.%06d", + GET_YEAR(self), GET_MONTH(self), + GET_DAY(self), + DATE_GET_HOUR(self), DATE_GET_MINUTE(self), + DATE_GET_SECOND(self), us); + else + result = PyUnicode_FromFormat("%04d-%02d-%02dT%02d:%02d:%02d", + GET_YEAR(self), GET_MONTH(self), + GET_DAY(self), + DATE_GET_HOUR(self), DATE_GET_MINUTE(self), + DATE_GET_SECOND(self)); + + PyUnicode_AppendAndDel(&result, utcoffset); + return result; +} + +static PyObject * datetime_ctime(PyDateTime_DateTime *self) { return format_ctime((PyDateTime_Date *)self, @@ -4730,6 +4782,12 @@ "sep is used to separate the year from the time, and " "defaults to 'T'.")}, + {"rfcformat", (PyCFunction)datetime_rfcformat, METH_VARARGS | METH_KEYWORDS, + PyDoc_STR("[default_utcoffset] -> string in RFC 3339 format, " + "YYYY-MM-DDTHH:MM:SS[.mmmmmm]+HH:MM.\n\n" + "default_utcoffset is used as the UTC offset for naive " + "instances, and defaults to '-00:00'.")}, + {"utcoffset", (PyCFunction)datetime_utcoffset, METH_NOARGS, PyDoc_STR("Return self.tzinfo.utcoffset(self).")},