Tại sao datetime.datetime.utcnow () không chứa thông tin múi giờ?


285
datetime.datetime.utcnow()

Tại sao điều này datetimekhông có bất kỳ thông tin múi giờ nào cho rằng nó rõ ràng là một UTCdatetime ?

Tôi hy vọng rằng điều này sẽ chứa tzinfo.


Làm cách nào để chuyển đổi trường ngày định dạng iso bình thường có kiểu chuỗi thành định dạng utc?
Navi

Câu trả lời:


192

Điều đó có nghĩa là nó là múi giờ ngây thơ, vì vậy bạn không thể sử dụng nó với datetime.astimezone

bạn có thể cho nó một múi giờ như thế này

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

bây giờ bạn có thể thay đổi múi giờ

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

Để có được thời gian hiện tại trong một múi giờ nhất định, bạn có thể chuyển datetime.now()trực tiếp tzinfo :

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

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

Nó hoạt động cho bất kỳ múi giờ nào, kể cả những múi giờ quan sát thời gian tiết kiệm ánh sáng ban ngày (DST), nghĩa là nó hoạt động cho các múi giờ có thể có các độ lệch utc khác nhau tại các thời điểm khác nhau (bù utc không cố định). Không sử dụng tz.localize(datetime.now())- nó có thể thất bại trong quá trình chuyển đổi cuối DST khi giờ địa phương không rõ ràng.


216
Nhưng không có lý do chính đáng nào để nó ngây thơ múi giờ - nó được chỉ định là UTC. Tại sao bạn cần tìm kiếm một thư viện bên thứ ba để làm cho nó hoạt động đúng?
Đánh dấu tiền chuộc

4
Tôi đồng ý; đối với tôi thời gian 'ngây thơ' là hoàn toàn vô dụng. Có cuộc thảo luận về danh sách python tại thời điểm này về việc thêm pytz vào stdlib; vấn đề không phải là cấp phép mà là dữ liệu múi giờ được cập nhật thường xuyên (mà bản thân Python không thể). Ngoài ra pytz không triển khai giao diện tzinfo theo cách dự kiến ​​để bạn có thể gặp lỗi nếu bạn cố gắng sử dụng một số múi giờ trong thành phố astimezone. Vì vậy, datetime không chỉ không có múi giờ riêng, mà việc triển khai tzinfo duy nhất có sẵn rộng rãi là không tuân thủ tiêu chuẩn được cho là.
bobince

5
@bobince Tại sao pytz và các thư viện datetime tiêu chuẩn làm việc cho bạn? Lõi Python và pytz phát triển như các dự án độc lập làm giảm độ phức tạp hậu cần cho nhóm cốt lõi. Đúng, giảm độ phức tạp cho nhóm lõi Python làm tăng độ phức tạp cho tất cả người dùng Python cần xử lý múi giờ, nhưng tôi tin rằng họ đã đưa ra quyết định này vì một lý do chính đáng. Quy tắc "Thư viện chuẩn không có phiên bản tzinfo ..." rất tuyệt vì nó đơn giản, tại sao lại tạo một ngoại lệ ở đây?
Derek Litz

15
Làm thế nào về chỉu=datetime.now(pytz.utc)
Craig McQueen

4
@bain: không sử dụng tz.localize(datetime.now()); sử dụng datetime.now(tz)thay thế.
jfs

142

Lưu ý rằng đối với Python 3.2 trở đi, datetimemô-đun chứa datetime.timezone. Các tài liệu cho datetime.utcnow()biết:

Một datetime UTC hiện tại có thể nhận được bằng cách gọi .datetime.now(timezone.utc)

Vì vậy, bạn có thể làm:

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

2
Cái nào thích hơn? datetime.now(timezone.utc)hay datetime.utcnow(timezone.utc)?
Jesse Webb

8
datetime.utcnow()không có đối số. Vì vậy, nó sẽ phải được datetime.now(timezone.utc).
Craig McQueen

1
datetime.now()sẽ trả về thời gian của máy nhưng datetime.utcnow()sẽ trả về thời gian UTC thực tế.
Babu

13
@Babu: datetime.utcnow()không được đặt tzinfođể chỉ ra rằng đó là UTC. Nhưng datetime.now(datetime.timezone.utc)không trả lại thời gian UTC với tzinfo thiết lập.
Craig McQueen

@CraigMcQueen Vậy nếu chúng ta vượt qua một tzđối tượng trong hàm tạo bây giờ thì nó sẽ trả về thời gian của múi giờ đó? Đồng ý! Cảm ơn đã chỉ ra.
Babu

71

Các thư viện Python chuẩn không bao gồm bất kỳ lớp tzinfo nào (nhưng xem pep 431 ). Tôi chỉ có thể đoán tại các lý do. Cá nhân tôi nghĩ rằng đó là một sai lầm khi không bao gồm một lớp tzinfo cho UTC, bởi vì đó là một điều không đủ tranh cãi để có một triển khai tiêu chuẩn.

Chỉnh sửa: Mặc dù không có triển khai trong thư viện, nhưng có một ví dụ được đưa ra làm tzinfotài liệu .

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()

Để sử dụng nó, để lấy thời gian hiện tại làm đối tượng datetime nhận thức:

from datetime import datetime 

now = datetime.now(utc)

datetime.timezone.utctrong Python 3.2+:

from datetime import datetime, timezone 

now = datetime.now(timezone.utc)

8
Tìm hiểu lý do tại sao lớp này không được cung cấp ở vị trí đầu tiên (và quan trọng hơn là được sử dụng cho datetimecác đối tượng được tạo bởi utcnow()) ...
André Caron

17
Đối tượng múi giờ timezone.utccuối cùng đã được thêm vào Python 3.2. Để tương thích ngược, utcnow()vẫn trả về một đối tượng thời gian không có múi giờ, nhưng bạn có thể nhận được những gì bạn muốn bằng cách gọi now(timezone.utc).
mhsmith

4
@rgove, đó là loại quyền sai được cho là trò chơi công bằng cho Python 3. Họ không nên lo lắng về khả năng tương thích ngược. Có một ví dụ khác tôi đã đọc trong vài ngày qua - structmô-đun sẽ thực hiện chuyển đổi tự động từ Unicode sang bytestring và quyết định cuối cùng là phá vỡ tính tương thích với các phiên bản Python 3 trước đó để ngăn chặn quyết định tồi tệ.
Đánh dấu tiền chuộc

2
Tôi chết lặng rằng tzinfotài liệu của Python bao gồm các ví dụ về mã để triển khai nó, nhưng chúng không bao gồm chức năng đó trong chính datetime! docs.python.org/2/l Library / datetime.html
LS

1
@LS có, pytzlà một tài nguyên tuyệt vời. Vào thời điểm tôi đã chỉnh sửa câu trả lời của mình để đưa vào mã ví dụ, một người khác đã gợi ý và tôi không muốn đánh cắp sấm sét của họ.
Đánh dấu tiền chuộc

20

Các pytzmô-đun là một lựa chọn, và có mộtpython-dateutil , mà mặc dù cũng là gói của bên thứ ba, có thể đã có sẵn tùy thuộc vào phụ thuộc khác của bạn và hệ điều hành.

Tôi chỉ muốn đưa phương pháp này vào tham khảo - nếu bạn đã cài đặt python-dateutilcho các mục đích khác, bạn có thể sử dụng phương pháp này tzinfothay vì sao chép vớipytz

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())

Tôi có xu hướng đồng ý rằng các cuộc gọi utcnownên bao gồm thông tin múi giờ UTC. Tôi nghi ngờ rằng điều này không được bao gồm bởi vì thư viện datetime gốc mặc định cho các datetimes ngây thơ cho khả năng tương thích chéo.


1
TênError: tên 'dt' không được xác định
xApple

Tôi đã sử dụng lệnh gọi datetime.datetime.utcfromtimestamp () và cần thêm tzinfo, Giải pháp thứ hai hiệu quả với tôi: utcdt = datetime.datetime.utcfromtimestamp(1234567890).replace(dateutil.tz.tzutc())
Ian Lee

1
lưu ý: không giống như datetime.now(pytz_tz)luôn luôn hoạt động; datetime.now(dateutil.tz.tzlocal())có thể thất bại trong quá trình chuyển đổi DST . PEP 495 - Định hướng thời gian địa phương có thể cải thiện dateutiltình hình trong tương lai.
jfs

@IanLee: bạn có thể sử dụng utc_dt = datetime.fromtimestamp(1234567890, dateutil.tz.tzutc())(lưu ý: dateutilvới một utc không cố định bù đắp (như dateutil.tz.tzlocal()) có thể thất bại ở đây , sử dụng một pytzgiải pháp dựa trên thay vì ).
jfs

Kể từ khi chương trình của tôi đã được nhập khẩu dateutilcho dateutil.parser, tôi thích giải pháp này tốt nhất. Nó đơn giản như : utcCurrentTime = datetime.datetime.now(tz=dateutil.tz.tzutc()). Viola !!
LS

11

Julien Danjou đã viết một bài báo hay giải thích lý do tại sao bạn không bao giờ nên đối phó với các múi giờ . Một đoạn trích:

Thật vậy, API datetime của Python luôn trả về các đối tượng datetime không biết, điều này rất đáng tiếc. Thật vậy, ngay khi bạn có được một trong những vật thể này, không có cách nào để biết múi giờ là gì, do đó những vật thể này khá "vô dụng".

Than ôi, mặc dù bạn có thể sử dụng utcnow(), bạn vẫn sẽ không thấy thông tin múi giờ, như bạn đã khám phá.

Khuyến nghị:

  • Luôn luôn sử dụng datetimecác đối tượng nhận thức , tức là với thông tin múi giờ. Điều đó đảm bảo rằng bạn có thể so sánh chúng trực tiếp ( datetime các đối tượng nhận biết và không biết không thể so sánh được) và sẽ trả lại chúng một cách chính xác cho người dùng. Tận dụng pytz để có các đối tượng múi giờ.

  • Sử dụng ISO 8601 làm định dạng chuỗi đầu vào và đầu ra. Sử dụng datetime.datetime.isoformat()để trả về dấu thời gian dưới dạng chuỗi được định dạng bằng định dạng đó, bao gồm thông tin múi giờ.

  • Nếu bạn cần phân tích các chuỗi có chứa dấu thời gian được định dạng ISO 8601, bạn có thể dựa vào iso8601đó, trả về dấu thời gian với thông tin múi giờ chính xác. Điều này làm cho dấu thời gian trực tiếp so sánh.


1
Đây là khuyến nghị hơi sai lệch. Quy tắc của ngón tay cái là, không bao giờ đối phó với múi giờ. Luôn lưu trữ và truyền các đối tượng utc unware (đối tượng epoch). Múi giờ chỉ nên được tính tại thời điểm đại diện trong UI
nehem

1
Nghe có vẻ như nó phù hợp với suy nghĩ của Julien khá tốt. Những khuyến nghị cụ thể nào của anh ấy (như được giới thiệu ở trên) là sai lệch?
Joe D'Andrea

10

Để thêm timezonethông tin trong 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 (mặc định, ngày 19 tháng 1 năm 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

Ngày UTC không cần bất kỳ thông tin múi giờ nào vì chúng là UTC, theo định nghĩa có nghĩa là chúng không có bù.


10
Theo như tôi có thể nói từ docs.python.org/library/datetime.html , một datetime mà không có một tzinfo là một trong những nơi mà các múi giờ là không xác định. Ở đây múi giờ đã được chỉ định, do đó, nó phải có mặt. Có một sự khác biệt lớn giữa ngày / giờ không có múi giờ liên quan và múi giờ chắc chắn ở UTC. (Lý tưởng nhất là các loại IMO khác nhau, nhưng đó là vấn đề khác ...)
Jon Skeet

@JonSkeet Tôi nghĩ rằng bạn đang thiếu quan điểm của Ignacio rằng UTC không phải là múi giờ. Thật ngạc nhiên khi câu trả lời này có điểm -9 khi tôi gõ này ...
CS

3
@CS: Vâng Ignacio không bao giờ nói rằng ... và trong khi nói một cách nghiêm túc thì UTC không phải là múi giờ, nó thường được coi là một để làm cho cuộc sống đơn giản hơn đáng kể (kể cả trong Python, ví dụ như với pytz.utc). Lưu ý rằng có một sự khác biệt lớn giữa một giá trị mà bù đắp từ UTC là không rõ và một trong những nơi được biết đến là 0. Sau đó là những gì utcnow() nên trở về, IMO. Điều đó sẽ phù hợp với "Một đối tượng nhận thức được sử dụng để thể hiện một thời điểm cụ thể không mở để giải thích" theo tài liệu.
Jon Skeet
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.