I tried to summarize the library that handles date and time in Python in a reverse lookup style.
The content of this article has been written with care for accuracy, but is not official information. Please refer to the official reference (reference # 1) for accurate information.
Most of it is about standard modules, so if you're new to Python or don't know much about the date and time library. (Because I'm still new to Python.)
Python2 has been confirmed with v2.7.10, and Python3 has been confirmed with v3.5.1. (Anaconda 4.0.0 Windows 64bit version is used.)
Those that do not deal with Python 2 and Python 3 separately can be used in common.
In that case, print is unified with parentheses, and the execution result is Python3.
The sample code mainly shows the results in an interactive environment.
The extension module versions are as follows.
dateutil 2.5.1
pytz 2016.2
A brief description of the standard module for date and time and the types it contains. For details, refer to the official reference (reference material # 1).
In the text, from datetime import * is applied unless otherwise specified.
| module | Description |
|---|---|
datetimemodule |
Provides standard types and operations for dates and times. |
timemodule |
Contains low-level (system-level) time utilities. |
calendarmodule |
It mainly includes utilities related to text calendars. |
| module | Description |
|---|---|
dateutil |
A module that makes up for the date and time processing that the standard module lacks. |
pytz |
A module that handles time zones. Details will be described later. |
| Mold | Description |
|---|---|
datetime.date |
Date object. |
datetime.datetime |
Date and time object. |
datetime.time |
Time object.timeNot to be confused with modules. |
datetime.timedelta |
An object that represents the difference between two dates and times. |
datetime.tzinfo |
An abstract base class for timezone information. |
datetime.timezone |
Implementation with fixed offset of time zone information. |
time.struct_time |
UNIXstruct tmA named tuple that corresponds to (structure). |
The type hierarchy of the datetime module is as follows.
timezone type below Python 3.2.object
timedelta
tzinfo
timezone
time
date
datetime
Hereafter, the module name of the type is omitted in the text.
Some of the same datetime objects have a timezone and some do not.
In Python, datetime with a time zone is called ** aware ** (date and time), and datetime without a time zone is called ** naive ** (date and time).
The date object can always be naive and the time object can be either.
The timezone object added in Python 3.2 is available as an instance of the timezone (tzinfo).
Prior to that, the tzinfo implementation did not exist in standard modules.
In such cases, use the pytz module.
The implementation of tzinfo also has a submodule tz of the dateutil module.
Also, if you want to indicate the time zone with an arbitrary offset value (+09: 00 for JST), timezone is sufficient, but
The pytz module is recommended if you need to handle timezone handling rigorously.
The pytz module references the IANA timezone database (Olson database).
For details, refer to the official reference (reference material # 1).
For the IANA timezone database, please refer to the following articles.
tz database - Wikipedia https://ja.wikipedia.org/wiki/Tz_database
The conversion method between naive and aware is explained in this volume.
It can be generated by the constructor. The time object is omitted.
>>> from datetime import datetime, date, timezone, timedelta
>>>
>>> datetime(2016, 7)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Required argument 'day' (pos 3) not found
>>> datetime(2016, 7, 5)
datetime.datetime(2016, 7, 5, 0, 0)
>>> datetime(2016, 7, 5, 13)
datetime.datetime(2016, 7, 5, 13, 0)
>>> datetime(2016, 7, 5, 13, 45)
datetime.datetime(2016, 7, 5, 13, 45)
>>> datetime(2016, 7, 5, 13, 45, 27)
datetime.datetime(2016, 7, 5, 13, 45, 27)
>>> datetime(2016, 7, 5, 13, 45, 27, 123456)
datetime.datetime(2016, 7, 5, 13, 45, 27, 123456)
>>> datetime(2016, 7, 5, 13, 45, 27, 123456, timezone(timedelta(hours=+9)))
datetime.datetime(2016, 7, 5, 13, 45, 27, 123456, tzinfo=datetime.timezone(datetime.timedelta(0, 32400)))
>>>
>>> date(2016, 7)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Required argument 'day' (pos 3) not found
>>> date(2016, 7, 5)
datetime.date(2016, 7, 5)
>>> date(2016, 7, 5, 0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function takes at most 3 arguments (4 given)
The seventh element of datetime is microseconds (1 / 1,000,000 seconds).
It can also be generated from a time stamp. See the next section for time stamps of the current date and time.
>>> datetime.fromtimestamp(12345678901.234567)
datetime.datetime(2361, 3, 22, 4, 15, 1, 234568)
>>> date.fromtimestamp(12345678901.234567)
datetime.date(2361, 3, 22)
The time stamp (float) here is a value called ** UNIX time ** or epoch seconds.
UNIX time-Wikipedia https://ja.wikipedia.org/wiki/UNIX%E6%99%82%E9%96%93
UNIX time is an integer value, but on Python it is represented by float.
Values after the decimal point are treated as microseconds in Python, but as you can see in the example, they are represented by the decimal part of float, so the precision is reduced.
With the datetime.date () method, you can retrieve only the date part as date.
>>> from datetime import datetime, date
>>>
>>> dt = datetime.now()
>>> dt
datetime.datetime(2016, 7, 14, 14, 24, 46, 157000)
>>> dt.date()
datetime.date(2016, 7, 14)
datetime.now () returns a datetime object that indicates the current date and time.
date.today () returns a date object that indicates the current day.
>>> from datetime import datetime, date
>>>
>>> datetime.now()
datetime.datetime(2016, 7, 14, 14, 14, 2, 900000)
>>> date.today()
datetime.date(2016, 7, 14)
You can get the timestamp of the current date and time with the time () function of the time module.
For the time stamp, refer to the previous section.
>>> import time
>>>
>>> time.time()
1468473337.565 # 2016-07-14 14:15:37.565000
There are some other (old-fashioned) functions that return a struct_time in the time module, but I won't cover them this time.
Please read the explanation about the time.gmtime () function.
The datetime module uses thedatetime.strptime ()function.
However, as you can see from the results below, this function is inflexible.
>>> from datetime import datetime, timezone, timedelta
>>> datetime.strptime("2016/07/05 13:45:06", "%Y/%m/%d %H:%M:%S")
datetime.datetime(2016, 7, 5, 13, 45, 6)
>>> datetime.strptime("2016/07/05 13:45", "%Y/%m/%d %H:%M:%S")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "...\lib\_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "...\lib\_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2016/07/05 13:45' does not match format '%Y/%m/%d %H:%M:%S'
(* The trace contents are partially processed.)
The parse () function of the parser submodule of the dateutil module is powerful, so let's use that.
>>> from dateutil.parser import parse
>>>
>>> parse("Tue Aug 23 17:00:35 JST 2016")
datetime.datetime(2016, 8, 23, 17, 0, 35)
>>> parse("2016-07-03T11:22:33Z")
datetime.datetime(2016, 7, 3, 11, 22, 33, tzinfo=tzutc())
>>> parse("2016/07/03 04:05:06")
datetime.datetime(2016, 7, 3, 4, 5, 6)
>>> parse("2016/07/03")
datetime.datetime(2016, 7, 3, 0, 0)
In the case of Python2, the following error occurred.
.../dateutil/parser.py:598: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
elif res.tzname and res.tzname in time.tzname:
It seems to be related to the issue described in this ↓ article, but it occurs even though the version of dateutil is 2.5.1.
Is it a similar but different (unfixed) bug?
twitter - python dateutil unicode warning - Stack Overflow http://stackoverflow.com/questions/21296475/python-dateutil-unicode-warning
To convert to ISO8601 format, use the date.isoformat () method.
This is used when simply converting a datetime or date object to a string.
If you want to convert it to a string in any format, use the strftime () method.
>>> from datetime import datetime, timezone, timedelta
>>>
>>> dt1 = datetime(2016, 7, 5, 13, 45) # naive
>>> dt2 = datetime(2016, 7, 5, 13, 45, tzinfo=timezone(timedelta(hours=+9))) # aware
>>> d = dt1.date()
>>> dt1, dt2, d
(datetime.datetime(2016, 7, 5, 13, 45), datetime.datetime(2016, 7, 5, 13, 45, tzinfo=datetime.timezone(datetime.timedelta(0, 32400))), datetime.date(2016, 7, 5))
>>>
>>> dt1.isoformat()
'2016-07-05T13:45:00'
>>> str(dt1)
'2016-07-05 13:45:00'
>>>
>>> dt2.isoformat()
'2016-07-05T13:45:00+09:00'
>>> str(dt2)
'2016-07-05 13:45:00+09:00'
>>>
>>> d.isoformat()
'2016-07-05'
>>> str(d)
'2016-07-05'
>>>
>>> dt1.strftime("%Y/%m/%d %H:%M:%S")
'2016/07/05 13:45:00'
>>> dt1.strftime("%Y/%m/%d %H:%M:%S %Z %z")
'2016/07/05 13:45:00 '
>>> dt2.strftime("%Y/%m/%d %H:%M:%S %Z %z")
'2016/07/05 13:45:00 UTC+09:00 +0900'
Please refer to the reference below for the format of the format.
8.1.8. Behavior of strftime () and strptime () --8.1. datetime — Basic date and time types — Python 3.5.1 documentation http://docs.python.jp/3.5/library/datetime.html#strftime-strptime-behavior
Comparisons can be made using the comparison operators ==, ! =, <, <=, >, > =.
You cannot compare datetime and date.
(TypeError: can't compare datetime.datetime to datetime.date)
Also, datetime cannot be compared between aware and naive.
(TypeError: can't compare offset-naive and offset-aware datetimes)
You need to match them to either type before comparing.
>>> from datetime import datetime, date
>>>
>>> dt1 = datetime(2016, 7, 1, 22, 30)
>>> dt2 = datetime(2016, 7, 5, 13, 45)
>>>
>>> dt1 == datetime(2016, 7, 1, 22, 30, 0)
True
>>> dt1 == dt1, dt1 == dt2, dt1 != dt1, dt1 != dt2, dt1 < dt2, dt1 > dt2, dt1 <= dt1, dt2 <= dt1, dt2 >= dt2, dt1 >= dt2
(True, False, False, True, True, False, True, False, True, False)
>>>
>>> d1 = dt1.date()
>>> d2 = dt2.date()
>>>
>>> d1 == date(2016, 7, 1)
True
>>> d1 == d1, d1 == d2, d1 != d1, d1 != d2, d1 < d2, d1 > d2, d1 <= d1, d2 <= d1, d2 >= d2, d1 >= d2
(True, False, False, True, True, False, True, False, True, False)
In Python, the date and time intervals and differences are represented by timedelta objects.
(Delta means difference (difference ⇒ Δ).)
timedelta can be obtained by subtracting datetimes or dates (- operation).
It cannot be calculated with datetime and date.
(TypeError: unsupported operand type(s) for -)
Also, datetime cannot be calculated between aware and naive.
(TypeError: can't subtract offset-naive and offset-aware datetimes)
You need to match it to either type before calculating.
>>> from datetime import datetime, date
>>>
>>> d1, d2 = date(2016, 7, 1), date(2016, 7, 3)
>>>
>>> type(d2 - d1)
<class 'datetime.timedelta'>
>>> d2 - d1
datetime.timedelta(2)
>>> str(d2 - d1)
'2 days, 0:00:00'
>>> str(d1 - d2)
'-2 days, 0:00:00'
>>>
>>> dt1, dt2 = datetime(2016, 7, 1, 10, 30), datetime(2016, 7, 3, 9, 10)
>>> dt2 - dt1
datetime.timedelta(1, 81600)
>>> str(dt2 - dt1)
'1 day, 22:40:00'
As mentioned in the previous section, the difference between the two dates is the number of days returned. What if I want to know "what month is the interval between two dates"?
In that case, try using the relativedelta submodule of the dateutil module.
Basically this should solve it.
>>> from datetime import date
>>> from dateutil.relativedelta import relativedelta
>>>
>>> d1, d2 = date(2014, 11, 22), date(2016, 3, 1)
>>> str(d2 - d1)
'465 days, 0:00:00'
>>> delta = relativedelta(d2, d1)
>>> delta
relativedelta(years=+1, months=+3, days=+8)
>>> month_count = delta.years * 12 + delta.months
>>> month_count
15
It will be years for 12 months or more, but I was able to calculate the number of months with years * 12 + months.
What is a little worrisome here is the calculation involving the end of the month, especially around February of a leap year. So, I shifted the two dates by one day and checked what the delta would be in that case.
--A script that shifts two dates by one day and examines the result of relativedelta
from datetime import date, timedelta
from dateutil.relativedelta import relativedelta
d1 = date(2016, 2, 26)
d2 = date(2016, 3, 26)
delta1day = timedelta(days=1)
for x in range(9):
print(d1, d2, relativedelta(d2, d1))
d1 += delta1day
d2 += delta1day
2016-02-26 2016-03-26 relativedelta(months=+1)
2016-02-27 2016-03-27 relativedelta(months=+1)
2016-02-28 2016-03-28 relativedelta(months=+1)
2016-02-29 2016-03-29 relativedelta(months=+1)
2016-03-01 2016-03-30 relativedelta(days=+29)
2016-03-02 2016-03-31 relativedelta(days=+29)
2016-03-03 2016-04-01 relativedelta(days=+29)
2016-03-04 2016-04-02 relativedelta(days=+29)
2016-03-05 2016-04-03 relativedelta(days=+29)
I looked at the dates further ahead, but roughly speaking, it seems that they are treated specially only when they cross the end of February. Other than that, the number of days has been the same (+29).
When I increased the interval between the two dates by one day, the number of days changed depending on whether it straddled the end of the 30th month or not. I'm sure it will be corrected on the last day of the month.
It seems that it is okay if you understand the nature of this area.
I've already written that datetime --datetime and date --date become timedelta,
For increase / decrease of date / date / time, you can get the increased / decreased datetime and date by adding / subtracting timedelta.
>>> from datetime import datetime, date, timedelta
>>>
>>> dt = datetime(2016, 7, 5, 13, 45)
>>> d = dt.date()
>>>
>>> dt + timedelta(days=5, minutes=168)
datetime.datetime(2016, 7, 10, 16, 33)
>>> d - timedelta(days=13)
datetime.date(2016, 6, 22)
For monthly adjustment, use the submodule relativedelta of the dateutil module, as in the case of monthly calculation.
>>> from datetime import date
>>> from dateutil.relativedelta import relativedelta
>>>
>>> date(2016, 7, 5) - relativedelta(months=32)
datetime.date(2013, 11, 5)
The following example confirms the mutual conversion between naive and aware in Python3 only with the standard module.
Python2 (less than Python3.2 to be exact) doesn't have a timezone type, so use the pytz module instead.
To turn a naive datetime into an aware datetime, use the datetime.replace () method.
>>> from datetime import datetime, timezone, timedelta
>>>
>>> jst = timezone(timedelta(hours=+9)) #When using pytz pytz.timezone('Asia/Tokyo')
>>> jst
datetime.timezone(datetime.timedelta(0, 32400))
>>> dt = datetime(2016, 7, 5, 13, 45) # naive
>>> dt
datetime.datetime(2016, 7, 5, 13, 45)
>>> dt2 = dt.replace(tzinfo=jst) # aware
>>> dt2
datetime.datetime(2016, 7, 5, 13, 45, tzinfo=datetime.timezone(datetime.timedelta(0, 32400)))
>>> str(dt2)
'2016-07-05 13:45:00+09:00'
According to reference # 4-2, it was reported that when the time zone was added by the datetime.replace () method, it behaved a little strangely.
An alternative is shown to use jst.localize (datetime (...)).
I didn't reproduce it in my environment, so it may be a bug in an older version of pytz.
Conversely, to turn an aware datetime into a naive datetime, use the same datetime.replace () method.
For the time zone, specify None which means" none ".
#(Continued from above)
>>> dt3 = dt2.replace(tzinfo=None)
>>> dt3
datetime.datetime(2016, 7, 5, 13, 45)
>>> str(dt3)
'2016-07-05 13:45:00'
struct_time to datetime or dateSometimes the timestamp type is represented by struct_time, but if you want to convert this to the datetime type.
Using the time.mktime () and datetime.fromtimestamp () functions,
struct_time→timestamp(float)→datetime
Convert in the order of.
>>> from datetime import datetime, date
>>> from time import localtime, mktime
>>>
>>> tm = localtime() # struct_time
>>> t = mktime(tm) #Time stamp(float)Conversion to
>>> datetime.fromtimestamp(t)
datetime.datetime(2016, 7, 12, 22, 31, 15)
>>> date.fromtimestamp(t)
datetime.date(2016, 7, 12)
Taking advantage of the fact that struct_time is a tuple, you can also write:
#(Continued from above)
>>> datetime(*tm[:6])
datetime.datetime(2016, 7, 12, 22, 31, 15)
tm [: 6] gives a tuple of year, month, day, hour, minute, and second, so we pass it to the constructor of datetime as six arguments.
This can be written concisely, but it reduces readability and may be avoided.
datetime or date to struct_timeContrary to the previous section, if you want to convert a datetime object or adate object to a struct_time object,
You can get struct_time by using thedate.timetuple ()method.
>>> from datetime import datetime
>>>
>>> dt = datetime(2016, 7, 3, 12, 25)
>>> d = dt.date()
>>>
>>> dt.timetuple()
time.struct_time(tm_year=2016, tm_mon=7, tm_mday=3, tm_hour=12, tm_min=25, tm_sec=0, tm_wday=6, tm_yday=185, tm_isdst=-1)
>>> d.timetuple()
time.struct_time(tm_year=2016, tm_mon=7, tm_mday=3, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=185, tm_isdst=-1)
Here, only the date example is written. In the case of date and time, either method should be applicable by changing the type and unit.
To generate a finite date list, I quickly came up with a way to combine timedelta and range to create a list with comprehensions.
>>> from datetime import date, timedelta
>>>
>>> start_date = date(2016, 7, 5)
>>> a = [start_date + timedelta(days=x) for x in range(5)]
>>> a
[datetime.date(2016, 7, 5), datetime.date(2016, 7, 6), datetime.date(2016, 7, 7), datetime.date(2016, 7, 8), datetime.date(2016, 7, 9)]
... but it's a little disappointing that I can't write in one line.
(You can write date (2016, 7, 5) directly instead of start_date, but of course it doesn't.)
You can write in one line using the rrule submodule of the dateutil module.
>>> from datetime import date
>>> from dateutil.rrule import rrule, DAILY
>>>
>>> a = [x.date() for x in rrule(DAILY, count=5, dtstart=date(2016, 7, 5))]
>>> a
[datetime.date(2016, 7, 5), datetime.date(2016, 7, 6), datetime.date(2016, 7, 7), datetime.date(2016, 7, 8), datetime.date(2016, 7, 9)]
Oh yeah, I wanted to write like this.
In some cases it may be more convenient to use the Pandas module (pandas.date_range).
See reference # 5 for details.
Use the ʻisleap function of the calendar` module.
>>> import calendar
>>>
>>> calendar.isleap(2016)
True
>>> calendar.isleap(2015)
False
>>>
>>> from datetime import date
>>>
>>> d = date(2016, 7, 5)
>>> calendar.isleap(d.year)
True
datetime moduleAs of Python 3.5, all datetime related objects in the datetime module are evaluated as True, except for the equivalent of timedelta (0).
(Timezone is not included in" all "because it was not mentioned in the document.)
>>> from datetime import *
>>>
>>> bool(datetime.fromtimestamp(0))
True
>>> bool(date.fromtimestamp(0))
True
>>> bool(time(0, 0, 0))
True
>>> bool(timedelta(1))
True
>>> bool(timedelta(0))
False
>>> bool(timezone.utc)
True
By the way, in Python2, the time object at midnight is evaluated as False.
>>> from datetime import *
>>> bool(time(0, 0, 0))
False
This is a bug (Issue13936) that existed in less than Python3.5 rather than Python2, and is the behavior fixed in Python3.5.
When I checked it with Python 3.4.3, it was still False.
This method is also used in other languages, but it is calculated by (Timestamp after processing-Timestamp before processing).
import time
t = time.time()
time.sleep(3.1)
print(time.time() - t)
# => 3.0999999046325684
Although not covered this time, you can also use the following modules to measure the execution time of code fragments.
27.5. timeit — Running time for small code snippets — Python 3.5.1 documentation http://docs.python.jp/3.5/library/timeit.html
This is an image when each object is serialized by pickle.
--Execution result in Python2
>>> from datetime import datetime
>>> import pickle
>>>
>>> dt = datetime(2016, 7, 5, 13, 45)
>>>
>>> pickle.dumps(dt) # datetime
"cdatetime\ndatetime\np0\n(S'\\x07\\xe0\\x07\\x05\\r-\\x00\\x00\\x00\\x00'\np1\ntp2\nRp3\n."
>>> pickle.dumps(dt.date()) # date
"cdatetime\ndate\np0\n(S'\\x07\\xe0\\x07\\x05'\np1\ntp2\nRp3\n."
>>> pickle.dumps(dt.timetuple()) # struct_time
'ctime\nstruct_time\np0\n((I2016\nI7\nI5\nI13\nI45\nI0\nI1\nI187\nI-1\ntp1\n(dp2\ntp3\nRp4\n.'
>>> pickle.dumps(dt - dt) # timedelta
'cdatetime\ntimedelta\np0\n(I0\nI0\nI0\ntp1\nRp2\n.'
--Execution result in Python3
>>> from datetime import datetime
>>> import pickle
>>>
>>> dt = datetime(2016, 7, 5, 13, 45)
>>> pickle.dumps(dt) # datetime
b'\x80\x03cdatetime\ndatetime\nq\x00C\n\x07\xe0\x07\x05\r-\x00\x00\x00\x00q\x01\x85q\x02Rq\x03.'
>>> pickle.dumps(dt.date()) # date
b'\x80\x03cdatetime\ndate\nq\x00C\x04\x07\xe0\x07\x05q\x01\x85q\x02Rq\x03.'
>>> pickle.dumps(dt.timetuple()) # struct_time
b'\x80\x03ctime\nstruct_time\nq\x00(M\xe0\x07K\x07K\x05K\rK-K\x00K\x01K\xbbJ\xff\xff\xff\xfftq\x01}q\x02(X\x07\x00\x00\x00tm_zoneq\x03NX\t\x00\x00\x00tm_gmtoffq\x04Nu\x86q\x05Rq\x06.'
>>> pickle.dumps(dt - dt) # timedelta
b'\x80\x03cdatetime\ntimedelta\nq\x00K\x00K\x00K\x00\x87q\x01Rq\x02.'
#1. (Official document / standard library reference)
8.1. datetime — Basic date and time types — Python 3.5.1 documentation http://docs.python.jp/3.5/library/datetime.html#module-datetime 8.1. datetime — basic date and time types — Python 2.7.x documentation http://docs.python.jp/2/library/datetime.html#module-datetime
(Links for modules other than datetime are redundant and will be omitted. There is a link somewhere on the above link page, so please skip from there.)
#2. dateutil - powerful extensions to datetime — dateutil 2.5.3 documentation https://dateutil.readthedocs.io/en/stable/
#3. pytz 2016.4 : Python Package Index https://pypi.python.org/pypi/pytz/
#4-1. Python Date Processing and TimeZone | Nekoya Press http://nekoya.github.io/blog/2013/06/21/python-datetime/
#4-2. Don't use replace to give tzinfo to datetime in Python | Nekoya Press http://nekoya.github.io/blog/2013/07/05/python-datetime-with-jst/
#5. Easily manipulate date and time related data with Python pandas-StatsFragments http://sinhrks.hatenablog.com/entry/2014/11/09/183603
Recommended Posts