Review for Python issue 5094 - Code Review (original) (raw)

OLD

NEW

1 /* C implementation for the date/time type documented at

1 /* C implementation for the date/time type documented at

2 * http://www.zope.org/Members/fdrake/DateTimeWiki/FrontPage

2 * http://www.zope.org/Members/fdrake/DateTimeWiki/FrontPage

3 */

3 */

4

4

5 #define PY_SSIZE_T_CLEAN

5 #define PY_SSIZE_T_CLEAN

6

6

7 #include "Python.h"

7 #include "Python.h"

8 #include "modsupport.h"

8 #include "modsupport.h"

9 #include "structmember.h"

9 #include "structmember.h"

10

10

11 #include <time.h>

11 #include <time.h>

(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading...

96 * 1 <= M <= 12

96 * 1 <= M <= 12

97 */

97 */

98 #define MONTH_IS_SANE(M) ((unsigned int)(M) - 1 < 12)

98 #define MONTH_IS_SANE(M) ((unsigned int)(M) - 1 < 12)

99

99

100 /* Forward declarations. */

100 /* Forward declarations. */

101 static PyTypeObject PyDateTime_DateType;

101 static PyTypeObject PyDateTime_DateType;

102 static PyTypeObject PyDateTime_DateTimeType;

102 static PyTypeObject PyDateTime_DateTimeType;

103 static PyTypeObject PyDateTime_DeltaType;

103 static PyTypeObject PyDateTime_DeltaType;

104 static PyTypeObject PyDateTime_TimeType;

104 static PyTypeObject PyDateTime_TimeType;

105 static PyTypeObject PyDateTime_TZInfoType;

105 static PyTypeObject PyDateTime_TZInfoType;

106 static PyTypeObject PyDateTime_UTCType;

106

107

107 /* ---------------------------------------------------------------------------

108 /* ---------------------------------------------------------------------------

108 * Math utilities.

109 * Math utilities.

109 */

110 */

110

111

111 /* k = i+j overflows iff k differs in sign from both inputs,

112 /* k = i+j overflows iff k differs in sign from both inputs,

112 * iff k^i has sign bit set and k^j has sign bit set,

113 * iff k^i has sign bit set and k^j has sign bit set,

113 * iff (k^i)&(k^j) has sign bit set.

114 * iff (k^i)&(k^j) has sign bit set.

114 */

115 */

115 #define SIGNED_ADD_OVERFLOWED(RESULT, I, J) \

116 #define SIGNED_ADD_OVERFLOWED(RESULT, I, J) \

(...skipping 628 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading...

744 SET_TD_DAYS(self, days);

745 SET_TD_DAYS(self, days);

745 SET_TD_SECONDS(self, seconds);

746 SET_TD_SECONDS(self, seconds);

746 SET_TD_MICROSECONDS(self, microseconds);

747 SET_TD_MICROSECONDS(self, microseconds);

747 }

748 }

748 return (PyObject *) self;

749 return (PyObject *) self;

749 }

750 }

750

751

751 #define new_delta(d, s, us, normalize) \

752 #define new_delta(d, s, us, normalize) \

752 new_delta_ex(d, s, us, normalize, &PyDateTime_DeltaType)

753 new_delta_ex(d, s, us, normalize, &PyDateTime_DeltaType)

753

754

755 static PyObject *

756 new_utc_ex(PyTypeObject *type)

757 {

758 return type->tp_alloc(type, 0);

759 }

760

761 #define new_utc() \

762 new_utc_ex(&PyDateTime_UTCType)

763

754 /* ---------------------------------------------------------------------------

764 /* ---------------------------------------------------------------------------

755 * tzinfo helpers.

765 * tzinfo helpers.

756 */

766 */

757

767

758 /* Ensure that p is None or of a tzinfo subclass. Return 0 if OK; if not

768 /* Ensure that p is None or of a tzinfo subclass. Return 0 if OK; if not

759 * raise TypeError and return -1.

769 * raise TypeError and return -1.

760 */

770 */

761 static int

771 static int

762 check_tzinfo_subclass(PyObject *p)

772 check_tzinfo_subclass(PyObject *p)

763 {

773 {

(...skipping 2275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading...

3039 0, /* tp_dict */

3049 0, /* tp_dict */

3040 0, /* tp_descr_get */

3050 0, /* tp_descr_get */

3041 0, /* tp_descr_set */

3051 0, /* tp_descr_set */

3042 0, /* tp_dictoffset */

3052 0, /* tp_dictoffset */

3043 0, /* tp_init */

3053 0, /* tp_init */

3044 0, /* tp_alloc */

3054 0, /* tp_alloc */

3045 PyType_GenericNew, /* tp_new */

3055 PyType_GenericNew, /* tp_new */

3046 0, /* tp_free */

3056 0, /* tp_free */

3047 };

3057 };

3048

3058

3059 static int

3060 utc_init(PyObject *self)

3061 {

3062 return 0;

3063 }

3064

3065 static PyObject *

3066 utc_tzname(PyObject *self, PyObject *dt)

3067 {

3068 return PyString_FromString("UTC");

3069 }

3070

3071 static PyObject *

3072 utc_utcoffset(PyObject *self, PyObject *dt)

3073 {

3074 return new_delta(0, 0, 0, 0);

3075 }

3076

3077 static PyObject *

3078 utc_dst(PyObject *self, PyObject *dt)

3079 {

3080 return new_delta(0, 0, 0, 0);

3081 }

3082

3083 static PyMethodDef utc_methods[] = {

3084

3085 {"tzname", (PyCFunction)utc_tzname, METH_O,

3086 PyDoc_STR("Always 'UTC'.")},

3087

3088 {"utcoffset", (PyCFunction)utc_utcoffset, METH_O,

3089 PyDoc_STR("Always 0 minutes.")},

3090

3091 {"dst", (PyCFunction)utc_dst, METH_O,

3092 PyDoc_STR("Always 0 minutes.")},

3093

3094 {NULL, NULL}

3095 };

3096

3097 static char utc_doc[] =

3098 PyDoc_STR("UTC timezone class.");

3099

3100 statichere PyTypeObject PyDateTime_UTCType = {

3101 PyObject_HEAD_INIT(NULL)

3102 0, /* ob_size */

3103 "datetime.UTC", /* tp_name */

3104 sizeof(PyDateTime_UTC), /* tp_basicsize */

3105 0, /* tp_itemsize */

3106 0, /* tp_dealloc */

3107 0, /* tp_print */

3108 0, /* tp_getattr */

3109 0, /* tp_setattr */

3110 0, /* tp_compare */

3111 0, /* tp_repr */

3112 0, /* tp_as_number */

3113 0, /* tp_as_sequence */

3114 0, /* tp_as_mapping */

3115 0, /* tp_hash */

3116 0, /* tp_call */

3117 0, /* tp_str */

3118 0, /* tp_getattro */

3119 0, /* tp_setattro */

3120 0, /* tp_as_buffer */

3121 Py_TPFLAGS_DEFAULT, /* tp_flags */

3122 utc_doc, /* tp_doc */

3123 0, /* tp_traverse */

3124 0, /* tp_clear */

3125 0, /* tp_richcompare */

3126 0, /* tp_weaklistoffset */

3127 0, /* tp_iter */

3128 0, /* tp_iternext */

3129 utc_methods, /* tp_methods */

3130 0, /* tp_members */

3131 0, /* tp_getset */

3132 &PyDateTime_TZInfoType, /* tp_base */

3133 0, /* tp_dict */

3134 0, /* tp_descr_get */

3135 0, /* tp_descr_set */

3136 0, /* tp_dictoffset */

3137 0, /* tp_init */

3138 0, /* tp_alloc */

3139 PyType_GenericNew, /* tp_new */

3140 };

3141

3049 /*

3142 /*

3050 * PyDateTime_Time implementation.

3143 * PyDateTime_Time implementation.

3051 */

3144 */

3052

3145

3053 /* Accessor properties.

3146 /* Accessor properties.

3054 */

3147 */

3055

3148

3056 static PyObject *

3149 static PyObject *

3057 time_hour(PyDateTime_Time *self, void *unused)

3150 time_hour(PyDateTime_Time *self, void *unused)

3058 {

3151 {

(...skipping 776 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading...

3835 self = PyObject_CallMethod(tzinfo, "fromutc", "O", self);

3928 self = PyObject_CallMethod(tzinfo, "fromutc", "O", self);

3836 Py_DECREF(temp);

3929 Py_DECREF(temp);

3837 }

3930 }

3838 return self;

3931 return self;

3839 }

3932 }

3840

3933

3841 /* Return best possible UTC time -- this isn't constrained by the

3934 /* Return best possible UTC time -- this isn't constrained by the

3842 * precision of a timestamp.

3935 * precision of a timestamp.

3843 */

3936 */

3844 static PyObject *

3937 static PyObject *

3845 datetime_utcnow(PyObject *cls, PyObject *dummy)

3938 datetime_utcnow(PyObject *cls, PyObject *args, PyObject *kw)

3846 {

3939 {

3847 » return datetime_best_possible(cls, gmtime, Py_None);

3940 PyObject *utc = Py_None;

3941 PyObject *tz_aware = Py_False;

3942 static char *keywords[] = {"tz_aware", NULL};

3943 ··

3944 » if (! PyArg_ParseTupleAndKeywords(args, kw, "|b",

3945 » » » » » keywords, &tz_aware))

3946 » » return NULL;

3947 if (tz_aware == Py_True)

3948 utc = new_utc();

3949

3950 » return datetime_best_possible(cls, gmtime, utc);

3848 }

3951 }

3849

3952

3850 /* Return new local datetime from timestamp (Python timestamp -- a double). */

3953 /* Return new local datetime from timestamp (Python timestamp -- a double). */

3851 static PyObject *

3954 static PyObject *

3852 datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw)

3955 datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw)

3853 {

3956 {

3854 PyObject *self;

3957 PyObject *self;

3855 double timestamp;

3958 double timestamp;

3856 PyObject *tzinfo = Py_None;

3959 PyObject *tzinfo = Py_None;

3857 static char *keywords[] = {"timestamp", "tz", NULL};

3960 static char *keywords[] = {"timestamp", "tz", NULL};

(...skipping 702 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading...

4560

4663

4561 static PyMethodDef datetime_methods[] = {

4664 static PyMethodDef datetime_methods[] = {

4562

4665

4563 /* Class methods: */

4666 /* Class methods: */

4564

4667

4565 {"now", (PyCFunction)datetime_now,

4668 {"now", (PyCFunction)datetime_now,

4566 METH_VARARGS | METH_KEYWORDS | METH_CLASS,

4669 METH_VARARGS | METH_KEYWORDS | METH_CLASS,

4567 PyDoc_STR("[tz] -> new datetime with tz's local day and time.")},

4670 PyDoc_STR("[tz] -> new datetime with tz's local day and time.")},

4568

4671

4569 {"utcnow", (PyCFunction)datetime_utcnow,

4672 {"utcnow", (PyCFunction)datetime_utcnow,

4570 » METH_NOARGS | METH_CLASS,

4673 » METH_VARARGS | METH_KEYWORDS | METH_CLASS,

4571 » PyDoc_STR("Return a new datetime representing UTC day and time.")},

4674 » PyDoc_STR("[tz_aware] -> Return a new datetime "\

4675 "representing UTC day and time.")},

4572

4676

4573 {"fromtimestamp", (PyCFunction)datetime_fromtimestamp,

4677 {"fromtimestamp", (PyCFunction)datetime_fromtimestamp,

4574 METH_VARARGS | METH_KEYWORDS | METH_CLASS,

4678 METH_VARARGS | METH_KEYWORDS | METH_CLASS,

4575 PyDoc_STR("timestamp[, tz] -> tz's local time from POSIX timestamp.")},

4679 PyDoc_STR("timestamp[, tz] -> tz's local time from POSIX timestamp.")},

4576

4680

4577 {"utcfromtimestamp", (PyCFunction)datetime_utcfromtimestamp,

4681 {"utcfromtimestamp", (PyCFunction)datetime_utcfromtimestamp,

4578 METH_VARARGS | METH_CLASS,

4682 METH_VARARGS | METH_CLASS,

4579 PyDoc_STR("timestamp -> UTC datetime from a POSIX timestamp "

4683 PyDoc_STR("timestamp -> UTC datetime from a POSIX timestamp "

4580 "(like time.time()).")},

4684 "(like time.time()).")},

4581

4685

(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading...

4709

4813

4710 /* C API. Clients get at this via PyDateTime_IMPORT, defined in

4814 /* C API. Clients get at this via PyDateTime_IMPORT, defined in

4711 * datetime.h.

4815 * datetime.h.

4712 */

4816 */

4713 static PyDateTime_CAPI CAPI = {

4817 static PyDateTime_CAPI CAPI = {

4714 &PyDateTime_DateType,

4818 &PyDateTime_DateType,

4715 &PyDateTime_DateTimeType,

4819 &PyDateTime_DateTimeType,

4716 &PyDateTime_TimeType,

4820 &PyDateTime_TimeType,

4717 &PyDateTime_DeltaType,

4821 &PyDateTime_DeltaType,

4718 &PyDateTime_TZInfoType,

4822 &PyDateTime_TZInfoType,

4823 &PyDateTime_UTCType,

4719 new_date_ex,

4824 new_date_ex,

4720 new_datetime_ex,

4825 new_datetime_ex,

4721 new_time_ex,

4826 new_time_ex,

4722 new_delta_ex,

4827 new_delta_ex,

4723 datetime_fromtimestamp,

4828 datetime_fromtimestamp,

4724 date_fromtimestamp

4829 date_fromtimestamp

4725 };

4830 };

4726

4831

4727

4832

4728 PyMODINIT_FUNC

4833 PyMODINIT_FUNC

(...skipping 11 matching lines...) Expand all Loading...

4740 if (PyType_Ready(&PyDateTime_DateType) < 0)

4845 if (PyType_Ready(&PyDateTime_DateType) < 0)

4741 return;

4846 return;

4742 if (PyType_Ready(&PyDateTime_DateTimeType) < 0)

4847 if (PyType_Ready(&PyDateTime_DateTimeType) < 0)

4743 return;

4848 return;

4744 if (PyType_Ready(&PyDateTime_DeltaType) < 0)

4849 if (PyType_Ready(&PyDateTime_DeltaType) < 0)

4745 return;

4850 return;

4746 if (PyType_Ready(&PyDateTime_TimeType) < 0)

4851 if (PyType_Ready(&PyDateTime_TimeType) < 0)

4747 return;

4852 return;

4748 if (PyType_Ready(&PyDateTime_TZInfoType) < 0)

4853 if (PyType_Ready(&PyDateTime_TZInfoType) < 0)

4749 return;

4854 return;

4855 if (PyType_Ready(&PyDateTime_UTCType) < 0)

4856 return;

4750

4857

4751 /* timedelta values */

4858 /* timedelta values */

4752 d = PyDateTime_DeltaType.tp_dict;

4859 d = PyDateTime_DeltaType.tp_dict;

4753

4860

4754 x = new_delta(0, 0, 1, 0);

4861 x = new_delta(0, 0, 1, 0);

4755 if (x == NULL || PyDict_SetItemString(d, "resolution", x) < 0)

4862 if (x == NULL || PyDict_SetItemString(d, "resolution", x) < 0)

4756 return;

4863 return;

4757 Py_DECREF(x);

4864 Py_DECREF(x);

4758

4865

4759 x = new_delta(-MAX_DELTA_DAYS, 0, 0, 0);

4866 x = new_delta(-MAX_DELTA_DAYS, 0, 0, 0);

(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading...

4833

4940

4834 Py_INCREF(&PyDateTime_TimeType);

4941 Py_INCREF(&PyDateTime_TimeType);

4835 PyModule_AddObject(m, "time", (PyObject *) &PyDateTime_TimeType);

4942 PyModule_AddObject(m, "time", (PyObject *) &PyDateTime_TimeType);

4836

4943

4837 Py_INCREF(&PyDateTime_DeltaType);

4944 Py_INCREF(&PyDateTime_DeltaType);

4838 PyModule_AddObject(m, "timedelta", (PyObject *) &PyDateTime_DeltaType);

4945 PyModule_AddObject(m, "timedelta", (PyObject *) &PyDateTime_DeltaType);

4839

4946

4840 Py_INCREF(&PyDateTime_TZInfoType);

4947 Py_INCREF(&PyDateTime_TZInfoType);

4841 PyModule_AddObject(m, "tzinfo", (PyObject *) &PyDateTime_TZInfoType);

4948 PyModule_AddObject(m, "tzinfo", (PyObject *) &PyDateTime_TZInfoType);

4842

4949

4950 Py_INCREF(&PyDateTime_UTCType);

4951 PyModule_AddObject(m, "UTC", (PyObject *) &PyDateTime_UTCType);

4952

4843 x = PyCObject_FromVoidPtrAndDesc(&CAPI, (void*) DATETIME_API_MAGIC,

4953 x = PyCObject_FromVoidPtrAndDesc(&CAPI, (void*) DATETIME_API_MAGIC,

4844 NULL);

4954 NULL);

4845 if (x == NULL)

4955 if (x == NULL)

4846 return;

4956 return;

4847 PyModule_AddObject(m, "datetime_CAPI", x);

4957 PyModule_AddObject(m, "datetime_CAPI", x);

4848

4958

4849 /* A 4-year cycle has an extra leap day over what we'd get from

4959 /* A 4-year cycle has an extra leap day over what we'd get from

4850 * pasting together 4 single years.

4960 * pasting together 4 single years.

4851 */

4961 */

4852 assert(DI4Y == 4 * 365 + 1);

4962 assert(DI4Y == 4 * 365 + 1);

(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading...

5073 enough to say.

5183 enough to say.

5074

5184

5075 In any case, it's clear that the default fromutc() is strong enough to handle

5185 In any case, it's clear that the default fromutc() is strong enough to handle

5076 "almost all" time zones: so long as the standard offset is invariant, it

5186 "almost all" time zones: so long as the standard offset is invariant, it

5077 doesn't matter if daylight time transition points change from year to year, or

5187 doesn't matter if daylight time transition points change from year to year, or

5078 if daylight time is skipped in some years; it doesn't matter how large or

5188 if daylight time is skipped in some years; it doesn't matter how large or

5079 small dst() may get within its bounds; and it doesn't even matter if some

5189 small dst() may get within its bounds; and it doesn't even matter if some

5080 perverse time zone returns a negative dst()). So a breaking case must be

5190 perverse time zone returns a negative dst()). So a breaking case must be

5081 pretty bizarre, and a tzinfo subclass can override fromutc() if it is.

5191 pretty bizarre, and a tzinfo subclass can override fromutc() if it is.

5082 --------------------------------------------------------------------------- */

5192 --------------------------------------------------------------------------- */

OLD

NEW