在 CPython 中處理日期時間最常用的內建模組是 datetime, 特別是要將 datetime 物件格式化成日期時間字串時的 strftime() 與將日期時間字串轉回 datetime 物件的 strptime() 這兩個方法/函式最常用 (兩者是反運算).
在 CPython 中, 要將日期時間字串轉成 datetime 物件可以直接呼叫 datetime 類別的靜態方法 strptime() 例如 :
>>> from datetime import datetime
>>> datetime.strptime('2024-10-03 09:04:35.123456', '%Y-%m-%d %H:%M:%S.%f')
datetime.datetime(2024, 10, 3, 9, 4, 35, 123456)
也可以呼叫 datetime 物件的 strptime() 方法, 例如 :
>>> from datetime import datetime
>>> today=datetime.today() # 用 now() 也可以
>>> today
datetime.datetime(2024, 10, 3, 9, 11, 55, 129274)
>>> today.strptime('2024-10-03 09:04:35.123456', '%Y-%m-%d %H:%M:%S.%f')
datetime.datetime(2024, 10, 3, 9, 4, 35, 123456)
此處我們只是借用 today 這個 datetime 物件的 strptime() 方法而已, strptime() 實際要轉換的日期時間字串內容與 today 物件自己的日期時間內容完全無關, 而是由傳入的第一參數 (日期時間字串).
但是將 datetime 物件轉成日期時間字串的 strftime() 則必須使用物件方法, 因為它的傳入參數只有格式化串一個而已 (datetime 類別的 strftime() 靜態方法也是), 所以轉換的對象就是 datetime 物件本身 :
>>> today.strftime('%Y-%m-%d %H:%M:%S.%f')
'2024-10-03 09:11:55.129274'
總之, 在 CPython 環境中, strptime() 既可以當類別的靜態方法用, 也可以當物件方法用; 但 strftime() 則只能當物件方法用, 參考 :
但是很可惜, MicroPython 並未實作 datetime 模組, 不論是匯入 datetime 或 udatetime 都會出錯 :
>>> import datetime
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: no module named 'datetime'
>>> import udatetime
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: no module named 'udatetime'
所以在 MicroPython 中如果要用到 strftime() 與 strptime() 的功能必須手刻, 但不需要完全實作 CPython 的 strftime() 與 strptime() 之完整功能, 只要針對物聯網最常用的 "%Y-%m-%d %H:%M:%S" 格式進行轉換即可.
strftime() 須用到 time 模組來產生日期時間物件, 其 localtime() 函式會傳回年月日時分秒的日期時間 tuple 物件, 透過字串的 replace() 方法將格式化字串中的相對應子字串用 tuple 中的元素取代. 傳入參數為格式化字串 format_str 與日期時間元組 dt (預設為 None 表示目前的日期時間), 傳回值為替換後的格式化字串 :
import time
def strftime(dt=None, format_str="%Y-%m-%d %H:%M:%S"):
if dt is None:
dt=time.localtime()
return format_str.replace("%Y", str(dt[0])) \
.replace("%m", "{:02d}".format(dt[1])) \
.replace("%d", "{:02d}".format(dt[2])) \
.replace("%H", "{:02d}".format(dt[3])) \
.replace("%M", "{:02d}".format(dt[4])) \
.replace("%S", "{:02d}".format(dt[5]))
此函式兩個參數皆有預設值, 未傳入參數時就傳回目前時間的格式化字串, 傳入年月日時分秒 tuple 時小於 10 也會補 0, 測試如下 :
>>> now=time.localtime()
>>> now
(2024, 10, 3, 9, 28, 40, 3, 277)
>>> strftime(now)
'2024-10-03 09:28:40'
>>> strftime() # 未傳參數 : 現在時間
'2024-10-03 11:59:48'
>>> strftime((2024, 1 , 1, 11, 2, 3)) # 有傳參數 : 指定時間
'2024-01-01 11:02:03'
而 strptime() 函式則是傳入日期時間字串 dt_str 與格式化字串 format_str, 經過字串剖析後取出年月日時分秒各元素後組成 tuple 物件傳回 :
def strptime(dt_str, format_str="%Y-%m-%d %H:%M:%S"):
if format_str=="%Y-%m-%d %H:%M:%S":
year=int(dt_str[0:4])
month=int(dt_str[5:7])
day=int(dt_str[8:10])
hour=int(dt_str[11:13])
minute=int(dt_str[14:16])
second=int(dt_str[17:19])
return (year, month, day, hour, minute, second, 0, 0, 0)
else:
raise ValueError("Unsupported format string")
測試如下 :
>>> dt=strptime('2024-10-03 09:28:40')
>>> dt
(2024, 10, 3, 9, 28, 40, 0, 0, 0)
檢視 xtools 函式庫已有一個類似 strftime() 功能的函式 format_datetime() :
def format_datetime(local_time):
Y,M,D,H,m,S,W,ds = local_time
t = str(Y) + '-'
t += pad_zero(M)
t += '-'
t += pad_zero(D)
t += ' '
t += pad_zero(H)
t += ':'
t += pad_zero(m)
t += ':'
t += pad_zero(S)
return t
它也能將傳入的日期時間元組轉成日期時間字串傳回 :
>>> import xtools
>>> import time
>>> now=time.localtime()
>>> now
(2024, 10, 3, 12, 23, 58, 3, 277)
>>> xtools.format_datetime(now)
'2024-10-03 12:23:58'
不過要注意的是如果要自行傳入日期時間元組給 xtools.format_datetime() 時必須傳入 8 個元素 (後面兩個設為 0 即可), 不能只傳年月日時分秒 6 個:
>>> xtools.format_datetime((2024, 10, 3, 12, 34, 56))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "xtools.py", line 191, in format_datetime
ValueError: need more than 6 values to unpack
>>> xtools.format_datetime((2024, 10, 3, 12, 34, 56, 0, 0))
'2024-10-03 12:34:56'
我已將此兩函式加入 xtools 函式庫中, 因為我覺得函式名稱較習慣 :
>>> import time
>>> now=time.localtime()
>>> xtools.strftime(now)
'2024-10-03 10:24:18'
>>> xtools.strftime((2024, 10, 3, 12, 34, 56))
'2024-10-03 12:34:56'
>>> dt=xtools.strptime('2024-10-03 10:24:18')
>>> dt
(2024, 10, 3, 10, 24, 18, 0, 0, 0)
沒有留言:
張貼留言