| title |
|---|
Python / Date/Time |
Python / Date/Time
-
datetime — Basic date and time types — Python 3.7.3 documentation #ril
-
The
datetimemodule supplies classes for manipulating dates and times in both simple and complex ways. While date and time arithmetic is supported, the focus of the implementation is on EFFICIENT ATTRIBUTE EXTRACTION FOR OUTPUT FORMATTING AND MANIPULATION. For related functionality, see also thetimeandcalendarmodules.為什麼說
time/calendar較多時間的計算? 因為時間差 (timedelta) 跟比較大小都在datetimemodule 裡。 -
There are two kinds of date and time objects: “NAIVE” and “AWARE”.
An aware object has sufficient knowledge of applicable algorithmic and political time adjustments, such as time zone and daylight saving time information, to LOCATE ITSELF RELATIVE TO OTHER AWARE OBJECTS. An aware object is used to represent a SPECIFIC MOMENT in time that is NOT OPEN TO INTERPRETATION.
A naive object does not contain enough information to UNAMBIGUOUSLY locate itself relative to other date/time objects. Whether a naive object represents Coordinated Universal Time (UTC), local time, or time in some other timezone is PURELY UP TO THE PROGRAM, just like it is up to the program whether a particular number represents metres, miles, or mass.
-
Naive objects are EASY TO UNDERSTAND AND TO WORK WITH, at the cost of ignoring some aspects of reality.
從 "easy to work with" 及 "applications requiring aware object" 看來,似乎是比較推 naive 的,由於 open to interpretation 的特性,統一將 naive 視為 UTC 即可。
-
For applications requiring aware objects,
datetimeandtimeobjects have an OPTIONAL time zone information attribute,tzinfo, that can be set to an instance of a subclass of the abstracttzinfoclass. Thesetzinfoobjects capture information about the OFFSET FROM UTC TIME, the time zone name, and whether Daylight Saving Time is in effect.Note that only one concrete
tzinfoclass, thetimezoneclass, is supplied by thedatetimemodule. Thetimezoneclass can represent simple timezones with FIXED OFFSET from UTC, such as UTC ITSELF or North American EST and EDT timezones.這裡 "fixed offset" 要強調的是
timezone未將 DST 等政治因素考量進去;唯一不受政治影響的是 UTC --timezone.utc。注意 Python 2 完全沒為
tzinfo提供實作 8.1. datetime — Basic date and time types — Python 2.7.16 documentation,datetime.timezone是 Python 3 才有的:Note that no concrete
tzinfoclasses are supplied by thedatetimemodule. -
Supporting timezones at deeper levels of detail 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.
Available Types
-
class
datetime.dateAn idealized ?? naive date, assuming the current Gregorian calendar always was, and always will be, in effect. Attributes:
year,month, andday. -
class
datetime.timeAn idealized time, independent of any particular day, assuming that every day has exactly 246060 seconds (there is no notion of “leap seconds” here). Attributes:
hour,minute,second,microsecond, andtzinfo. -
class
datetime.datetimeA combination of a date and a time. Attributes:
year,month,day,hour,minute,second,microsecond, andtzinfo. -
class
datetime.timedeltaA duration expressing the difference between two
date,time, ordatetimeinstances to microsecond resolution. -
class
datetime.tzinfoAn abstract base class for time zone information objects. These are used by the
datetimeandtimeclasses to provide a customizable notion of time adjustment (for example, to account for time zone and/or daylight saving time). -
class
datetime.timezoneA class that implements the
tzinfoabstract base class as a fixed offset from the UTC. New in version 3.2. -
Objects of these types are IMMUTABLE.
python - Do datetime objects need to be deep-copied? - Stack Overflow 提到,因此所有對
datetimeinstance 的操作都會傳回新的 instance,不用怕動到原來的 instance。 -
Objects of the
datetype are ALWAYS NAIVE.An object of type
timeordatetimemay be naive or aware. Adatetimeobjectdis aware ifd.tzinfois notNoneandd.tzinfo.utcoffset(d)does not returnNone. Ifd.tzinfoisNone, or ifd.tzinfois notNonebutd.tzinfo.utcoffset(d)returnsNone,dis naive. Atimeobject t is aware ift.tzinfois notNoneandt.tzinfo.utcoffset(None)does not returnNone. Otherwise,tis naive. -
The distinction between naive and aware doesn’t apply to
timedeltaobjects.因為
timedelta本身就是相對的概念,相對於 naive 或 aware 都沒問題。 -
Subclass relationships:
object timedelta tzinfo timezone time date datetime
-
-
8.1. datetime — Basic date and time types — Python 2.7.14 documentation 專注在取用 date/time 的 attribute extraction - 取年、月、日、時等 #ril
- Objects of these types are immutable,這也代表著所有的
datetime.*types 都是 hashable,可以搭配 hashable collection 使用。
- Objects of these types are immutable,這也代表著所有的
-
15.3. time — Time access and conversions — Python 2.7.14 documentation 大部份 function 背後都是同名的 C function,可能因 platform 不同而異 #ril
-
8.2. calendar — General calendar-related functions — Python 2.7.14 documentation 會輪出類似 Unix-like
cal的日曆 #ril
>>> d = datetime.strptime('2017-02-02 18:00', '%Y-%m-%d %H:%M')
>>> d.isoformat()
'2017-02-02T18:00:00'
參考資料:
- strftime() and strptime() Behavior - 8.1. datetime — Basic date and time types — Python 2.7.14 documentation
datetime.date、datetime.time及datetime.datetime都有strftime(format)將代表的日期/時間轉成字串,不過反過來的 parsing 只有datetime.datetime有提供strptime(date_string, format),不過format都要自己用 format code 自己併就是了。 - datetime.isoformat([sep]) - 8.1. datetime — Basic date and time types — Python 2.7.14 documentation 輸出成 ISO 8601,但 timezone 只會用
+/-HH:MM來表示,UTC 並不會在後面串上Z(而是+00:00)。反過來要解析的話,若要支援不同寫法的解析,得要寫多種 format code 應付各種狀況。
-
Unicode 有所謂的 Unicode Sandwich -- 進入程式都轉成 Unicode,輸出都用 byte string。在 time zone 的部份,實務上該如何取捨 naive 與 aware?
程式跟儲存裡都用 naive,輸出時再轉 aware。
參考資料:
-
8.1. datetime — Basic date and time types — Python 2.7.14 documentation
- date/time object 區分為 naive (天真的) 與 aware 兩種。所謂 aware 是知道 timezone、daylight saving time (DST) 是否作用中 (in effect),可以明確地跟其他 aware object 比較 (unambiguously),相對於 naive 就沒有這些資訊 (可以自己決定該如何解讀)。
datetime跟time都有tzinfo屬性 (不是None時就是 aware,型態繼承自datetime.tzinfoabstract class),記錄著與 UTC 的偏移 (offset)、time zone 名稱、DST (Daylight Saving Time) 是否作用中等。- 有趣的是
datetimemodule 並未提供任何datetime.tzinfo的實作;或許跟 "Naive objects are easy to understand and to work with, at the cost of ignoring some aspects of reality" 與 "The rules for time adjustment across the world are more political than rational, and there is no standard suitable for every application." 這兩段話有關,time zone 並非必要。
-
datetime.astimezone(tz) - 8.1. datetime — Basic date and time types — Python 2.7.14 documentation 將 aware
datetime轉換成另一個 timezone,若想直接代換掉 timezone 則用replace(tzinfo=tz),其中tz若傳入None,則會把 awaredatetime變成 naive object。 -
tzinfo Objects - 8.1. datetime — Basic date and time types — Python 2.7.14 documentation #ril
datetime.tzinfo的實作一定要提供utcoffset(self, dt)、dst(self, dt)與tzname(self, dt)。utcoffset()會傳回與 UTC 間的偏移 (timedelta),並把 DST 考量進去。- 從
LocalTimezone的實作看來,utcoffset()、dst()及tzname()的回傳值都跟_isdst(dt)有關,也就是某個 date/time 是否 DST 有在作用中,也難怪所有的 method 都要傳dt進去;tzname()的 "return different names depending on the specific value of dt passed, especially if the tzinfo class is accounting for daylight time" 印證了這個說法。
-
Timezones and Python | Julien Danjou (2015-06-16) #ril
-
pytz - World Timezone Definitions for Python — pytz 2014.10 documentation #ril
- Available Types - 8.1. datetime — Basic date and time types — Python 2.7.15 documentation 提到
datetime.timedelta是 "A DURATION expressing the difference between twodate,time, ordatetimeinstances to MICROSECOND resolution.",也提到 The distinction between naive and aware doesn’t apply totimedeltaobjects. 沒有 time zone naive/aware 的概念。 - timedelta Objects - 8.1. datetime — Basic date and time types — Python 2.7.14 documentation
class datetime.timedelta([days[, seconds[, microseconds[, milliseconds[, minutes[, hours[, weeks]]]]]]])所有 argument 預設都是0,可以接受 integer/float,也可以是 positive/negative,彈性很大;但 microsecond 已經最小精度,再給小數好像也沒意思?- 雖然 constructor 提供了
milliseconds、minutes、hours、weeks等,但內部只存days、seconds跟microseconds(也就是timedeltainstance 的 3 個 attribute);也就是內部會做 normalization 以確保 "unique representation",所以milliseconds=> x 1000 macroseconds、minutes=> x 60 seconds、hours=> x 3600 seconds、weeks=> x 7 days。 - 除了 supported operations 提到的
timedeltaobjects 間可以做一些數學運算,例如t1 + t2、t1 - t2、t * i、t // i、+t、-t還有abs(t),另外timedelta間也可以比較,比的是 duration 的長短。 timedelta本身是 hashable,也支援 pickling。在 boolean context 裡,只要不是timedelta(0)就會被視為True。- 中間提到
timedelta可以跟date/datetime做加減運算 (跟time不行??),不過細節就在date/datetimeobjects 的章節說明了。
- 8.1. datetime — Basic date and time types — Python 2.7.14 documentation 出現不少
timedelta(0)的用法,甚至有ZERO = timedelta(0)。
- date Objects - 8.1. datetime — Basic date and time types — Python 2.7.15 documentation #ril
- datetime Objects - 8.1. datetime — Basic date and time types — Python 2.7.15 documentation #ril
- time Objects - 8.1. datetime — Basic date and time types — Python 2.7.15 documentation #ril
如果要解析 ISO 8601 (或它的子集 RFC 3339),都不建議用 datetime.strptime(),處理各種變化型會很苦。建議用 python-dateutil:
>>> from dateutil import parser
>>> parser.parse('2017-12-29T13:54:01.2732344+00:00')
datetime.datetime(2017, 12, 29, 13, 54, 1, 273234, tzinfo=tzutc())
>>> parser.parse('2017-12-29T13:54:01.2732344')
datetime.datetime(2017, 12, 29, 13, 54, 1, 273234)
參考資料:
- python - How to parse an ISO 8601-formatted date? - Stack Overflow
datetime.strptime()不好用,有什麼好方法解析 RFC 3339? Mark Amery: 因為 RFC 3339 有很多變化,別用strptime()。許多人同意 Flimm 用python-dateutil套件的做法dateutil.parser.parse(...)。 - How do I translate a ISO 8601 datetime string into a Python datetime object? - Stack Overflow Wes Winham: 傾向用
python-dateutil,用strptime()會很歡樂...
from datetime import datetime
now = datetime.now()
year, month, day, hour, minute, second =
now.year, now.month, now.day,
now.hour, now.minute, now.second
參考資料:
- 8.1. datetime — Basic date and time types — Python 2.7.14 documentation https://docs.python.org/2/library/datetime.html
datetime.now()可以取得datetime.datetime的 instance,然後透過.year、.month、.day、.hour、.minute、.second就能取得不同欄位的值。提到datetime.today()等同於datetime.fromtimestamp(time.time()),也就是等同於datetime.now()。不過date.today()的可讀性似乎比datetime.today()?
參考資料:
- datetime.now([tz]) - 8.1. datetime — Basic date and time types — Python 2.7.14 documentation #ril
datetime.now()沒給tz時會拿到 local datetime,有提供tz時則會轉成tz的時間。
- datetime.utcnow() - 8.1. datetime — Basic date and time types — Python 2.7.14 documentation 跟
now()一樣,只不過傳回 UTC 時間,但tzinfo一樣是None(naive)。
from datetime import datetime, date
import json
import pytz
def test_default_serializer():
def default(obj):
if isinstance(obj, (date, datetime)):
return obj.isoformat()
else:
return str(obj)
# raise TypeError('%r is not JSON serializable' % obj)
data = [
date(2018, 1, 2),
datetime(2018, 1, 2, 13, 50, tzinfo=pytz.utc),
]
s = json.dumps(data, default=default)
assert s == '["2018-01-02", "2018-01-02T13:50:00+00:00"]'
參考資料:
- Serializing your datetime objects - Understanding datetime in Python: A primer | Opensource.com 用
datetime.isoformat()轉成 ISO 8601 字串,也可以轉成 timestamp,最後是是自己寫 serializer -- 不知道如何 serialize 時會被呼叫的 function,搭配json.dumps(data, default=serializer)使用。 - datetime.date(2008, 5, 27) is not JSON serializable · Issue #22 · jeffknupp/sandman dolinsky:
flask.json_encoder有支援datetime.datetime? 但不支援datetime.date,這裡用flask.json.JSONEncoder重新改寫過 - Better Python Object Serialization · Hynek Schlawack (2016-08-22) 實作
default()傳回JSONEncoder看得懂的東西,或是自己實作JSONEncoder;但擴充性都很差,帶出了 PEP 443 #ril - python - How to overcome "datetime.datetime not JSON serializable"? - Stack Overflow jgbarah: 提供
defaultfunction,而 jmontes: 提出default=str的做法也滿妙的;或許可做為defaultfunction 的 fallback? - Encoders and Decoders - 19.2. json — JSON encoder and decoder — Python 3.6.4 documentation 出現 2 次
def default(self, obj)的實作,最後都轉回json.JSONEncoder.default(self, obj)。