Chuyển đổi datetime sang dấu thời gian Unix và chuyển đổi lại bằng python


186

Tôi có dt = datetime(2013,9,1,11), và tôi muốn có một dấu thời gian Unix của đối tượng datetime này.

Khi tôi làm (dt - datetime(1970,1,1)).total_seconds()tôi có dấu thời gian 1378033200.

Khi chuyển đổi nó trở lại bằng cách sử dụng datetime.fromtimestamptôi đã nhận datetime.datetime(2013, 9, 1, 6, 0).

Giờ không khớp. Tôi đã bỏ lỡ điều gì ở đây?



1
Như một lưu ý phụ, nếu bạn đang sử dụng Python 3.3+, bạn thực sự, thực sự muốn sử dụng timestampphương thức thay vì cố gắng tự làm. Đối với một điều, điều đó hoàn toàn tránh được khả năng trừ đi thời gian ngây thơ từ các múi giờ khác nhau.
abarnert

1
Nơi nào dtđến từ đâu? Đó là một giờ địa phương hoặc thời gian trong UTC?
jfs

2
@abarnert Tôi cũng muốn gửi yêu cầu thanh lọc tất cả các bảng mã và ký hiệu unicode, nghĩa là, ngoài vòng pháp luật tất cả các ngôn ngữ không phải mã ascii và không mặc định. Tranh của các biểu tượng vẫn được cho phép.
Daniel F

6
@DanielF: Yêu cầu bị từ chối. Tôi không quan tâm đến việc tạo ra một ngôn ngữ một thế giới ở đây, và ngay cả khi chúng tôi không muốn làm cho cuộc sống không thể đối với các nhà ngôn ngữ học lịch sử và các học giả Tolkien. Unicode đã giải quyết được vấn đề, ngoại trừ một số tổ chức và sản phẩm nhất định (tập đoàn TRON, phần mềm Nhật Bản sử dụng Shift-JIS trên UTF-8, Microsoft vẫn cung cấp HĐH mặc định cho cp1252 cho các tệp văn bản của người dùng và nhiều SDK khác nhau giả vờ rằng UTF -16 là một bộ ký tự có chiều rộng cố định và / hoặc tương tự như Unicode) cần phải bị trừng phạt để đưa chúng vào hàng.
abarnert

Câu trả lời:


105

Những gì bạn đã bỏ lỡ ở đây là múi giờ.

Có lẽ bạn đã nghỉ năm giờ UTC, vì vậy 2013-09-01T11: 00: 00 địa phương và 2013-09-01T06: 00: 00Z là cùng một lúc.

Bạn cần đọc phần trên cùng của datetimetài liệu, trong đó giải thích về múi giờ và các đối tượng "ngây thơ" và "nhận thức".

Nếu datetime ngây thơ ban đầu của bạn là UTC, cách để phục hồi nó là sử dụng utcfromtimestampthay vì fromtimestamp.

Mặt khác, nếu datetime ngây thơ ban đầu của bạn là cục bộ, bạn không nên trừ dấu thời gian UTC khỏi nó ở vị trí đầu tiên; sử dụng datetime.fromtimestamp(0)thay thế.

Hoặc, nếu bạn đã có một đối tượng datetime nhận thức, bạn cần sử dụng một epoch cục bộ (nhận biết) ở cả hai bên, hoặc chuyển đổi rõ ràng sang và từ UTC.

Nếu bạn có, hoặc có thể nâng cấp lên, Python 3.3 trở lên, bạn có thể tránh tất cả các vấn đề này bằng cách chỉ sử dụng timestampphương pháp thay vì cố gắng tìm ra cách tự làm. Và ngay cả khi bạn không, bạn có thể muốn xem xét việc mượn mã nguồn của nó .

(Và nếu bạn có thể chờ cho Python 3.4, có vẻ như PEP 341 có khả năng để làm cho nó vào việc phát hành chính thức, có nghĩa là tất cả những thứ JF Sebastian và tôi đã nói về trong các ý kiến nên được doable chỉ với stdlib, và hoạt động theo cùng một cách trên cả Unix và Windows.)


1
nếu dtlà trong múi giờ địa phương thì công thức trong câu hỏi không chính xác datetime.fromtimestamp(0)(epoch trong múi giờ hiện tại) nên được sử dụng thay vì datetime(1970, 1,1)(unix epoch trong UTC).
jfs

@JFSebastian: Tôi không muốn đề cập chi tiết đến cả ba khả năng, nhưng tôi đoán bạn đúng, tôi nên làm vậy.
abarnert

btw, fromtimestamp(0)có thể thất bại nếu hệ thống không lưu trữ thông tin múi giờ lịch sử, ví dụ như trên Windows. pytzcó thể được sử dụng trong trường hợp này.
jfs

@JFSebastian: Nhưng pytzkhông giúp được gì trừ khi bạn biết bạn đang ở múi giờ nào; để thực hiện việc đó theo chương trình, bạn cần một thư viện khác lấy múi giờ Windows hiện tại và chuyển đổi nó thành pytzmúi giờ và / hoặc tìm kiếm theo tên.
abarnert

tzlocalmô-đun cũng hoạt động trên Windows. Đây là cách bạn có thể chuyển đổi thời gian utc sang giờ địa phương .
jfs

141

giải pháp là

import time
import datetime
d = datetime.date(2015,1,5)

unixtime = time.mktime(d.timetuple())

12
nó giả định rằng đó dlà một đối tượng ngày / thời gian ngây thơ đại diện cho giờ địa phương (nó có thể thất bại trong thời gian mơ hồ hoặc cho những ngày trong quá khứ / tương lai nếu HĐH không cung cấp db tz lịch sử (bù đắp UTC có thể khác trước đây Múi giờ)). Nhiều lựa chọn hơn .
JFS

6
Hình như không ai bận tâm đến giải pháp điểm nổi. Đó là điều hiển nhiên cho tất cả mọi người?
Ivan Balashov

4
Điều này giảm micro giây. Có thể thú vị.
Alfe

Vấn đề duy nhất là bạn không tính đến múi giờ.
Blairg23

nó không nên Nếu bạn cần điều chỉnh TZ, bạn cần làm điều đó trước.
Marcin Orleansowski

69

Nếu bạn muốn chuyển đổi một datetime python thành giây kể từ epoch, bạn nên làm điều đó một cách rõ ràng:

>>> import datetime
>>> datetime.datetime(2012,04,01,0,0).strftime('%s')
'1333234800'
>>> (datetime.datetime(2012,04,01,0,0) - datetime.datetime(1970,1,1)).total_seconds()
1333238400.0

Trong Python 3.3+, bạn có thể sử dụng timestamp()thay thế:

>>> import datetime
>>> datetime.datetime(2012,4,1,0,0).timestamp()
1333234800.0

5
Không tính thời gian vào tài khoản.
Blairg23

3
Bạn không muốn sử dụng %s, vì nó sẽ được bản địa hóa theo đồng hồ của hệ thống bạn hiện đang sử dụng. Bạn chỉ nên sử dụng .timestamp()để có được thời gian Epoch / UNIX chính xác.
Blairg23

3
%skhông hoạt động trên các hệ thống Windows ( ValueError: Invalid format string)
chrki

1
@ amitnair92 chỉ cần đặt 8hoặc9
Francisco Costa

54

Thay vì biểu thức này để tạo dấu thời gian POSIX từ dt,

(dt - datetime(1970,1,1)).total_seconds()

Dùng cái này:

int(dt.strftime("%s"))

Tôi nhận được câu trả lời đúng trong ví dụ của bạn bằng phương pháp thứ hai.

EDIT: Một số followup ... Sau khi một số ý kiến (xem dưới đây), tôi đã tò mò về việc thiếu hỗ trợ hoặc tài liệu cho %strong strftime. Đây là những gì tôi tìm thấy:

Trong nguồn Python cho datetimetime, chuỗi STRFTIME_FORMAT_CODEScho chúng ta biết:

"Other codes may be available on your platform.
 See documentation for the C library strftime function."

Vì vậy, bây giờ nếu chúng tôi man strftime(trên các hệ thống BSD như Mac OS X), bạn sẽ tìm thấy hỗ trợ cho %s:

"%s is replaced by the number of seconds since the Epoch, UTC (see mktime(3))."

Dù sao, đó là lý do tại sao %shoạt động trên các hệ thống nó làm. Nhưng có những giải pháp tốt hơn cho vấn đề của OP (tính đến các múi giờ). Xem câu trả lời được chấp nhận của @ abarnert tại đây.


4
Đây là hành vi không có giấy tờ (tôi tin). Ví dụ: trên windows, nó dẫn đến "Chuỗi định dạng không hợp lệ".
Lưỡi liềm tươi

@CrescentFresh, thú vị. Bạn có thể đúng. Mặc dù tôi không thấy strftime("%s")trong tài liệu, tôi chỉ xác nhận điều này để hoạt động trên Mac và Linux. Cảm ơn.
Darren Stone

1
hình như nó bỏ qua trường tzinfo.
Daniel F

1
@DarrenStone: bạn không cần phải đọc nguồn. Cả hai time.strftime()datetime.strftimetài liệu ủy quyền cho strftime(3)chức năng nền tảng cho các chỉ thị không được hỗ trợ. %scó thể thất bại ngay cả trên Mac OS X, ví dụ: datetime.strftime ('% s') nên tôn trọng tzinfo .
JFS

1
Bạn không bao giờ nên sử dụng %svì bạn sẽ chỉ sử dụng thời gian hệ thống cục bộ của hệ thống bạn đang bật. Bạn muốn sử dụng .timestamp()nếu bạn đang cố lấy dấu thời gian UNIX thực.
Blairg23

6

Để làm việc với các múi giờ UTC:

time_stamp = calendar.timegm(dt.timetuple())

datetime.utcfromtimestamp(time_stamp)

Sau một giờ tìm kiếm, đây là câu trả lời duy nhất có hiệu quả: ')
Qurashi

4

Bạn đã bỏ lỡ thông tin múi giờ (đã trả lời, đồng ý)

arrowgói cho phép để tránh sự tra tấn này với datetimes; Nó đã được viết, thử nghiệm, xuất bản pypi, chéo python (2.6 - 3.xx).

Tất cả bạn cần: pip install arrow(hoặc thêm vào phụ thuộc)

Giải pháp cho trường hợp của bạn

dt = datetime(2013,9,1,11)
arrow.get(dt).timestamp
# >>> 1378033200

bc = arrow.get(1378033200).datetime
print(bc)
# >>> datetime.datetime(2013, 9, 1, 11, 0, tzinfo=tzutc())
print(bc.isoformat())
# >>> '2013-09-01T11:00:00+00:00'

3

Nếu đối tượng datetime của bạn đại diện cho thời gian UTC, đừng sử dụng time.mktime, vì nó giả sử bộ dữ liệu nằm trong múi giờ địa phương của bạn. Thay vào đó, hãy sử dụng calendar.timegm:

>>> import datetime, calendar
>>> d = datetime.datetime(1970, 1, 1, 0, 1, 0)
>>> calendar.timegm(d.timetuple())
60


1
def dt2ts(dt, utc=False):
    if utc:
        return calendar.timegm(dt.timetuple())
    if dt.tzinfo is None:
        return int(time.mktime(dt.timetuple()))
    utc_dt = dt.astimezone(tz.tzutc()).timetuple()
    return calendar.timegm(utc_dt)

Nếu bạn muốn dấu thời gian UTC: time.mktimechỉ dành cho dt cục bộ . Sử dụng calendar.timegman toàn nhưng dt phải vùng utc vì vậy hãy thay đổi vùng thành utc. Nếu dt trong UTC chỉ cần sử dụng calendar.timegm.


1
def datetime_to_epoch(d1):

    # create 1,1,1970 in same timezone as d1
    d2 = datetime(1970, 1, 1, tzinfo=d1.tzinfo)
    time_delta = d1 - d2
    ts = int(time_delta.total_seconds())
    return ts


def epoch_to_datetime_string(ts, tz_name="UTC"):
    x_timezone = timezone(tz_name)
    d1 = datetime.fromtimestamp(ts, x_timezone)
    x = d1.strftime("%d %B %Y %H:%M:%S")
    return x

0

Lớp này sẽ đáp ứng nhu cầu của bạn, bạn có thể chuyển biến vào ConvertUnixToDatetime & gọi hàm nào bạn muốn nó hoạt động dựa trên tắt.

from datetime import datetime
import time

class ConvertUnixToDatetime:
    def __init__(self, date):
        self.date = date

    # Convert unix to date object
    def convert_unix(self):
        unix = self.date

        # Check if unix is a string or int & proceeds with correct conversion
        if type(unix).__name__ == 'str':
            unix = int(unix[0:10])
        else:
            unix = int(str(unix)[0:10])

        date = datetime.utcfromtimestamp(unix).strftime('%Y-%m-%d %H:%M:%S')

        return date

    # Convert date to unix object
    def convert_date(self):
        date = self.date

        # Check if datetime object or raise ValueError
        if type(date).__name__ == 'datetime':
            unixtime = int(time.mktime(date.timetuple()))
        else:
            raise ValueError('You are trying to pass a None Datetime object')
        return type(unixtime).__name__, unixtime


if __name__ == '__main__':

    # Test Date
    date_test = ConvertUnixToDatetime(datetime.today())
    date_test = date_test.convert_date()
    print(date_test)

    # Test Unix
    unix_test = ConvertUnixToDatetime(date_test[1])
    print(unix_test.convert_unix())
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.