ทำไม datetime.datetime.utcnow () ไม่มีข้อมูลเขตเวลา


285
datetime.datetime.utcnow()

ทำไมนี้datetimeไม่ได้ข้อมูลเขตเวลาใดก็ตามที่มันเป็นอย่างชัดเจน UTC เราจะต้องdatetime?

tzinfoผมจะคาดหวังว่าเรื่องนี้จะประกอบด้วย


วิธีการแปลงฟิลด์วันที่จัดรูปแบบ iso ปกติซึ่งเป็นประเภทสตริงเป็นรูปแบบ utc?
Navi

คำตอบ:


192

นั่นหมายความว่ามันเป็นเขตเวลาไร้เดียงสาดังนั้นคุณจึงไม่สามารถใช้กับ datetime.astimezone

คุณสามารถให้เขตเวลาเป็นแบบนี้ได้

import pytz  # 3rd party: $ pip install pytz

u = datetime.utcnow()
u = u.replace(tzinfo=pytz.utc) #NOTE: it works only with a fixed utc offset

ตอนนี้คุณสามารถเปลี่ยนเขตเวลา

print(u.astimezone(pytz.timezone("America/New_York")))

หากต้องการรับเวลาปัจจุบันในเขตเวลาที่กำหนดคุณสามารถส่ง tzinfo ไปที่datetime.now()โดยตรง:

#!/usr/bin/env python
from datetime import datetime
import pytz # $ pip install pytz

print(datetime.now(pytz.timezone("America/New_York")))

ใช้งานได้กับเขตเวลาใดก็ได้รวมถึงเขตเวลาที่สังเกตว่าการปรับเวลาตามฤดูกาล (DST) คือการทำงานสำหรับเขตเวลาที่อาจมีการชดเชย UTC ที่แตกต่างกันในเวลาที่ต่างกัน อย่าใช้tz.localize(datetime.now())- มันอาจล้มเหลวในระหว่างการเปลี่ยนแปลงเมื่อสิ้นสุดเวลา DST เมื่อเวลาท้องถิ่นไม่ชัดเจน


216
แต่ไม่มีเหตุผลที่ดีที่จะใช้เขตเวลาไร้เดียงสา - ระบุเป็น UTC เหตุใดคุณจึงต้องค้นหาห้องสมุดบุคคลที่สามเพื่อให้ทำงานได้อย่างถูกต้อง
Mark Ransom

4
ฉันเห็นด้วย; สำหรับเวลาของฉันไร้เดียงสาไร้ประโยชน์อย่างสมบูรณ์ มีการสนทนาในรายการไพ ธ อนในขณะนี้เกี่ยวกับการเพิ่ม pytz ใน stdlib; ปัญหาไม่ใช่สิทธิ์ใช้งาน แต่ความจริงที่ว่าข้อมูลเขตเวลาได้รับการปรับปรุงบ่อยครั้ง (ซึ่ง Python เองไม่สามารถทำได้) นอกจากนี้ยัง pytz ไม่ใช้ tzinfo astimezoneอินเตอร์เฟซในทางที่คาดหวังเพื่อให้คุณสามารถรับข้อผิดพลาดถ้าคุณพยายามที่จะใช้บางส่วนของเขตเมือง ดังนั้นวันที่และเวลาไม่เพียง แต่ไม่มีเขตเวลาดั้งเดิมเท่านั้น แต่การใช้งาน tzinfo ที่มีอยู่อย่างกว้างขวางเท่านั้นไม่สอดคล้องกับมาตรฐานที่ควรจะเป็น
bobince

5
@bobince ทำไมไม่ pytz และไลบรารี datetime มาตรฐานทำงานให้คุณ แกน Python และ pytz พัฒนาขึ้นเมื่อโครงการอิสระลดความซับซ้อนด้านลอจิสติกสำหรับทีมหลัก ใช่การลดความซับซ้อนสำหรับทีม Python core จะเพิ่มความซับซ้อนให้กับผู้ใช้ Python ทุกคนที่ต้องจัดการกับเขตเวลา แต่ฉันเชื่อว่าพวกเขาตัดสินใจด้วยเหตุผลนี้ กฎ "ไลบรารีมาตรฐานไม่มีอินสแตนซ์ tzinfo ... " ดีมากเพราะมันง่ายทำไมต้องยกเว้นที่นี่
Derek Litz

15
วิธีการเกี่ยวกับเพียงu=datetime.now(pytz.utc)
เครกแมก

4
@bain: ไม่ได้ใช้tz.localize(datetime.now()); ใช้datetime.now(tz)แทน
jfs

142

โปรดทราบว่าสำหรับงูหลาม 3.2 เป็นต้นไปโมดูลมีdatetime datetime.timezoneเอกสารสำหรับdatetime.utcnow()พูดว่า:

ตระหนัก datetime UTC ปัจจุบันสามารถหาได้โดยการโทรdatetime.now(timezone.utc)

ดังนั้นคุณสามารถทำได้:

>>> import datetime
>>> datetime.datetime.now(datetime.timezone.utc)
datetime.datetime(2014, 7, 10, 2, 43, 55, 230107, tzinfo=datetime.timezone.utc)

2
ข้อไหนดี? datetime.now(timezone.utc)หรือdatetime.utcnow(timezone.utc)?
Jesse Webb

8
datetime.utcnow()ไม่มีข้อโต้แย้ง datetime.now(timezone.utc)ดังนั้นจึงจะต้องมีการ
Craig McQueen

1
datetime.now()จะคืนค่าเวลาของเครื่อง แต่datetime.utcnow()จะส่งคืนเวลา UTC ที่แท้จริง
Babu

13
@Babu: datetime.utcnow()ไม่ได้ตั้งค่าtzinfoเพื่อระบุว่าเป็น UTC แต่datetime.now(datetime.timezone.utc)ส่งคืนเวลา UTC ด้วยการ tzinfoตั้งค่า
Craig McQueen

@CraigMcQueen ดังนั้นถ้าเราผ่านtzวัตถุในตัวสร้างตอนนี้มันจะคืนค่าเวลาของเขตเวลานั้นหรือไม่ ตกลง! ขอบคุณสำหรับการชี้ให้เห็น
Babu

71

ไลบรารี Python มาตรฐานไม่มีคลาส tzinfo ใด ๆ (แต่ดู pep 431 ) ฉันสามารถเดาได้จากเหตุผลเท่านั้น โดยส่วนตัวฉันคิดว่ามันเป็นความผิดพลาดที่จะไม่รวมคลาส tzinfo สำหรับ UTC เพราะนั่นเป็นเรื่องที่ไม่น่าโต้เถียงมากพอที่จะใช้งานมาตรฐาน

แก้ไข:แม้ว่าจะไม่มีการดำเนินการในห้องสมุดมีหนึ่งให้เป็นตัวอย่างในเอกสารtzinfo

from datetime import timedelta, tzinfo

ZERO = timedelta(0)

# A UTC class.

class UTC(tzinfo):
    """UTC"""

    def utcoffset(self, dt):
        return ZERO

    def tzname(self, dt):
        return "UTC"

    def dst(self, dt):
        return ZERO

utc = UTC()

วิธีใช้เพื่อรับเวลาปัจจุบันเป็นวัตถุ datetime ที่รับรู้:

from datetime import datetime 

now = datetime.now(utc)

มีdatetime.timezone.utcใน Python 3.2+:

from datetime import datetime, timezone 

now = datetime.now(timezone.utc)

8
ลองคิดดูว่าทำไมคลาสนี้ไม่ได้ถูกจัดเตรียมไว้ตั้งแต่แรก (และที่สำคัญกว่านั้นใช้สำหรับdatetimeวัตถุที่สร้างขึ้นโดยutcnow()) ...
André Caron

17
timezone.utcในที่สุดวัตถุเขตเวลาได้ถูกเพิ่มไปยัง Python 3.2 ความเข้ากันได้ย้อนหลังutcnow()ยังคงส่งกลับวัตถุเวลาเขตเวลาน้อย now(timezone.utc)แต่คุณจะได้รับสิ่งที่คุณต้องการโดยการเรียก
mhsmith

4
@ rgove นั่นเป็นชนิดของการแก้ไขความผิดที่ควรจะเป็นเกมที่ยุติธรรมสำหรับ Python 3 พวกเขาไม่ควรกังวลเกี่ยวกับความเข้ากันได้ย้อนหลัง มีอีกตัวอย่างหนึ่งที่ฉันอ่านภายในสองสามวันที่ผ่านมา - structโมดูลจะทำการแปลงอัตโนมัติจาก Unicode เป็นการทดสอบและการตัดสินใจขั้นสุดท้ายคือการหยุดความเข้ากันได้กับ Python 3 รุ่นก่อนหน้าเพื่อป้องกันไม่ให้การตัดสินใจที่ไม่ดีก้าวไปข้างหน้า
Mark Ransom

2
ฉันตะลึงว่าtzinfoเอกสารของ Python มีตัวอย่างของโค้ดที่จะนำไปใช้ แต่มันไม่ได้รวมฟังก์ชั่นนั้นไว้ใน datetime เอง! docs.python.org/2/library/datetime.html#datetime.tzinfo.fromutc
LS

1
@ LS ใช่pytzเป็นแหล่งข้อมูลที่ยอดเยี่ยม เมื่อถึงเวลาที่ฉันได้แก้ไขคำตอบของฉันให้ใส่รหัสตัวอย่างบางคนได้แนะนำไปแล้วและฉันไม่ต้องการขโมยฟ้าร้องของพวกเขา
Mark Ransom

20

pytzโมดูลเป็นทางเลือกหนึ่งและมีอีกpython-dateutilซึ่งแม้จะยังเป็นแพคเกจของบุคคลที่สามแล้วอาจจะขึ้นอยู่กับการอ้างอิงอื่น ๆ ของคุณและระบบปฏิบัติการ

ฉันแค่ต้องการรวมวิธีการนี้ไว้สำหรับอ้างอิงถ้าคุณติดตั้งไว้แล้วpython-dateutilเพื่อจุดประสงค์อื่นคุณสามารถใช้วิธีนี้tzinfoแทนการทำซ้ำpytz

import datetime
import dateutil.tz

# Get the UTC time with datetime.now:
utcdt = datetime.datetime.now(dateutil.tz.tzutc())

# Get the UTC time with datetime.utcnow:
utcdt = datetime.datetime.utcnow()
utcdt = utcdt.replace(tzinfo=dateutil.tz.tzutc())

# For fun- get the local time
localdt = datetime.datetime.now(dateutil.tz.tzlocal())

ฉันมักจะเห็นด้วยว่าการเรียกร้องให้utcnowควรรวมข้อมูลเขตเวลา UTC ไว้ด้วย ฉันสงสัยว่าสิ่งนี้ไม่รวมอยู่เพราะไลบราลี่ datetime ดั้งเดิมจะใช้ค่าเริ่มต้นที่ไร้เดียงสาสำหรับการทำงานร่วมกันข้าม


1
NameError: ไม่ได้กำหนดชื่อ 'dt'
xApple

ฉันใช้ datetime.datetime.utcfromtimestamp () การโทรและต้องการเพิ่ม tzinfo โซลูชันที่สองใช้งานได้สำหรับฉัน: utcdt = datetime.datetime.utcfromtimestamp(1234567890).replace(dateutil.tz.tzutc())
Ian Lee

1
หมายเหตุ: ไม่เหมือนdatetime.now(pytz_tz)ที่ใช้งานได้เสมอ อาจล้มเหลวในระหว่างการเปลี่ยนเวลาdatetime.now(dateutil.tz.tzlocal()) PEP 495 - ความไม่ลงรอยกันเวลาท้องถิ่นอาจช่วยให้dateutilสถานการณ์ดีขึ้นในอนาคต
jfs

@IanLee: คุณสามารถใช้utc_dt = datetime.fromtimestamp(1234567890, dateutil.tz.tzutc())(หมายเหตุ: dateutilมีไม่คง UTC ชดเชย (เช่นdateutil.tz.tzlocal()) อาจล้มเหลวที่นี่ใช้แก้ปัญหาชั่นแทน ) pytz
jfs

เนื่องจากโปรแกรมของฉันนำเข้าdateutilมาdateutil.parserแล้วฉันชอบวิธีนี้มากที่สุด utcCurrentTime = datetime.datetime.now(tz=dateutil.tz.tzutc())มันเป็นง่ายๆเป็น: Viola !!
LS

11

Julien Danjou เขียนบทความที่ดีอธิบายว่าทำไมคุณไม่ควรจัดการกับเขตเวลา ข้อความที่ตัดตอนมา:

แท้จริงแล้ว Python datetime API จะส่งคืนออบเจ็กต์ที่ไม่รู้จักซึ่งมักจะโชคไม่ดี อันที่จริงแล้วทันทีที่คุณได้รับหนึ่งในวัตถุนี้ไม่มีวิธีที่จะรู้ว่าเขตเวลาคืออะไรดังนั้นวัตถุเหล่านี้จะค่อนข้าง "ไร้ประโยชน์" ด้วยตนเอง

อนิจจาแม้ว่าคุณอาจใช้utcnow()คุณยังคงไม่เห็นข้อมูลเขตเวลาตามที่คุณค้นพบ

คำแนะนำ:

  • ใช้datetimeวัตถุที่รับรู้เสมอเช่นข้อมูลเขตเวลา ซึ่งทำให้แน่ใจว่าคุณสามารถเปรียบเทียบพวกเขาโดยตรง ( datetime วัตถุที่รับรู้และไม่รู้จักนั้นไม่สามารถเทียบเคียงได้) และจะส่งกลับไปยังผู้ใช้อย่างถูกต้อง ใช้ประโยชน์จากpytzให้มีวัตถุเขตเวลา

  • ใช้ISO 8601เป็นรูปแบบสตริงอินพุตและเอาต์พุต ใช้datetime.datetime.isoformat()เพื่อส่งคืนการประทับเวลาเป็นสตริงที่จัดรูปแบบโดยใช้รูปแบบนั้นซึ่งรวมถึงข้อมูลเขตเวลา

  • หากคุณต้องการแยกสตริงที่มีการประทับเวลาที่จัดรูปแบบ ISO 8601 คุณสามารถพึ่งพาiso8601ซึ่งจะส่งคืนการประทับเวลาด้วยข้อมูลเขตเวลาที่ถูกต้อง สิ่งนี้ทำให้การเปรียบเทียบเวลาประทับโดยตรง


1
นี่เป็นคำแนะนำที่ทำให้เข้าใจผิดเล็กน้อย กฎง่ายๆคือไม่ต้องจัดการกับเขตเวลา เก็บและส่ง tz unware utc objects (วัตถุยุค) เสมอ ควรคำนวณเขตเวลาเฉพาะเวลาที่เป็นตัวแทนใน UI
nehem

1
ฟังดูเหมือนว่ามันจะเข้ากันได้ดีกับความคิดของจูเลียนค่อนข้างดี คำแนะนำเฉพาะใดของเขา (ตามที่อ้างถึงด้านบน) ทำให้เข้าใจผิด?
Joe D'Andrea

10

เพื่อเพิ่มtimezoneข้อมูลใน Python 3.2+

import datetime

>>> d = datetime.datetime.now(tz=datetime.timezone.utc)
>>> print(d.tzinfo)
'UTC+00:00'

1
AttributeError: 'module' object has no attribute 'timezone' Python 2.7.13 (ค่าเริ่มต้น, 19 ม.ค. 2017, 14:48:08)
Marcin Owsiany

-6
from datetime import datetime 
from dateutil.relativedelta import relativedelta
d = datetime.now()
date = datetime.isoformat(d).split('.')[0]
d_month = datetime.today() + relativedelta(months=1)
next_month = datetime.isoformat(d_month).split('.')[0]

-13

วันที่ UTC ไม่ต้องการข้อมูลเขตเวลาใด ๆ เนื่องจากเป็น UTC ซึ่งตามคำจำกัดความหมายความว่าไม่มีการชดเชย


10
เท่าที่ฉันสามารถบอกได้จากdocs.python.org/library/datetime.html datetime ที่ไม่มี tzinfo จะเป็นที่ที่ไม่ได้ระบุเขตเวลา ที่นี่มีการระบุเขตเวลาดังนั้นควรมีเขตเหตุผล มีความแตกต่างใหญ่ระหว่างวันที่ / เวลาโดยไม่มีเขตเวลาที่เกี่ยวข้องและอีกอันหนึ่งซึ่งอยู่ใน UTC อย่างแน่นอน (เป็นการดีที่พวกเขาควรจะเป็นประเภท IMO ที่แตกต่างกัน แต่นั่นเป็นอีกเรื่อง ... )
Jon Skeet

@ JonSkeet ฉันคิดว่าคุณพลาดจุดสำคัญของ Ignacio ที่ UTC ไม่ใช่เขตเวลา น่าอัศจรรย์ที่คำตอบนี้มี -9 คะแนนในขณะที่ฉันพิมพ์ ...
CS

3
@CS: อิกนาชิโอไม่เคยระบุว่า ... และแม้ว่าการพูดอย่างเคร่งครัด UTC ไม่ใช่เขตเวลา แต่ก็มักจะถือว่าเป็นหนึ่งในการทำให้ชีวิตง่ายขึ้นอย่างมาก (รวมถึงใน Python เช่นกับpytz.utc) โปรดทราบว่ามีความแตกต่างอย่างมากระหว่างค่าที่ไม่ทราบค่าออฟเซ็ตจาก UTC และค่าที่ทราบว่าเป็น 0 ค่าหลังคือสิ่งที่utcnow() ควรส่งคืน IMO ซึ่งจะสอดคล้องกับ "วัตถุที่รับรู้ใช้เพื่อแสดงช่วงเวลาที่เฉพาะเจาะจงซึ่งไม่เปิดให้ตีความ" ตามเอกสารประกอบ
Jon Skeet
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.