Giờ ISO (ISO 8601) bằng Python


337

Tôi có một tập tin. Trong Python, tôi muốn dành thời gian tạo của nó và chuyển đổi nó thành chuỗi thời gian ISO (ISO 8601) trong khi bảo tồn thực tế rằng nó được tạo trong Múi giờ miền đông (ET) .

Làm cách nào để tôi lấy thời gian của tệp và chuyển đổi nó thành chuỗi thời gian ISO biểu thị Múi giờ miền đông (và tính đến thời gian tiết kiệm ánh sáng ban ngày, nếu cần thiết)?



11
@ Nick- Liên kết hữu ích, nhưng không phải là một bản sao - anh ấy hỏi về việc chuyển đổi theo cách khác.
Yarin

1
@ Joseph- Tôi vừa hỏi điều này liên quan đến RFC 3999- nên hoạt động cho việc này - Tạo dấu thời gian RFC 3339 bằng Python
Yarin

Câu trả lời:


557

Địa phương theo ISO 8601:

import datetime
datetime.datetime.now().isoformat()
>>> 2020-03-20T14:28:23.382748

UTC đến ISO 8601:

import datetime
datetime.datetime.utcnow().isoformat()
>>> 2020-03-20T01:30:08.180856

Cục bộ theo ISO 8601 mà không cần micro giây:

import datetime
datetime.datetime.now().replace(microsecond=0).isoformat()
>>> 2020-03-20T14:30:43

UTC đến ISO 8601 với thông tin TimeZone (Python 3):

import datetime
datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat()
>>> 2020-03-20T01:31:12.467113+00:00

UTC đến ISO 8601 với thông tin TimeZone cục bộ không có micro giây (Python 3):

import datetime
datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
>>> 2020-03-20T14:31:43+13:00

Địa phương theo ISO 8601 với thông tin TimeZone (Python 3):

import datetime
datetime.datetime.now().astimezone().isoformat()
>>> 2020-03-20T14:32:16.458361+13:00

Lưu ý có một lỗi khi sử dụng astimezone()vào thời gian utc. Điều này cho kết quả không chính xác:

datetime.datetime.utcnow().astimezone().isoformat() #Incorrect result

Đối với Python 2, xem và sử dụng pytz .


17
.isoformat()có thể lấy tham số dấu phân cách, (Trong trường hợp bạn muốn thứ gì đó ngoài 'T'):.isoformat(' ')
ThorSummoner

5
@ThorSummoner tốt để biết! Nhưng hãy lưu ý rằng việc thay đổi dải phân cách sẽ không tuân thủ ISO-8601 nữa ... điều này rất ít ý nghĩa (bên cạnh đó, có nhiều cách tốt hơn để in ngày nhưng đó không phải là câu hỏi ở đây). RFC
estani

4
Không gian được phép là một phần của tiêu chuẩn ISO-8601. It is permitted to omit the 'T' character by mutual agreement.
raychi

4
@raychi Nó luôn được phép thay đổi một tiêu chuẩn theo thỏa thuận chung (trong nhiều trường hợp sẽ phá vỡ tiêu chuẩn, nhưng ai quan tâm nếu đó là thỏa thuận chung, phải không?). 2c của tôi: đừng, hãy để nguyên như vậy.
estani

14
Câu trả lời này là sai vì datetime.datetime.now (). Isoformat () trả về chuỗi ISO 8601 cục bộ mà không gắn nhãn là cục bộ. Bạn cần phải có datetime.timezone đại diện cho múi giờ địa phương để có được isoformat để thực hiện đúng.
Sam Hartman

66

Đây là những gì tôi sử dụng để chuyển đổi sang định dạng thời gian XSD:

from datetime import datetime
datetime.now().replace(microsecond=0).isoformat()
# You get your ISO string

Tôi đã gặp câu hỏi này khi tìm định dạng thời gian ngày XSD ( xs:dateTime). Tôi cần phải loại bỏ micro giây từ isoformat.


4
Là gì "XSD" (trong ngữ cảnh này)?
Peter Mortensen

1
Tôi tin rằng anh ấy có nghĩa là xs:datetừ các bảng định kiểu XSD / XML.
sventechie

1
Nó có nghĩa làxs:dateTime
radtek

56

Biểu diễn thời gian ISO 8601

Tiêu chuẩn quốc tế ISO 8601 mô tả một chuỗi đại diện cho ngày và thời gian. Hai ví dụ đơn giản của định dạng này là

2010-12-16 17:22:15
20101216T172215

(cả hai đều đại diện cho ngày 16 tháng 12 năm 2010), nhưng định dạng cũng cho phép thời gian phân giải dưới giây và chỉ định múi giờ. Định dạng này tất nhiên không dành riêng cho Python, nhưng nó tốt cho việc lưu trữ ngày và giờ ở định dạng di động. Chi tiết về định dạng này có thể được tìm thấy trong mục Markus Kuhn .

Tôi khuyên bạn nên sử dụng định dạng này để lưu trữ thời gian trong các tệp.

Một cách để có được thời gian hiện tại trong biểu diễn này là sử dụng strftime từ mô đun thời gian trong thư viện chuẩn Python:

>>> from time import strftime
>>> strftime("%Y-%m-%d %H:%M:%S")
'2010-03-03 21:16:45'

Bạn có thể sử dụng hàm tạo strptime của lớp datetime:

>>> from datetime import datetime
>>> datetime.strptime("2010-06-04 21:08:12", "%Y-%m-%d %H:%M:%S")
datetime.datetime(2010, 6, 4, 21, 8, 12)

Mạnh mẽ nhất là mô-đun mxDateTime của Egenix:

>>> from mx.DateTime.ISO import ParseDateTimeUTC
>>> from datetime import datetime
>>> x = ParseDateTimeUTC("2010-06-04 21:08:12")
>>> datetime.fromtimestamp(x)
datetime.datetime(2010, 3, 6, 21, 8, 12)

Người giới thiệu


2
Theo nghĩa nào thì nó "mạnh mẽ hơn"?
Stéphane

Ngày:2018-05-25
loxaxs

Ngày và giờ kết hợp trong UTC:2018-05-25T12:16:14+00:00
loxaxs

2
Ngày và giờ kết hợp trong UTC:2018-05-25T12:16:14Z
loxaxs

Ngày và giờ kết hợp trong UTC:20180525T121614Z
loxaxs

49

Tôi tìm thấy datetime.isoformat trong tài liệu . Nó dường như làm những gì bạn muốn:

datetime.isoformat([sep])

Return a string representing the date and time in ISO 8601 format, YYYY-MM-DDTHH:MM:SS.mmmmmm or, if microsecond is 0, YYYY-MM-DDTHH:MM:SS

If utcoffset() does not return None, a 6-character string is appended, giving the UTC offset in (signed) hours and minutes: YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM or, if microsecond is 0 YYYY-MM-DDTHH:MM:SS+HH:MM

The optional argument sep (default 'T') is a one-character separator, placed between the date and time portions of the result. For example,
>>>

>>> from datetime import tzinfo, timedelta, datetime
>>> class TZ(tzinfo):
...     def utcoffset(self, dt): return timedelta(minutes=-399)
...
>>> datetime(2002, 12, 25, tzinfo=TZ()).isoformat(' ')
'2002-12-25 00:00:00-06:39'

30

ISO 8601 cho phép biểu diễn nhỏ gọn không có dấu phân cách ngoại trừ T, vì vậy tôi muốn sử dụng lớp lót này để có được chuỗi dấu thời gian nhanh:

>>> datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%S.%fZ")
'20180905T140903.591680Z'

Nếu bạn không cần micrô giây, chỉ cần bỏ qua .%fphần:

>>> datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
'20180905T140903Z'

Đối với giờ địa phương:

>>> datetime.datetime.now().strftime("%Y%m%dT%H%M%S")
'20180905T140903'

Biên tập:

Sau khi đọc thêm về điều này, tôi khuyên bạn nên để lại dấu câu. RFC 3339 khuyến nghị kiểu đó bởi vì nếu mọi người sử dụng dấu câu, sẽ không có nguy cơ những thứ như nhiều chuỗi ISO 8601 được sắp xếp theo nhóm theo dấu câu. Vì vậy, một lớp lót cho một chuỗi tuân thủ sẽ là:

>>> datetime.datetime.now().strftime("%Y-%m-%dT%H:%M%SZ")
'2018-09-05T14:09:03Z'

3
Có cách nào để giới hạn các chữ số của mili giây đến 3 không? tức là ứng dụng javascript khác của tôi sẽ sản xuất 2019-02-23T04:02:04.051Zvớinew Date().toISOString()
Miranda

19

Các định dạng thời gian ISO 8601 không lưu trữ một tên múi giờ, chỉ có UTC tương ứng bù đắp được bảo tồn.

Để chuyển đổi thời gian tập tin thành chuỗi thời gian ISO 8601 trong khi duy trì bù UTC trong Python 3:

>>> import os
>>> from datetime import datetime, timezone
>>> ts = os.path.getctime(some_file)
>>> dt = datetime.fromtimestamp(ts, timezone.utc)
>>> dt.astimezone().isoformat()
'2015-11-27T00:29:06.839600-05:00'

Mã giả định rằng múi giờ địa phương của bạn là Múi giờ miền đông (ET) và hệ thống của bạn cung cấp bù UTC chính xác cho dấu thời gian POSIX đã cho (ts ), tức là Python có quyền truy cập vào cơ sở dữ liệu múi giờ lịch sử trên hệ thống của bạn hoặc múi giờ có quy tắc tương tự tại một ngày nhất định.

Nếu bạn cần một giải pháp di động; sử dụng pytzmô-đun cung cấp quyền truy cập vào cơ sở dữ liệu tz :

>>> import os
>>> from datetime import datetime
>>> import pytz  # pip install pytz
>>> ts = os.path.getctime(some_file)
>>> dt = datetime.fromtimestamp(ts, pytz.timezone('America/New_York'))
>>> dt.isoformat()
'2015-11-27T00:29:06.839600-05:00'

Kết quả là giống nhau trong trường hợp này.

Nếu bạn cần tên múi giờ / chữ viết tắt / id vùng, hãy lưu trữ riêng.

>>> dt.astimezone().strftime('%Y-%m-%d %H:%M:%S%z (%Z)')
'2015-11-27 00:29:06-0500 (EST)'

Lưu ý: không, :trong phần bù UTC và ESTchữ viết tắt múi giờ không phải là một phần của định dạng thời gian ISO 8601. Nó không phải là duy nhất.

Các thư viện khác nhau / các phiên bản khác nhau của cùng một thư viện có thể sử dụng các quy tắc múi giờ khác nhau cho cùng một ngày / múi giờ. Nếu đó là một ngày trong tương lai thì các quy tắc có thể chưa được biết. Nói cách khác, thời gian tính theo giờ UTC tương tự có thể tương ứng với một giờ địa phương khác nhau tùy thuộc vào những gì bạn sử dụng quy tắc - tiết kiệm thời gian trong định dạng ISO 8601 mứt UTC thời gian và thời gian địa phương tương ứng với hiện tại quy định múi giờ được sử dụng trên nền tảng của bạn . Bạn có thể cần tính toán lại giờ địa phương trên một nền tảng khác nếu nó có các quy tắc khác nhau.


14

Bạn sẽ cần sử dụng os.statđể có được thời gian tạo tệp và kết hợp time.strftimetime.timezoneđịnh dạng:

>>> import time
>>> import os
>>> t = os.stat('C:/Path/To/File.txt').st_ctime
>>> t = time.localtime(t)
>>> formatted = time.strftime('%Y-%m-%d %H:%M:%S', t)
>>> tz = str.format('{0:+06.2f}', float(time.timezone) / 3600)
>>> final = formatted + tz
>>> 
>>> final
'2008-11-24 14:46:08-02.00'

Liệu múi giờ chiếm thời gian tiết kiệm ánh sáng ban ngày? Có vẻ như tz sẽ giống nhau bất kể thời gian tiết kiệm ánh sáng ban ngày hay không.
Joseph Turian

2
Nó sẽ là bất cứ điều gì bù đắp hiện đang có hiệu lực. Nếu DST hoạt động, nó sẽ có phần bù khác với khi DST không hoạt động.
Tối đa Shawabkeh

4

Sửa lỗi cho tôi nếu tôi sai (tôi không), nhưng phần bù từ UTC thay đổi theo thời gian tiết kiệm ánh sáng ban ngày. Vì vậy, bạn nên sử dụng

tz = str.format('{0:+06.2f}', float(time.altzone) / 3600)

Tôi cũng tin rằng dấu hiệu phải khác nhau:

tz = str.format('{0:+06.2f}', -float(time.altzone) / 3600)

Tôi có thể sai, nhưng tôi không nghĩ vậy.


2

Tôi đồng ý với Jarek và tôi cũng lưu ý rằng ký tự phân tách bù ISO là dấu hai chấm, vì vậy tôi nghĩ câu trả lời cuối cùng phải là:

isodate.datetime_isoformat(datetime.datetime.now()) + str.format('{0:+06.2f}', -float(time.timezone) / 3600).replace('.', ':')

2

Thêm một biến thể nhỏ vào câu trả lời tuyệt vời của estani

Cục bộ theo ISO 8601 với TimeZone và không có thông tin micro giây (Python 3):

import datetime, time

utc_offset_sec = time.altzone if time.localtime().tm_isdst else time.timezone
utc_offset = datetime.timedelta(seconds=-utc_offset_sec)
datetime.datetime.now().replace(microsecond=0, tzinfo=datetime.timezone(offset=utc_offset)).isoformat()

Đầu ra mẫu:

'2019-11-06T12:12:06-08:00'

Đã kiểm tra rằng đầu ra này có thể được phân tích cú pháp bằng cả Javascript Datevà C # DateTime/DateTimeOffset


1

Tôi đã phát triển chức năng này:

def iso_8601_format(dt):
    """YYYY-MM-DDThh:mm:ssTZD (1997-07-16T19:20:30-03:00)"""

    if dt is None:
        return ""

    fmt_datetime = dt.strftime('%Y-%m-%dT%H:%M:%S')
    tz = dt.utcoffset()
    if tz is None:
        fmt_timezone = "+00:00"
    else:
        fmt_timezone = str.format('{0:+06.2f}', float(tz.total_seconds() / 3600))

    return fmt_datetime + fmt_timezone

-6
import datetime, time    
def convert_enddate_to_seconds(self, ts):
    """Takes ISO 8601 format(string) and converts into epoch time."""
     dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+\
                datetime.timedelta(hours=int(ts[-5:-3]),
                minutes=int(ts[-2:]))*int(ts[-6:-5]+'1')
    seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0
    return seconds 

>>> import datetime, time
>>> ts = '2012-09-30T15:31:50.262-08:00'
>>> dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+ datetime.timedelta(hours=int(ts[-5:-3]), minutes=int(ts[-2:]))*int(ts[-6:-5]+'1')
>>> seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0
>>> seconds
1348990310.26
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.