การจัดการวันเวลาใน python ด้วย datetime
เขียนเมื่อ 2016/06/21 19:35
มอดูล datetime เป็นหนึ่งในมอดูลภายในตัวของไพธอน มีหน้าที่จัดการเกี่ยวกับเรื่องวันเดือนปีและเวลาต่างๆ หน้าที่มีความคล้ายคลึงกับมอดูล time (อ่านรายละเอียดใน https://phyblas.hinaboshi.com/20160610) แต่ก็มีความต่างกันอยู่ บางครั้งก็อาจใช้ร่วมกัน datetime มักถูกใช้เมื่อต้องการจัดการกับข้อมูลที่อยู่ในรูปของวันเดือนปีหรือเวลาชั่วโมงนาทีวินาที เวลาและวันเดือนปีนั้นเป็นปริมาณที่ใช้หน่วยหลากหลายในการอธิบาย และการแปลงหน่วยก็มีความยุ่งยากเพราะมีความไม่สม่ำเสมอ เช่นจำนวนวันในหนึ่งปีหรือหนึ่งเดือนเป็นต้น
การใช้ออบเจ็กต์พิเศษของ datetime จะทำให้การคำนวณทำได้โดยง่ายขึ้น อีกทั้งยังสามารถปรับเปลี่ยนรูปแบบการแสดงผลให้เป็นไปตามที่ต้องการได้ง่ายด้วย การใช้มอดูลนี้ก่อนอื่นต้องเริ่มจากทำการ import เรียกใช้ก่อน
import datetime
ออบเจ็กต์พิเศษใน datetime
มอดูล datetime นั้นมีการนิยามคลาสของออบเจ็กต์สำหรับเก็บค่าวันเดือนปีและเวลาโดยเฉพาะ มีอยู่ 4 ชนิดคือ
datetime.date
ออบเจ็กต์เก็บค่าวันเดือนปีdatetime.time
ออบเจ็กต์เก็บค่าเวลาdatetime.datetime
เป็นออบเจ็กต์ที่เอา datetime.date กับ datetime.time มารวมกัน เก็บค่าทั้งวันเดือนปีและเวลาdatetime.timedelta
ออบเจ็กต์เก็บค่าระยะห่างระหว่างเวลาซึ่งมีหน่วยเป็นวันและวินาที
datetime.date
จะเก็บค่าตัวเลขปี เดือน วัน ทั้งหมดเป็นจำนวนเต็มเอาไว้ ในการสร้าง datetime.date
จะต้องใส่ค่าปี, เดือน, วัน ตามลำดับ เช่น
datetime.date(1905, 6, 1)
เมื่อใช้คำสั่ง print จะแสดงผลเป็น ปี-เดือน-วัน
print(datetime.date(1905, 6, 1)) # ได้ 1905-06-01
ค่าเดือนจะใส่ได้แค่ 1 ถึง 12 และค่าวันจะใส่ได้แค่ไหนขึ้นอยู่กับจำนวนวันในเดือนนั้น และทั้งหมดต้องเป็นจำนวนเต็มเท่านั้น จะมีทศนิยมไม่ได้ ถ้าใส่ค่าที่ไม่อยู่ในขอบเขตที่กำหนดจะเกิดข้อผิดพลาดทันที เช่น
datetime.date(1911,2,29)
# ได้ ValueError: day is out of range for month
datetime.date(1911,0,28)
# ได้ ValueError: month must be in 1..12
datetime.date(1911,2,27.1)
# ได้ TypeError: integer argument expected, got float
ส่วน datetime.time
จะเก็บค่าเวลาในหน่วยชั่วโมง, นาที, วินาที และไมโครวินาที การสร้าง datetime.time
จะต้องใส่ค่า ชั่วโมง, นาที, วินาที และไมโครวินาที เรียงตามลำดับ โดยจะใส่แต่ค่าชั่วโมงอย่างเดียวก็ได้ ค่าที่เหลือจะเป็น 0 เช่น
datetime.time(1)
# คือ 1 ชั่วโมง 0 นาที 0 วินาที 0 ไมโครวินาที
datetime.time(23, 59, 59, 999999)
# คือ 23 ชั่วโมง 59 นาที 59 วินาที 999999 ไมโครวินาที
เมื่อสั่ง print จะแสดงผลเป็น ชั่วโมง:นาที:วินาที.ไมโครวินาที
print(datetime.time(23, 59, 59, 999999))
# ได้ 23:59:59.999999
ค่าชั่วโมงจะต้องอยู่ในช่วง 0 ถึง 23 นาทีและวินาทีเป็น 0 ถึง 60 ส่วนไมโครวินาทีตั้งแต่ 0 ถึง 999999 ค่าทั้งหมดต้องเป็นจำนวนเต็มเท่านั้น ส่วนออบเจ็กต์ชนิด datetime.datetime นั้นเป็นตัวที่รวม datetime.date กับ datetime.time เข้าด้วยกัน คือจะเก็บค่า ปี, เดือน, วัน, ชั่วโมง, นาที, วินาที, ไมโครวินาที
เวลาที่สร้าง datetime.datetime
ขึ้นมาก็ใส่ค่าเรียงไล่ตั้งแต่ปีไปจนถึงไมโครวินาที โดยอาจใส่แค่ปีเดือนวัน 3 ตัวเท่านั้นส่วนที่เหลือละไว้ก็ได้ เช่น
datetime.datetime(2016,6,21)
# 21 มิ.ย. 2016 เวลา 0:00:00:000000 น.
เมื่อสั่ง print จะแสดงผลเป็น ปี-เดือน-วัน ชั่วโมง:นาที:วินาที.ไมโครวินาที
print(datetime.datetime(2016,6,21,17,35,30,115421))
# ได้ 2016-06-21 17:35:30.115421
ส่วน datetime.timedelta นั้นจะเก็บค่าช่วงระยะเวลา โดยเก็บในรูปของวัน, วินาที และ ไมโครวินาทีเท่านั้น โดย 1 วันมีค่าเท่ากับ 60*60*24 = 86400 วินาที การสร้าง datetime.timedelta นั้นต้องใส่ค่าเป็น วัน, วินาที และไมโครวินาที ตามลำดับ โดยสามารถละตัวหลังแล้วใส่แต่ตัวแรกๆก็ได้ เช่น
datetime.timedelta(1, 60)
# คือ 1 วัน 60 วินาที (1 นาที)
ค่าวันและวินาทีจะเป็นทศนิยมก็ได้ ถ้าใส่เป็นทศนิยมค่าจะถูกแปลงไปเป็นตัวหลังแทน เช่น
datetime.timedelta(1.1)
# กลายเป็น datetime.timedelta(1, 8640)
datetime.timedelta(1.1111111111)
# กลายเป็น datetime.timedelta(1, 9599, 999999)
ในทางกลับกันหากใส่ค่าวินาทีเกิน 86400 ก็จะถูกแปลงเป็นวัน และหากใส่ไมโครวินาทีเกิน 1 ล้านก็จะถูกแปลงเป็นวินาที
ค่าที่ใส่จะติดลบก็ได้ ถ้าหากวินาทีหรือไมโครวินาทีติดลบจะถูกนำไปหักจากวันและวินาทีตามลำดับ เช่น
datetime.timedelta(1,-1,-1)
# กลายเป็น datetime.timedelta(0, 86398, 999999)
เรายังอาจสร้าง datetime.timedelta
โดยกำหนดระยะเวลาเป็นมิลลิวินาที, นาที, ชั่วโมง, หรือสัปดาห์ได้ด้วย โดยใส่ในรูปคีย์เวิร์ด เวลาจะถูกแปลงเป็นหน่วยวัน, วินาที และไมโครวินาทีโดยอัตโนมัติ
datetime.timedelta(weeks=1,hours=17,minutes=2,milliseconds=999)
# ได้ datetime.timedelta(7, 61320, 999000)
เมื่อสั่ง print จะอยู่ในรูปของ วัน days, ชั่วโมง:นาที:วินาที.ไมโครวินาที
print(datetime.timedelta(111.9999999))
# ได้ 111 days, 23:59:59.991360
การคำนวณของ datetime.datetime และ datetime.timedelta
เมื่อนำ datetime.datetime
มาลบกันจะได้ผลออกมาเป็น datetime.timedelta
ซึ่งเก็บค่าระยะเวลาระหว่างสองเวลาที่เอามาลบกันนั้น เช่น
datetime.datetime(2016,6,21)-datetime.datetime(2016,6,20)
# ได้ datetime.timedelta(1)
เนื่องจากหน่วยที่เก็บใน datetime.timedelta นั้นใหญ่สุดเป็นวัน และรองลงมาเป็นวินาที ดังนั้นหน่วยอื่นก็จะถูกแปลงเป็นวันและวินาทีหมด
datetime.datetime(2016,6,21,7)-datetime.datetime(2016,6,21,3)
# ได้ datetime.timedelta(0, 14400)
datetime.datetime(2016,6,21)-datetime.datetime(1905,6,21)
# ได้ datetime.timedelta(40543)
นอกจากการลบกันแล้ว datetime.datetime และ datetime.datetime ด้วยกันไม่สามารถนำมาคำนวณอย่างอื่นได้เลย ทั้งบวก, คูณ, และยกกำลังแต่ datetime.datetime
สามารถนำมาบวกหรือลบกับ datetime.timedelta
ได้ ซึ่งก็จะได้ผลเป็น datetime.datetime
ตัวใหม่ เช่น
datetime.datetime(2016,6,21)+datetime.timedelta(0.71)
# ได้ datetime.datetime(2016, 6, 21, 17, 2, 24)
datetime.datetime(2016,6,21)-datetime.timedelta(1,1,1)
# ได้ datetime.datetime(2016, 6, 19, 23, 59, 58, 999999)
ส่วน datetime.timedelta นั้นสามารถเอามาคูณหรือหารกับตัวเลขได้ แต่ไม่สามารถบวกหรือลบหรือยกกำลังได้
datetime.timedelta(1,1,1)*2
# ได้ datetime.timedelta(2, 2, 2)
datetime.timedelta(1,1,1)/2
# ได้ datetime.timedelta(0, 43200, 500000)
datetime.timedelta กับ datetime.timedelta สามารถนำมาบวกหรือลบกันได้ แต่ไม่สามารถคูณหรือยกกำลังกันได้
datetime.timedelta(1,1)+datetime.timedelta(0,0,111)
# ได้ datetime.timedelta(1, 1, 111)
datetime.timedelta(1,1,1)-datetime.timedelta(1,1,1)
# ได้ datetime.timedelta(0)
และสามารถหารกันได้ ผลที่ได้คือค่าจำนวนเท่าของระยะเวลา
datetime.timedelta(1,1,1)/datetime.timedelta(1)
# ได้ 1.0000115740856481
และสามารถหารเอาเศษได้
datetime.timedelta(7,1,1)%datetime.timedelta(1)
# ได้ datetime.timedelta(0, 1, 1)
datetime.timedelta(7,2,1)%datetime.timedelta(0,0,999999)
# ได้ datetime.timedelta(0, 0, 604803)
สำหรับการเปรียบเทียบระหว่างเวลานั้น datetime.datetime นึงจะมากกว่าอีก datetime.datetime หนึ่งเมื่อเป็นเวลาช้ากว่า ส่วน datetime.timedelta ก็เทียบตามความยาวของเวลา
datetime.datetime(2016,6,21)>datetime.datetime(2016,6,20)
# ได้ True
แอตทริบิวต์และเมธอดของ datetime.timedelta
ค่าของวัน, วินาที และไมโครวินาที ถูกเก็บอยู่ในแอตทริบิวต์ days, seconds และ microseconds
ตามลำดับ
สามารถแสดงค่าทั้งหมดเป็นวินาทีได้ด้วยเมธอด total_seconds()
ตัวอย่าง
tdt = datetime.timedelta(3,70000,400000)
print(tdt.days) # ได้ 3
print(tdt.seconds) # ได้ 70000
print(tdt.microseconds) # ได้ 400000
print(tdt.total_seconds()) # ได้ 329200.4
แอตทริบิวต์และเมธอดของ datetime.datetime
ภายในออบเจ็กต์ datetime.datetime นั้นเก็บข้อมูลของปี, เดือน, วัน, ชั่วโมง, นาที, วินาที, ไมโครวินาที เอาไว้โดยสามารถดูค่าแต่ละค่าได้ที่แอตทริบิวต์ year, month, day, hour, minute, second, microsecond
dtdt = datetime.datetime(2016,6,21,17,35,30,115421)
print(dtdt.year) # ได้ 2016
print(dtdt.month) # ได้ 6
print(dtdt.day) # ได้ 21
print(dtdt.hour) # ได้ 17
print(dtdt.minute) # ได้ 35
print(dtdt.second) # ได้ 30
print(dtdt.microsecond) # ได้ 115421
datetime.datetime ยังประกอบด้วยเมธอดต่างๆที่ใช้แสดงผลข้อมูลส่วนต่างๆในรูปแบบต่างๆ ได้แก่
date() # แสดงส่วนวันเดือนปีในรูป datetime.date
time() # แสดงส่วนเวลาในรูป datetime.time
weekday() # แสดงเลขวันในสัปดาห์ โดยวันจันทร์เป็น 0 วันอาทิตย์เป็น 6
isoweekday() # แสดงเลขวันในสัปดาห์ โดยวันจันทร์เป็น 1 วันอาทิตย์เป็น 7
isocalendar() # แสดงผลวันเดือนปีในรูปแบบทูเพิล
ctime() # แสดงวันเวลาในรูป _วันในสัปดาห์ เดือน วัน ชั่วโมง:นาที:วินาที ปี_
timetuple() # แสดงวันเวลาในรูปออบเจ็กต์ time.struct_time
timestamp() # แสดงเวลาในรูปของจำนวนวินาทีนับจากเที่ยงคืนเวลา UTC ของวันที่ 1 ม.ค. 1970
isoformat() # แสดงวันเวลาในรูป _ปี-เดือน-วันTชั่วโมง:นาที:วินาที.ไมโครวินาที_
สำหรับ isoformat
ถ้าใส่อาร์กิวเมนต์ลงไปจะเป็นตัวคั่นระหว่างวันกับชั่วโมงแทนตัว T
ตัวอย่างเมธอดต่างๆ
dtdt = datetime.datetime(2016,6,21,17,35,30,115421)
print(dtdt.date()) # ได้ 2016-06-21
print(dtdt.time()) # ได้ 17:35:30.115421
print(dtdt.weekday()) # ได้ 1
print(dtdt.isoweekday()) # ได้ 2
print(dtdt.isocalendar()) # ได้ (2016, 25, 2)
print(dtdt.ctime()) # ได้ Tue Jun 21 17:35:30 2016
print(dtdt.timetuple()) # ได้ time.struct_time(tm_year=2016, tm_mon=6, tm_mday=21, tm_hour=17, tm_min=35, tm_sec=30, tm_wday=1, tm_yday=173, tm_isdst=-1)
print(dtdt.isoformat()) # ได้ 2016-06-21T17:35:30.115421
print(dtdt.isoformat(' ')) # ได้ 2016-06-21 17:35:30.115421
สำหรับ timestamp()
ค่าจะเป็น 0 ที่เวลา 7 โมงเช้าของวันที่ 1 ม.ค. 1970
เนื่องจากไทยอยู่เขตเวลา +7
print(dtdt.timestamp())
# ได้ 1466505330.115421
print(datetime.datetime(1970,1,1,0,0,0).timestamp())
# ได้ -25200.0
print(datetime.datetime(1970,1,1,7,0,0).timestamp())
# ได้ 0.0
การแก้ค่าวันเวลาใน datetime.datetime
ใน datetime.datetime มีเมธอด replace ซึ่งใช้แก้ไขค่าต่างๆภายใน datetime.datetime โดยอาร์กิวเมนต์ที่ต้องใส่นั้นเหมือนกับตอนสร้าง datetime.datetime เพียงแต่ว่าจะใส่แค่บางค่าในรูปคีย์เวิร์ด เฉพาะค่าที่ต้องการแก้เท่านั้น เพียงแต่ว่าเมธอดนี้ไม่ได้ทำการเปลี่ยนแปลงตัว datetime.datetime แค่คืนค่าของ datetime.datetime ที่ถูกแก้แล้วกลับมาเท่านั้น
ตัวอย่าง
dtdt = datetime.datetime(2016,6,21,17,35,30,115421)
dtdt.replace(2015)
# ได้ datetime.datetime(2015, 6, 21, 17, 35, 30, 115421)
dtdt.replace(month=7)
# ได้ datetime.datetime(2016, 7, 21, 17, 35, 30, 115421)
dtdt.replace(second=0,microsecond=0)
# ได้ datetime.datetime(2016, 6, 21, 17, 35)
การแสดงผลวันเวลาตามที่ต้องการ
นอกจาก การแสดงผล datetime.datetime ด้วยเมธอดตามที่กล่าวมาข้างต้น เราสามารถให้แสดงผล วันเวลาในรูปแบบตามที่ต้องการซึ่งกำหนดเองได้โดยใช้เมธอด strftime
อาร์กิวเมนต์ที่ต้องใส่คือสายอักขระที่ประกอบไปด้วย %
ตามด้วยอักษร ซึ่งแทนค่าในส่วนต่างๆในรูปแบบต่างๆของวันเวลา ซึ่งสรุปได้ตามนี้
%a # วันในสัปดาห์ในรูปย่อ
%A # วันในสัปดาห์เป็นชื่อเต็ม
%w # วันในสัปดาห์เป็นตัวเลข อาทิตย์เป็น 0 เสาร์เป็น 6
%d # วันที่ในรูปเลขสองหลัก (เติม 0 เมื่อมีหลักเดียว)
%b # ชื่อเดือนในรูปย่อ
%B # ชื่อเดือนเป็นชื่อเต็ม
%m # เลขเดือนเป็นเลขสองหลัก (เติม 0 เมื่อมีหลักเดียว)
%y # เลขปีในรูปเลขสองหลักสุดท้าย
%Y # เลขปีในรูปเลขสี่หลัก (เติม 0 เมื่อมีไม่ถึงสี่หลัก)
%H # เวลาชั่วโมงเป็นเลขสองหลักถึง 24 (เติม 0 เมื่อมีหลักเดียว)
%I # เวลาชั่วโมงเป็นเลขสองหลักไม่เกิน 12 (เติม 0 เมื่อมีหลักเดียว)
%p # เวลา AM หรือ PM
%M # เวลานาทีเป็นเลขสองหลัก (เติม 0 เมื่อมีหลักเดียว)
%S # เวลาวินาทีเป็นเลขสองหลัก (เติม 0 เมื่อมีหลักเดียว)
%f # เวลาไมโครวินาทีเป็นเลขหกหลัก (เติม 0 เมื่อมีไม่ถึงหกหลัก)
%j # เลขลำดับวันในปี (1 ถึง 366)
%U # หรือ %W ลำดับของสัปดาห์ภายในปี
%c # แสดงวันเวลาในรูปแบบเดียวกับ ctime()
%x # เดือน/ปี/วัน
%X # ชั่วโมง:นาที:วินาที
ตัวอย่าง
dtdt = datetime.datetime(2016,6,21,17,35,30,115421)
print(dtdt.strftime('%a')) # ได้ Tue
print(dtdt.strftime('%A')) # ได้ Tuesday
print(dtdt.strftime('%w')) # ได้ 2
print(dtdt.strftime('%d')) # ได้ 21
print(dtdt.strftime('%b')) # ได้ Jun
print(dtdt.strftime('%B')) # ได้ June
print(dtdt.strftime('%m')) # ได้ 06
print(dtdt.strftime('%y')) # ได้ 16
print(dtdt.strftime('%Y')) # ได้ 2016
print(dtdt.strftime('%H')) # ได้ 17
print(dtdt.strftime('%I')) # ได้ 05
print(dtdt.strftime('%p')) # ได้ PM
print(dtdt.strftime('%M')) # ได้ 35
print(dtdt.strftime('%S')) # ได้ 30
print(dtdt.strftime('%f')) # ได้ 115421
print(dtdt.strftime('%j')) # ได้ 173
print(dtdt.strftime('%U')) # ได้ 25
print(dtdt.strftime('%W')) # ได้ 25
print(dtdt.strftime('%c')) # ได้ Tue Jun 21 17:35:30 2016
print(dtdt.strftime('%x')) # ได้ 06/21/16
print(dtdt.strftime('%X')) # ได้ 17:35:30
การสร้าง datetime.datetime จากเมธอดของคลาส
เราสามารถสร้าง datetime.datetime ขึ้นมาจากเมธอดของคลาส datetime.datetime เองได้ด้วย เมธอดเหล่านั้นได้แก่
now() # สร้าง datetime.datetime ขึ้นจากเวลาขณะนี้
utcnow() # สร้าง datetime.datetime ขึ้นจากเวลาขณะนี้ในเขตเวลาสากล
fromtimestamp() # สร้าง datetime.datetime ขึ้นจาก timestamp โดยอิงเวลาท้องถิ่น
utcfromtimestamp() # สร้าง datetime.datetime ขึ้นจาก timestamp โดยอิงเวลาสากล
combine() # สร้าง datetime.datetime โดยใช้ datetime.date และ datetime.time มารวมกัน
strptime() # สร้าง datetime.datetime ขึ้นจากกระบวนการตรงข้ามกับ strftime
ตัวอย่าง
print(datetime.datetime.now()) # ได้เวลาปัจจุบัน
print(datetime.datetime.utcnow()) # ได้เวลาปัจจุบันลบ 7 ชั่วโมง
print(datetime.datetime.fromtimestamp(0)) # ได้ 1970-01-01 07:00:00
print(datetime.datetime.utcfromtimestamp(0)) # ได้ 1970-01-01 00:00:00
dtd = datetime.date(2016,6,21)
dtt = datetime.time(17,35,30,115421)
print(datetime.datetime.combine(dtd,dtt)) # ได้ 2016-06-21 17:35:30.115421
เมธอด strptime
นั้นเป็นกระบวนการที่ตรงกันข้ามกันกับ strftime ใช้แปลงสายอักขระที่มีรูปแบบตามที่กำหนดให้กลายเป็น datetime.datetime ในการใช้ให้ใส่สายอักขระที่จะแปลง ตามด้วยสายอักขระที่เขียนรูปแบบที่กำหนดการแปลง
ตัวอย่าง
print(datetime.datetime.strptime('11:11:11.1111','%X.%f'))
# ได้ 1900-01-01 11:11:11.111100
print(datetime.datetime.strptime('02','%H'))
# ได้ 1900-01-01 02:00:00
print(datetime.datetime.strptime('7/6/1991','%d/%m/%Y'))
# ได้ 1991-06-07 00:00:00
r = u'1842-11-5 เวลา 8 โมง 41 นาที 32 วินาที'
fmt = u'%Y-%m-%d เวลา %I โมง %M นาที %S วินาที'
print(datetime.datetime.strptime(r,fmt))
# ได้ 1842-11-05 08:41:32
อ้างอิง
http://docs.python.jp/3/library/datetime.html
http://nkmk.github.io/blog/python-datetime