Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
4e749a11
Commit
4e749a11
authored
Jun 14, 2010
by
Alexander Belopolsky
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #5094: The ``datetime`` module now has a simple concrete class
implementing ``datetime.tzinfo`` interface.
parent
510b6227
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
483 additions
and
26 deletions
+483
-26
Doc/library/datetime.rst
Doc/library/datetime.rst
+82
-12
Lib/test/test_datetime.py
Lib/test/test_datetime.py
+108
-13
Misc/ACKS
Misc/ACKS
+1
-0
Misc/NEWS
Misc/NEWS
+8
-0
Modules/datetimemodule.c
Modules/datetimemodule.c
+284
-1
No files found.
Doc/library/datetime.rst
View file @
4e749a11
...
...
@@ -28,11 +28,14 @@ For applications requiring more, :class:`datetime` and :class:`time` objects
have an optional time zone information member, :attr:`tzinfo`, that can contain
an instance of a subclass of the abstract :class:`tzinfo` class. These
:class:`tzinfo` objects capture information about the offset from UTC time, the
time zone name, and whether Daylight Saving Time is in effect. Note that no
concrete :class:`tzinfo` classes are supplied by the :mod:`datetime` module.
Supporting timezones at whatever level of detail is required is up to the
application. The rules for time adjustment across the world are more political
than rational, and there is no standard suitable for every application.
time zone name, and whether Daylight Saving Time is in effect. Note that only
one concrete :class:`tzinfo` class, the :class:`timezone` class, is supplied by the
:mod:`datetime` module. The :class:`timezone` class can reprsent simple
timezones with fixed offset from UTC such as UTC itself or North American EST and
EDT timezones. Supporting timezones at whatever level of detail is
required is up to the application. The rules for time adjustment across the
world are more political than rational, change frequently, and there is no
standard suitable for every application aside from UTC.
The :mod:`datetime` module exports the following constants:
...
...
@@ -99,6 +102,14 @@ Available Types
time adjustment (for example, to account for time zone and/or daylight saving
time).
.. class:: timezone
A class that implements the :class:`tzinfo` abstract base class as a
fixed offset from the UTC.
.. versionadded:: 3.2
Objects of these types are immutable.
Objects of the :class:`date` type are always naive.
...
...
@@ -116,6 +127,7 @@ Subclass relationships::
object
timedelta
tzinfo
timezone
time
date
datetime
...
...
@@ -660,8 +672,8 @@ Other constructors, all class methods:
Return the current UTC date and time, with :attr:`tzinfo` ``None``. This is like
:meth:`now`, but returns the current UTC date and time, as a naive
:class:`datetime` object.
See also :meth:`now`.
:class:`datetime` object.
An aware current UTC datetime can be obtained by
calling ``datetime.now(timezone.utc)``. See also :meth:`now`.
.. classmethod:: datetime.fromtimestamp(timestamp, tz=None)
...
...
@@ -1318,8 +1330,10 @@ Example:
:class:`tzinfo` is an abstract base class, meaning that this class should not be
instantiated directly. You need to derive a concrete subclass, and (at least)
supply implementations of the standard :class:`tzinfo` methods needed by the
:class:`datetime` methods you use. The :mod:`datetime` module does not supply
any concrete subclasses of :class:`tzinfo`.
:class:`datetime` methods you use. The :mod:`datetime` module supplies
a simple concrete subclass of :class:`tzinfo` :class:`timezone` which can reprsent
timezones with fixed offset from UTC such as UTC itself or North American EST and
EDT.
An instance of (a concrete subclass of) :class:`tzinfo` can be passed to the
constructors for :class:`datetime` and :class:`time` objects. The latter objects
...
...
@@ -1520,9 +1534,65 @@ arranged, as in the example, by expressing DST switch times in the time zone's
standard local time.
Applications that can't bear such ambiguities should avoid using hybrid
:class:`tzinfo` subclasses; there are no ambiguities when using UTC, or any
other fixed-offset :class:`tzinfo` subclass (such as a class representing only
EST (fixed offset -5 hours), or only EDT (fixed offset -4 hours)).
:class:`tzinfo` subclasses; there are no ambiguities when using :class:`timezone`,
or any other fixed-offset :class:`tzinfo` subclass (such as a class representing
only EST (fixed offset -5 hours), or only EDT (fixed offset -4 hours)).
.. _datetime-timezone:
:class:`timezone` Objects
--------------------------
A :class:`timezone` object represents a timezone that is defined by a
fixed offset from UTC. Note that objects of this class cannot be used
to represent timezone information in the locations where different
offsets are used in different days of the year or where historical
changes have been made to civil time.
.. class:: timezone(offset[, name])
The ``offset`` argument must be specified as a :class:`timedelta`
object representing the difference between the local time and UTC. It must
be within the range [``-timedelta(hours=23, minutes=59),
``timedelta(hours=23, minutes=59)``] and represent whole number of minutes,
otherwise :exc:`ValueError` is raised.
The ``name`` argument is optional. If specified it must be a string that
used as the value returned by the ``tzname(dt)`` method. Otherwise,
``tzname(dt)`` returns a string 'UTCsHH:MM', where s is the sign of
``offset``, HH and MM are two digits of ``offset.hours`` and
``offset.minutes`` respectively.
.. method:: timezone.utcoffset(self, dt)
Returns the fixed value specified when the :class:`timezone` instance is
constructed. The ``dt`` argument is ignored. The return value is a
:class:`timedelta` instance equal to the difference between the
local time and UTC.
.. method:: timezone.tzname(self, dt)
Returns the fixed value specified when the :class:`timezone` instance is
constructed or a string 'UTCsHH:MM', where s is the sign of
``offset``, HH and MM are two digits of ``offset.hours`` and
``offset.minutes`` respectively. The ``dt`` argument is ignored.
.. method:: timezone.dst(self, dt)
Always returns ``None``.
.. method:: timezone.fromutc(self, dt)
Returns ``dt + offset``. The ``dt`` argument must be aware with ``tzinfo``
set to ``self``.
Class attributes:
.. attribute:: timezone.utc
The UTC timezone, ``timezone(0, 'UTC')``.
.. _strftime-strptime-behavior:
...
...
Lib/test/test_datetime.py
View file @
4e749a11
...
...
@@ -15,6 +15,7 @@ from datetime import MINYEAR, MAXYEAR
from
datetime
import
timedelta
from
datetime
import
tzinfo
from
datetime
import
time
from
datetime
import
timezone
from
datetime
import
date
,
datetime
pickle_choices
=
[(
pickle
,
pickle
,
proto
)
for
proto
in
range
(
3
)]
...
...
@@ -49,6 +50,7 @@ class TestModule(unittest.TestCase):
# tzinfo tests
class
FixedOffset
(
tzinfo
):
def
__init__
(
self
,
offset
,
name
,
dstoffset
=
42
):
if
isinstance
(
offset
,
int
):
offset
=
timedelta
(
minutes
=
offset
)
...
...
@@ -67,6 +69,7 @@ class FixedOffset(tzinfo):
return
self
.
__dstoffset
class
PicklableFixedOffset
(
FixedOffset
):
def
__init__
(
self
,
offset
=
None
,
name
=
None
,
dstoffset
=
None
):
FixedOffset
.
__init__
(
self
,
offset
,
name
,
dstoffset
)
...
...
@@ -131,6 +134,97 @@ class TestTZInfo(unittest.TestCase):
self
.
assertEqual
(
derived
.
utcoffset
(
None
),
offset
)
self
.
assertEqual
(
derived
.
tzname
(
None
),
'cookie'
)
class
TestTimeZone
(
unittest
.
TestCase
):
def
setUp
(
self
):
self
.
ACDT
=
timezone
(
timedelta
(
hours
=
9.5
),
'ACDT'
)
self
.
EST
=
timezone
(
-
timedelta
(
hours
=
5
),
'EST'
)
self
.
DT
=
datetime
(
2010
,
1
,
1
)
def
test_str
(
self
):
for
tz
in
[
self
.
ACDT
,
self
.
EST
,
timezone
.
utc
,
timezone
.
min
,
timezone
.
max
]:
self
.
assertEqual
(
str
(
tz
),
tz
.
tzname
(
None
))
def
test_class_members
(
self
):
limit
=
timedelta
(
hours
=
23
,
minutes
=
59
)
self
.
assertEquals
(
timezone
.
utc
.
utcoffset
(
None
),
ZERO
)
self
.
assertEquals
(
timezone
.
min
.
utcoffset
(
None
),
-
limit
)
self
.
assertEquals
(
timezone
.
max
.
utcoffset
(
None
),
limit
)
def
test_constructor
(
self
):
self
.
assertEquals
(
timezone
.
utc
,
timezone
(
timedelta
(
0
)))
# invalid offsets
for
invalid
in
[
timedelta
(
microseconds
=
1
),
timedelta
(
1
,
1
),
timedelta
(
seconds
=
1
),
timedelta
(
1
),
-
timedelta
(
1
)]:
self
.
assertRaises
(
ValueError
,
timezone
,
invalid
)
self
.
assertRaises
(
ValueError
,
timezone
,
-
invalid
)
with
self
.
assertRaises
(
TypeError
):
timezone
(
None
)
with
self
.
assertRaises
(
TypeError
):
timezone
(
42
)
with
self
.
assertRaises
(
TypeError
):
timezone
(
ZERO
,
None
)
with
self
.
assertRaises
(
TypeError
):
timezone
(
ZERO
,
42
)
def
test_inheritance
(
self
):
self
.
assertTrue
(
isinstance
(
timezone
.
utc
,
tzinfo
))
self
.
assertTrue
(
isinstance
(
self
.
EST
,
tzinfo
))
def
test_utcoffset
(
self
):
dummy
=
self
.
DT
for
h
in
[
0
,
1.5
,
12
]:
offset
=
h
*
HOUR
self
.
assertEquals
(
offset
,
timezone
(
offset
).
utcoffset
(
dummy
))
self
.
assertEquals
(
-
offset
,
timezone
(
-
offset
).
utcoffset
(
dummy
))
with
self
.
assertRaises
(
TypeError
):
self
.
EST
.
utcoffset
(
''
)
with
self
.
assertRaises
(
TypeError
):
self
.
EST
.
utcoffset
(
5
)
def
test_dst
(
self
):
self
.
assertEquals
(
None
,
timezone
.
utc
.
dst
(
self
.
DT
))
with
self
.
assertRaises
(
TypeError
):
self
.
EST
.
dst
(
''
)
with
self
.
assertRaises
(
TypeError
):
self
.
EST
.
dst
(
5
)
def
test_tzname
(
self
):
self
.
assertEquals
(
'UTC+00:00'
,
timezone
(
ZERO
).
tzname
(
None
))
self
.
assertEquals
(
'UTC-05:00'
,
timezone
(
-
5
*
HOUR
).
tzname
(
None
))
self
.
assertEquals
(
'UTC+09:30'
,
timezone
(
9.5
*
HOUR
).
tzname
(
None
))
self
.
assertEquals
(
'UTC-00:01'
,
timezone
(
timedelta
(
minutes
=-
1
)).
tzname
(
None
))
self
.
assertEquals
(
'XYZ'
,
timezone
(
-
5
*
HOUR
,
'XYZ'
).
tzname
(
None
))
with
self
.
assertRaises
(
TypeError
):
self
.
EST
.
tzname
(
''
)
with
self
.
assertRaises
(
TypeError
):
self
.
EST
.
tzname
(
5
)
def
test_fromutc
(
self
):
with
self
.
assertRaises
(
ValueError
):
timezone
.
utc
.
fromutc
(
self
.
DT
)
for
tz
in
[
self
.
EST
,
self
.
ACDT
,
Eastern
]:
utctime
=
self
.
DT
.
replace
(
tzinfo
=
tz
)
local
=
tz
.
fromutc
(
utctime
)
self
.
assertEquals
(
local
-
utctime
,
tz
.
utcoffset
(
local
))
self
.
assertEquals
(
local
,
self
.
DT
.
replace
(
tzinfo
=
timezone
.
utc
))
def
test_comparison
(
self
):
self
.
assertNotEqual
(
timezone
(
ZERO
),
timezone
(
HOUR
))
self
.
assertEqual
(
timezone
(
HOUR
),
timezone
(
HOUR
))
self
.
assertEqual
(
timezone
(
-
5
*
HOUR
),
timezone
(
-
5
*
HOUR
,
'EST'
))
with
self
.
assertRaises
(
TypeError
):
timezone
(
ZERO
)
<
timezone
(
ZERO
)
self
.
assertIn
(
timezone
(
ZERO
),
{
timezone
(
ZERO
)})
def
test_aware_datetime
(
self
):
# test that timezone instances can be used by datetime
t
=
datetime
(
1
,
1
,
1
)
for
tz
in
[
timezone
.
min
,
timezone
.
max
,
timezone
.
utc
]:
self
.
assertEquals
(
tz
.
tzname
(
t
),
t
.
replace
(
tzinfo
=
tz
).
tzname
())
self
.
assertEquals
(
tz
.
utcoffset
(
t
),
t
.
replace
(
tzinfo
=
tz
).
utcoffset
())
self
.
assertEquals
(
tz
.
dst
(
t
),
t
.
replace
(
tzinfo
=
tz
).
dst
())
#############################################################################
# Base clase for testing a particular aspect of timedelta, time, date and
# datetime comparisons.
...
...
@@ -2729,20 +2823,21 @@ class TestDateTimeTZ(TestDateTime, TZInfoBase, unittest.TestCase):
# We don't know which time zone we're in, and don't have a tzinfo
# class to represent it, so seeing whether a tz argument actually
# does a conversion is tricky.
weirdtz
=
FixedOffset
(
timedelta
(
hours
=
15
,
minutes
=
58
),
"weirdtz"
,
0
)
utc
=
FixedOffset
(
0
,
"utc"
,
0
)
for
dummy
in
range
(
3
):
now
=
datetime
.
now
(
weirdtz
)
self
.
assertTrue
(
now
.
tzinfo
is
weirdtz
)
utcnow
=
datetime
.
utcnow
().
replace
(
tzinfo
=
utc
)
now2
=
utcnow
.
astimezone
(
weirdtz
)
if
abs
(
now
-
now2
)
<
timedelta
(
seconds
=
30
):
break
# Else the code is broken, or more than 30 seconds passed between
# calls; assuming the latter, just try again.
else
:
# Three strikes and we're out.
self
.
fail
(
"utcnow(), now(tz), or astimezone() may be broken"
)
for
weirdtz
in
[
FixedOffset
(
timedelta
(
hours
=
15
,
minutes
=
58
),
"weirdtz"
,
0
),
timezone
(
timedelta
(
hours
=
15
,
minutes
=
58
),
"weirdtz"
),]:
for
dummy
in
range
(
3
):
now
=
datetime
.
now
(
weirdtz
)
self
.
assertTrue
(
now
.
tzinfo
is
weirdtz
)
utcnow
=
datetime
.
utcnow
().
replace
(
tzinfo
=
utc
)
now2
=
utcnow
.
astimezone
(
weirdtz
)
if
abs
(
now
-
now2
)
<
timedelta
(
seconds
=
30
):
break
# Else the code is broken, or more than 30 seconds passed between
# calls; assuming the latter, just try again.
else
:
# Three strikes and we're out.
self
.
fail
(
"utcnow(), now(tz), or astimezone() may be broken"
)
def
test_tzinfo_fromtimestamp
(
self
):
import
time
...
...
Misc/ACKS
View file @
4e749a11
...
...
@@ -406,6 +406,7 @@ Bob Kahn
Kurt B. Kaiser
Tamito Kajiyama
Peter van Kampen
Rafe Kaplan
Jacob Kaplan-Moss
Lou Kates
Hiroaki Kawai
...
...
Misc/NEWS
View file @
4e749a11
...
...
@@ -1306,6 +1306,14 @@ Library
Extension Modules
-----------------
- Issue #5094: The ``datetime`` module now has a simple concrete class
implementing ``datetime.tzinfo`` interface. Instances of the new
class, ``datetime.timezone``, return fixed name and UTC offset from
their ``tzname(dt)`` and ``utcoffset(dt)`` methods. The ``dst(dt)``
method always returns ``None``. A class attribute, ``utc`` contains
an instance representing the UTC timezone. Original patch by Rafe
Kaplan.
- Issue #8973: Add __all__ to struct module; this ensures that
help(struct) includes documentation for the struct.Struct class.
...
...
Modules/datetimemodule.c
View file @
4e749a11
...
...
@@ -102,6 +102,7 @@ static PyTypeObject PyDateTime_DateTimeType;
static
PyTypeObject
PyDateTime_DeltaType
;
static
PyTypeObject
PyDateTime_TimeType
;
static
PyTypeObject
PyDateTime_TZInfoType
;
static
PyTypeObject
PyDateTime_TimeZoneType
;
/* ---------------------------------------------------------------------------
* Math utilities.
...
...
@@ -771,6 +772,52 @@ new_delta_ex(int days, int seconds, int microseconds, int normalize,
#define new_delta(d, s, us, normalize) \
new_delta_ex(d, s, us, normalize, &PyDateTime_DeltaType)
typedef
struct
{
PyObject_HEAD
PyObject
*
offset
;
PyObject
*
name
;
}
PyDateTime_TimeZone
;
/* Create new timezone instance checking offset range. This
function does not check the name argument. Caller must assure
that offset is a timedelta instance and name is either NULL
or a unicode object. */
static
PyObject
*
new_timezone
(
PyObject
*
offset
,
PyObject
*
name
)
{
PyDateTime_TimeZone
*
self
;
PyTypeObject
*
type
=
&
PyDateTime_TimeZoneType
;
assert
(
offset
!=
NULL
);
assert
(
PyDelta_Check
(
offset
));
assert
(
name
==
NULL
||
PyUnicode_Check
(
name
));
if
(
GET_TD_MICROSECONDS
(
offset
)
!=
0
||
GET_TD_SECONDS
(
offset
)
%
60
!=
0
)
{
PyErr_Format
(
PyExc_ValueError
,
"offset must be a timedelta"
" representing a whole number of minutes"
);
return
NULL
;
}
if
((
GET_TD_DAYS
(
offset
)
==
-
1
&&
GET_TD_SECONDS
(
offset
)
==
0
)
||
GET_TD_DAYS
(
offset
)
<
-
1
||
GET_TD_DAYS
(
offset
)
>=
1
)
{
PyErr_Format
(
PyExc_ValueError
,
"offset must be a timedelta"
" strictly between -timedelta(hours=24) and"
" timedelta(hours=24)."
);
return
NULL
;
}
self
=
(
PyDateTime_TimeZone
*
)(
type
->
tp_alloc
(
type
,
0
));
if
(
self
==
NULL
)
{
return
NULL
;
}
Py_INCREF
(
offset
);
self
->
offset
=
offset
;
Py_XINCREF
(
name
);
self
->
name
=
name
;
return
(
PyObject
*
)
self
;
}
/* ---------------------------------------------------------------------------
* tzinfo helpers.
*/
...
...
@@ -3261,7 +3308,7 @@ static PyTypeObject PyDateTime_TZInfoType = {
PyObject_GenericGetAttr
,
/* tp_getattro */
0
,
/* tp_setattro */
0
,
/* tp_as_buffer */
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_BASETYPE
,
/* tp_flags */
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_BASETYPE
,
/* tp_flags */
tzinfo_doc
,
/* tp_doc */
0
,
/* tp_traverse */
0
,
/* tp_clear */
...
...
@@ -3283,6 +3330,206 @@ static PyTypeObject PyDateTime_TZInfoType = {
0
,
/* tp_free */
};
static
char
*
timezone_kws
[]
=
{
"offset"
,
"name"
,
NULL
};
static
PyObject
*
timezone_new
(
PyTypeObject
*
type
,
PyObject
*
args
,
PyObject
*
kw
)
{
PyObject
*
offset
;
PyObject
*
name
=
NULL
;
if
(
PyArg_ParseTupleAndKeywords
(
args
,
kw
,
"O!|O!:timezone"
,
timezone_kws
,
&
PyDateTime_DeltaType
,
&
offset
,
&
PyUnicode_Type
,
&
name
))
return
new_timezone
(
offset
,
name
);
return
NULL
;
}
static
void
timezone_dealloc
(
PyDateTime_TimeZone
*
self
)
{
Py_CLEAR
(
self
->
offset
);
Py_CLEAR
(
self
->
name
);
Py_TYPE
(
self
)
->
tp_free
((
PyObject
*
)
self
);
}
static
PyObject
*
timezone_richcompare
(
PyDateTime_TimeZone
*
self
,
PyDateTime_TimeZone
*
other
,
int
op
)
{
if
(
op
!=
Py_EQ
&&
op
!=
Py_NE
)
{
Py_INCREF
(
Py_NotImplemented
);
return
Py_NotImplemented
;
}
return
delta_richcompare
(
self
->
offset
,
other
->
offset
,
op
);
}
static
long
timezone_hash
(
PyDateTime_TimeZone
*
self
)
{
return
delta_hash
((
PyDateTime_Delta
*
)
self
->
offset
);
}
/* Check argument type passed to tzname, utcoffset, or dst methods.
Returns 0 for good argument. Returns -1 and sets exception info
otherwise.
*/
static
int
_timezone_check_argument
(
PyObject
*
dt
,
const
char
*
meth
)
{
if
(
dt
==
Py_None
||
PyDateTime_Check
(
dt
))
return
0
;
PyErr_Format
(
PyExc_TypeError
,
"%s(dt) argument must be a datetime instance"
" or None, not %.200s"
,
meth
,
Py_TYPE
(
dt
)
->
tp_name
);
return
-
1
;
}
static
PyObject
*
timezone_str
(
PyDateTime_TimeZone
*
self
)
{
char
buf
[
10
];
int
hours
,
minutes
,
seconds
;
PyObject
*
offset
;
char
sign
;
if
(
self
->
name
!=
NULL
)
{
Py_INCREF
(
self
->
name
);
return
self
->
name
;
}
/* Offset is normalized, so it is negative if days < 0 */
if
(
GET_TD_DAYS
(
self
->
offset
)
<
0
)
{
sign
=
'-'
;
offset
=
delta_negative
((
PyDateTime_Delta
*
)
self
->
offset
);
if
(
offset
==
NULL
)
return
NULL
;
}
else
{
sign
=
'+'
;
offset
=
self
->
offset
;
Py_INCREF
(
offset
);
}
/* Offset is not negative here. */
seconds
=
GET_TD_SECONDS
(
offset
);
Py_DECREF
(
offset
);
minutes
=
divmod
(
seconds
,
60
,
&
seconds
);
hours
=
divmod
(
minutes
,
60
,
&
minutes
);
assert
(
seconds
==
0
);
/* XXX ignore sub-minute data, curently not allowed. */
PyOS_snprintf
(
buf
,
sizeof
(
buf
),
"UTC%c%02d:%02d"
,
sign
,
hours
,
minutes
);
return
PyUnicode_FromString
(
buf
);
}
static
PyObject
*
timezone_tzname
(
PyDateTime_TimeZone
*
self
,
PyObject
*
dt
)
{
if
(
_timezone_check_argument
(
dt
,
"tzname"
)
==
-
1
)
return
NULL
;
return
timezone_str
(
self
);
}
static
PyObject
*
timezone_utcoffset
(
PyDateTime_TimeZone
*
self
,
PyObject
*
dt
)
{
if
(
_timezone_check_argument
(
dt
,
"utcoffset"
)
==
-
1
)
return
NULL
;
Py_INCREF
(
self
->
offset
);
return
self
->
offset
;
}
static
PyObject
*
timezone_dst
(
PyObject
*
self
,
PyObject
*
dt
)
{
if
(
_timezone_check_argument
(
dt
,
"dst"
)
==
-
1
)
return
NULL
;
Py_RETURN_NONE
;
}
static
PyObject
*
add_datetime_timedelta
(
PyDateTime_DateTime
*
date
,
PyDateTime_Delta
*
delta
,
int
factor
);
static
PyObject
*
timezone_fromutc
(
PyDateTime_TimeZone
*
self
,
PyDateTime_DateTime
*
dt
)
{
if
(
!
PyDateTime_Check
(
dt
))
{
PyErr_SetString
(
PyExc_TypeError
,
"fromutc: argument must be a datetime"
);
return
NULL
;
}
if
(
!
HASTZINFO
(
dt
)
||
dt
->
tzinfo
!=
(
PyObject
*
)
self
)
{
PyErr_SetString
(
PyExc_ValueError
,
"fromutc: dt.tzinfo "
"is not self"
);
return
NULL
;
}
return
add_datetime_timedelta
(
dt
,
(
PyDateTime_Delta
*
)
self
->
offset
,
1
);
}
static
PyMethodDef
timezone_methods
[]
=
{
{
"tzname"
,
(
PyCFunction
)
timezone_tzname
,
METH_O
,
PyDoc_STR
(
"If name is specified when timezone is created, returns the name."
" Otherwise returns offset as 'UTC(+|-)HHMM'."
)},
{
"utcoffset"
,
(
PyCFunction
)
timezone_utcoffset
,
METH_O
,
PyDoc_STR
(
"Returns fixed offset. Ignores its argument."
)},
{
"dst"
,
(
PyCFunction
)
timezone_dst
,
METH_O
,
PyDoc_STR
(
"Returns None. Ignores its argument."
)},
{
"fromutc"
,
(
PyCFunction
)
timezone_fromutc
,
METH_O
,
PyDoc_STR
(
"datetime in UTC -> datetime in local time."
)},
{
NULL
,
NULL
}
};
static
char
timezone_doc
[]
=
PyDoc_STR
(
"Fixed offset from UTC implementation of tzinfo."
);
static
PyTypeObject
PyDateTime_TimeZoneType
=
{
PyVarObject_HEAD_INIT
(
NULL
,
0
)
"datetime.timezone"
,
/* tp_name */
sizeof
(
PyDateTime_TimeZone
),
/* tp_basicsize */
0
,
/* tp_itemsize */
(
destructor
)
timezone_dealloc
,
/* tp_dealloc */
0
,
/* tp_print */
0
,
/* tp_getattr */
0
,
/* tp_setattr */
0
,
/* tp_reserved */
0
,
/* tp_repr */
0
,
/* tp_as_number */
0
,
/* tp_as_sequence */
0
,
/* tp_as_mapping */
(
hashfunc
)
timezone_hash
,
/* tp_hash */
0
,
/* tp_call */
(
reprfunc
)
timezone_str
,
/* tp_str */
0
,
/* tp_getattro */
0
,
/* tp_setattro */
0
,
/* tp_as_buffer */
Py_TPFLAGS_DEFAULT
,
/* tp_flags */
timezone_doc
,
/* tp_doc */
0
,
/* tp_traverse */
0
,
/* tp_clear */
(
richcmpfunc
)
timezone_richcompare
,
/* tp_richcompare */
0
,
/* tp_weaklistoffset */
0
,
/* tp_iter */
0
,
/* tp_iternext */
timezone_methods
,
/* tp_methods */
0
,
/* tp_members */
0
,
/* tp_getset */
&
PyDateTime_TZInfoType
,
/* tp_base */
0
,
/* tp_dict */
0
,
/* tp_descr_get */
0
,
/* tp_descr_set */
0
,
/* tp_dictoffset */
0
,
/* tp_init */
0
,
/* tp_alloc */
timezone_new
,
/* tp_new */
};
/*
* PyDateTime_Time implementation.
*/
...
...
@@ -4971,6 +5218,7 @@ PyInit_datetime(void)
PyObject
*
m
;
/* a module object */
PyObject
*
d
;
/* its dict */
PyObject
*
x
;
PyObject
*
delta
;
m
=
PyModule_Create
(
&
datetimemodule
);
if
(
m
==
NULL
)
...
...
@@ -4986,6 +5234,8 @@ PyInit_datetime(void)
return
NULL
;
if
(
PyType_Ready
(
&
PyDateTime_TZInfoType
)
<
0
)
return
NULL
;
if
(
PyType_Ready
(
&
PyDateTime_TimeZoneType
)
<
0
)
return
NULL
;
/* timedelta values */
d
=
PyDateTime_DeltaType
.
tp_dict
;
...
...
@@ -5059,6 +5309,36 @@ PyInit_datetime(void)
return
NULL
;
Py_DECREF
(
x
);
/* timezone values */
d
=
PyDateTime_TimeZoneType
.
tp_dict
;
delta
=
new_delta
(
0
,
0
,
0
,
0
);
if
(
delta
==
NULL
)
return
NULL
;
x
=
new_timezone
(
delta
,
NULL
);
Py_DECREF
(
delta
);
if
(
x
==
NULL
||
PyDict_SetItemString
(
d
,
"utc"
,
x
)
<
0
)
return
NULL
;
Py_DECREF
(
x
);
delta
=
new_delta
(
-
1
,
60
,
0
,
1
);
/* -23:59 */
if
(
delta
==
NULL
)
return
NULL
;
x
=
new_timezone
(
delta
,
NULL
);
Py_DECREF
(
delta
);
if
(
x
==
NULL
||
PyDict_SetItemString
(
d
,
"min"
,
x
)
<
0
)
return
NULL
;
Py_DECREF
(
x
);
delta
=
new_delta
(
0
,
(
23
*
60
+
59
)
*
60
,
0
,
0
);
/* +23:59 */
if
(
delta
==
NULL
)
return
NULL
;
x
=
new_timezone
(
delta
,
NULL
);
Py_DECREF
(
delta
);
if
(
x
==
NULL
||
PyDict_SetItemString
(
d
,
"max"
,
x
)
<
0
)
return
NULL
;
Py_DECREF
(
x
);
/* module initialization */
PyModule_AddIntConstant
(
m
,
"MINYEAR"
,
MINYEAR
);
PyModule_AddIntConstant
(
m
,
"MAXYEAR"
,
MAXYEAR
);
...
...
@@ -5079,6 +5359,9 @@ PyInit_datetime(void)
Py_INCREF
(
&
PyDateTime_TZInfoType
);
PyModule_AddObject
(
m
,
"tzinfo"
,
(
PyObject
*
)
&
PyDateTime_TZInfoType
);
Py_INCREF
(
&
PyDateTime_TimeZoneType
);
PyModule_AddObject
(
m
,
"timezone"
,
(
PyObject
*
)
&
PyDateTime_TimeZoneType
);
x
=
PyCapsule_New
(
&
CAPI
,
PyDateTime_CAPSULE_NAME
,
NULL
);
if
(
x
==
NULL
)
return
NULL
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment