แปลงวันที่และเวลาเป็น Unix timestamp และแปลงกลับเป็นไพ ธ อน


186

ฉันมีdt = datetime(2013,9,1,11)และฉันต้องการได้รับการประทับเวลา Unix ของวัตถุวันที่และเวลานี้

เมื่อผมทำผมได้รับการประทับเวลา(dt - datetime(1970,1,1)).total_seconds()1378033200

เมื่อมีการแปลงมันกลับมาใช้ผมได้datetime.fromtimestampdatetime.datetime(2013, 9, 1, 6, 0)

ชั่วโมงไม่ตรงกัน ฉันคิดถึงอะไรที่นี่


2
ที่เกี่ยวข้อง: การแปลง datetime.date เป็นเวลา UTC ใน Python
jfs

1
ตามบันทึกด้านข้างหากคุณใช้ Python 3.3+ คุณต้องการใช้timestampวิธีการแทนการทำด้วยตัวเอง สำหรับสิ่งหนึ่งที่หลีกเลี่ยงความเป็นไปได้ที่จะลบเวลาไร้เดียงสาจากเขตเวลาที่แตกต่างกันโดยสิ้นเชิง
abarnert

1
ในกรณีที่ไม่dtมาจากไหน? มันเป็นเวลาท้องถิ่นหรือเวลาใน UTC?
jfs

2
@abarnert ฉันต้องการส่งคำขอเพื่อล้าง codepages และสัญลักษณ์ยูนิโค้ดทั้งหมดนั่นคือเพื่อห้ามภาษาที่ไม่ใช่ ascii และ non-default-codepage ทั้งหมด ภาพวาดของสัญลักษณ์ยังคงได้รับอนุญาต
Daniel F

6
@DanielF: คำขอถูกปฏิเสธ ฉันไม่สนใจที่จะสร้างภาษาโลกเดียวที่นี่และแม้ว่าเราจะทำฉันก็ไม่อยากทำให้ชีวิตเป็นไปไม่ได้สำหรับนักภาษาศาสตร์เชิงประวัติศาสตร์และนักวิชาการโทลคีน Unicode แก้ปัญหาได้แล้วยกเว้นว่าบางองค์กรและผลิตภัณฑ์ (กลุ่ม TRON, ซอฟต์แวร์ญี่ปุ่นที่ใช้ Shift-JIS มากกว่า UTF-8, Microsoft ยังคงส่งมอบระบบปฏิบัติการที่มีค่าเริ่มต้นเป็น cp1252 สำหรับไฟล์ข้อความผู้ใช้และ SDK ต่างๆที่ทำท่าว่า UTF -16 เป็นชุดอักขระที่มีความกว้างคงที่และ / หรือสิ่งเดียวกันกับ Unicode) จะต้องถูกลงโทษเพื่อนำมาไว้ในบรรทัด
abarnert

คำตอบ:


106

สิ่งที่คุณพลาดได้คือเขตเวลา

สมมุติว่าคุณปิด UTC ห้าชั่วโมงดังนั้น 2013-09-01T11: 00: 00 local และ 2013-09-01T06: 00: 00Z เป็นเวลาเดียวกัน

คุณต้องอ่านส่วนบนของdatetimeเอกสารซึ่งอธิบายเกี่ยวกับเขตเวลาและวัตถุ "ไร้เดียงสา" และ "รับรู้"

หาก datetime ไร้เดียงสาเดิมของคุณเป็นเวลา UTC วิธีการกู้คืนก็คือการใช้แทนutcfromtimestampfromtimestamp

ในทางกลับกันถ้าวันที่ไร้เดียงสาดั้งเดิมของคุณเป็นแบบโลคัลคุณไม่ควรลบเวลาประทับ UTC ออกจากตำแหน่งในตอนแรก ใช้datetime.fromtimestamp(0)แทน

หรือถ้าคุณมีออบเจ็กต์ datetime ที่รู้ตัวคุณต้องใช้ epoch แบบโลคัล (aware) บนทั้งสองด้านหรือแปลงเป็นจาก UTC อย่างชัดเจน

หากคุณมีหรือสามารถอัพเกรดเป็น Python 3.3 หรือใหม่กว่าคุณสามารถหลีกเลี่ยงปัญหาเหล่านี้ได้เพียงแค่ใช้timestampวิธีการแทนการพยายามหาวิธีทำด้วยตัวเอง และยิ่งถ้าคุณทำไม่ได้คุณอาจต้องการที่จะต้องพิจารณาการยืมรหัสแหล่งที่มาของ

(และถ้าคุณสามารถรอ Python 3.4 ดูเหมือนว่าPEP 341มีแนวโน้มที่จะทำให้มันเป็นรุ่นสุดท้ายซึ่งหมายความว่าทุกสิ่งที่เจเอฟเจบาสเตียนและฉันกำลังพูดถึงในความคิดเห็นควรทำได้ด้วย stdlib และ ทำงานในลักษณะเดียวกันกับทั้ง Unix และ Windows)


1
ถ้าdtอยู่ในเขตเวลาท้องถิ่นควรใช้สูตรในคำถามที่ไม่ถูกต้องdatetime.fromtimestamp(0)(epoch ในเขตเวลาปัจจุบัน) แทนที่จะใช้datetime(1970, 1,1)(unix epoch ใน UTC)
jfs

@JFSebastian: ฉันไม่ต้องการให้ครอบคลุมความเป็นไปได้ทั้งสามในรายละเอียด แต่ฉันคิดว่าคุณพูดถูกต้องฉันควร
abarnert

btw fromtimestamp(0)อาจล้มเหลวหากระบบไม่จัดเก็บข้อมูลเขตเวลาในอดีตเช่นบน Windows pytzสามารถใช้ในกรณีนี้
jfs

@JFSebastian: แต่pytzไม่ช่วยถ้าคุณไม่ได้รู้ว่าคุณอยู่ในเขตเวลาใด ในการทำเช่นนั้นโดยทางโปรแกรมคุณต้องมีไลบรารีอื่นที่ได้รับเขตเวลา Windows ปัจจุบันและแปลงเป็นpytzเขตเวลาและ / หรือค้นหาตามชื่อ
abarnert

มีtzlocalโมดูลที่ใช้งานได้บน Windows นี่คือวิธีที่คุณสามารถแปลงเวลา UTC เป็นเวลาท้องถิ่น
jfs

141

ทางออกคือ

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

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

12
มันถือว่าdเป็นวันที่ / ไร้เดียงสาวัตถุวันที่ / เวลาที่แสดงถึงเวลาท้องถิ่น (มันอาจล้มเหลวสำหรับเวลาที่ไม่ชัดเจนหรือสำหรับวันที่ผ่านมา / ในอนาคตหากระบบปฏิบัติการไม่ได้ให้ประวัติ tz db (UTC ชดเชยอาจจะแตกต่างกันในอดีตในท้องถิ่น เขตเวลา)). ตัวเลือกเพิ่มเติม
jfs

6
ดูเหมือนว่าไม่มีใครคิดวิธีแก้ปัญหาจุดลอย ชัดเจนสำหรับทุกคนหรือไม่
Ivan Balashov

4
สิ่งนี้จะลดไมโครวินาที อาจจะน่าสนใจ
Alfe

ปัญหาเดียวก็คือคุณไม่ต้องคำนึงถึงเขตเวลา
Blairg23

มันไม่ควร หากคุณต้องการปรับ TZ คุณต้องทำก่อน
Marcin Orlowski

69

ถ้าคุณต้องการแปลง python datetime เป็นวินาทีตั้งแต่ epoch คุณควรทำอย่างชัดเจน:

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

ใน Python 3.3+ คุณสามารถใช้timestamp()แทน:

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

5
ไม่คำนึงถึงเขตเวลา
Blairg23

3
คุณไม่ต้องการใช้%sเนื่องจากจะแปลเป็นนาฬิกาของระบบที่คุณใช้งานอยู่ คุณควรใช้.timestamp()เพื่อรับเวลา Epoch / UNIX ที่ถูกต้องเท่านั้น
Blairg23 23

3
%sไม่ทำงานบนระบบ Windows ( ValueError: Invalid format string)
chrki

1
@ amitnair92 เพียงแค่ใส่8หรือ9
Francisco Costa

54

แทนที่จะแสดงออกนี้เพื่อสร้างการประทับเวลา POSIX จากdt,

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

ใช้สิ่งนี้:

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

ฉันได้รับคำตอบที่ถูกต้องในตัวอย่างของคุณโดยใช้วิธีที่สอง

แก้ไข: บางคนติดตาม ... หลังจากที่ความคิดเห็นบางส่วน (ดูด้านล่าง) ผมก็อยากรู้เกี่ยวกับการขาดการสนับสนุนหรือเอกสารสำหรับใน%s strftimeนี่คือสิ่งที่ฉันพบ:

ในPython sourceสำหรับdatetimeและtimeสตริงSTRFTIME_FORMAT_CODESบอกเรา:

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

ดังนั้นถ้าเราman strftime(ในระบบ BSD เช่น Mac OS X) คุณจะพบการสนับสนุนสำหรับ%s:

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

อย่างไรก็ตามนั่นเป็นสาเหตุที่%sทำงานบนระบบที่ใช้ แต่มีวิธีแก้ไขปัญหาของ OP ที่ดีกว่า (ซึ่งคำนึงถึงเขตเวลาด้วย) ดูคำตอบที่ยอมรับของ @ abarnert ที่นี่


4
นี่คือพฤติกรรมที่ไม่มีเอกสาร (ฉันเชื่อว่า) ตัวอย่างเช่นใน windows มันส่งผลให้ "สตริงรูปแบบไม่ถูกต้อง"
Crescent Fresh

@CrescentFresh น่าสนใจ คุณอาจจะถูก ในขณะที่ฉันไม่เห็นstrftime("%s")ในเอกสารฉันเพิ่งยืนยันสิ่งนี้เพื่อทำงานบน Mac และ Linux ขอบคุณ
Darren Stone

1
เห็นได้ชัดว่ามันไม่สนใจฟิลด์ tzinfo
Daniel F

1
@DarrenStone: คุณไม่จำเป็นต้องอ่านซอร์ส ทั้งผู้แทนtime.strftime()และdatetime.strftimeผู้แทนเอกสารไปยังstrftime(3)ฟังก์ชันแพลตฟอร์มสำหรับคำสั่งที่ไม่สนับสนุน %sอาจล้มเหลวแม้กระทั่งบน Mac OS X เช่นdatetime.strftime ( '% s') ควรเคารพ tzinfo
jfs

1
คุณไม่ควรใช้%sเนื่องจากคุณจะใช้เวลาของระบบที่แปลเป็นภาษาท้องถิ่นของระบบที่คุณเปิดเท่านั้น คุณต้องการใช้.timestamp()ถ้าคุณพยายามที่จะรับเวลาจริง UNIX
Blairg23

6

สำหรับการทำงานกับเขตเวลา UTC:

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

datetime.utcfromtimestamp(time_stamp)

หลังจากหนึ่งชั่วโมงของการค้นหานี่เป็นคำตอบเดียวที่ใช้ได้: ')
Qurashi

4

คุณพลาดข้อมูลโซนเวลา (ตอบแล้วเห็นด้วย)

arrowแพคเกจช่วยให้หลีกเลี่ยงการทรมานด้วยชุดข้อมูล; มันถูกเขียน, ทดสอบ, ตีพิมพ์ pypi, cross-python (2.6 - 3.xx)

ทั้งหมดที่คุณต้องการ: pip install arrow(หรือเพิ่มการอ้างอิง)

ทางออกสำหรับกรณีของคุณ

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

หากวัตถุ datetime ของคุณแทนเวลา UTC อย่าใช้ time.mktime เนื่องจากถือว่า tuple อยู่ในเขตเวลาท้องถิ่นของคุณ ใช้ calendar.timegm แทน:

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

2

เมื่อทำการแปลงเป็น timestamp ของยูนิกซ์แล้วไพ ธ อนถือว่าเป็น UTC แต่ในขณะที่แปลงกลับมันจะให้วันที่แปลงเป็นเขตเวลาท้องถิ่นของคุณ

ดูคำถาม / คำตอบนี้ รับเขตเวลาที่ใช้โดย datetime.datetime.fromtimestamp ()


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)

ถ้าคุณต้องการ UTC UTC: time.mktimeเฉพาะlocal dt .Use calendar.timegmนั้นปลอดภัย แต่ dt ต้อง utc zone ดังนั้นเปลี่ยน zone เป็น utc หาก dt ใน UTC 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

คลาสนี้จะครอบคลุมความต้องการของคุณคุณสามารถส่งตัวแปรไปยัง ConvertUnixToDatetime และเรียกใช้ฟังก์ชันที่คุณต้องการให้ทำงาน

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())
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.