Converteer datetime naar Unix-tijdstempel en converteer het terug naar python

Ik heb dt = datetime(2013,9,1,11)en ik wil graag een Unix-tijdstempel van dit datetime-object.

Als ik (dt - datetime(1970,1,1)).total_seconds()doe, krijg ik de tijdstempel 1378033200.

Bij het terug converteren met datetime.fromtimestampkreeg ik datetime.datetime(2013, 9, 1, 6, 0).

Het uur komt niet overeen. Wat heb ik hier gemist?


Antwoord 1, autoriteit 100%

Wat je hier hebt gemist, zijn tijdzones.

Vermoedelijk heb je vijf uur vrij van UTC, dus 2013-09-01T11:00:00 lokaal en 2013-09-01T06:00:00Z zijn dezelfde tijd.

U moet de bovenkant van de datetime-documenten lezen, die uitleg over tijdzones en “naïeve” en “bewuste” objecten.

Als uw oorspronkelijke naïeve datetime UTC was, kunt u deze herstellen door utcfromtimestampin plaats van fromtimestamp.

Aan de andere kant, als je oorspronkelijke naïeve datetime lokaal was, had je er in de eerste plaats geen UTC-tijdstempel van moeten aftrekken; gebruik in plaats daarvan datetime.fromtimestamp(0).

Of, als je een bewust datetime-object had, moet je ofwel een lokaal (bewust) tijdperk aan beide kanten gebruiken, of expliciet converteren van en naar UTC.

Als u hebt, of kunt upgraden naar, Python 3.3 of hoger, kunt u al deze problemen vermijden door gewoon de timestampmethode in plaats van te proberen erachter te komen hoe het zelf te doen. En zelfs als je dat niet doet, wil je misschien zijn broncode .

(en als u op Python kunt wachten 3.4, ziet het eruit als PEP 341 waarschijnlijk Maak het in de laatste release, wat betekent dat alle dingen JF Sebastian en ik het over hadden in de opmerkingen, zou met alleen de stdlib te doen, en op dezelfde manier werken op zowel Unix als Windows.)


Antwoord 2, Autoriteit 124%

oplossing is

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

Antwoord 3, Autoriteit 87%

Als u een Python Datetime naar seconden wilt converteren sinds Epoch u dit expliciet moet doen:

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

In Python 3.3+ kunt u timestamp()in plaats daarvan:

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

Antwoord 4, Autoriteit 43%

In plaats van deze uitdrukking om een POSIX-tijdstempel te maken van dt,

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

Gebruik dit:

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

Ik krijg het juiste antwoord in uw voorbeeld met de tweede methode.

EDIT: Wat vervolg… Na wat opmerkingen (zie hieronder), was ik benieuwd naar het gebrek aan ondersteuning of documentatie voor %sin strftime. Dit is wat ik heb gevonden:

In de Python-bronvoor datetimeen time, de string STRFTIME_FORMAT_CODESvertelt ons:

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

Dus als we nu man strftime(op BSD-systemen zoals Mac OS X), zul je ondersteuning vinden voor %s:

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

Hoe dan ook, daarom werkt %sop de systemen die het doet. Maar er zijn betere oplossingen voor het probleem van OP (die rekening houden met tijdzones). Bekijk hier het geaccepteerde antwoord van @abarnert.


Antwoord 5, autoriteit 9%

Voor het werken met UTC-tijdzones:

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

Antwoord 6, autoriteit 5%

Je hebt de tijdzone-info gemist (reeds beantwoord, akkoord)

arrow-pakketmaakt het mogelijk om deze marteling met datetimes; Het is al geschreven, getest, pypi-gepubliceerd, cross-python (2.6 – 3.xx).

Alles wat je nodig hebt: pip install arrow(of toevoegen aan afhankelijkheden)

Oplossing voor uw zaak

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'

Antwoord 7, autoriteit 5%

Als uw datetime-object UTC-tijd vertegenwoordigt, gebruik dan geen time.mktime, omdat het ervan uitgaat dat de tuple zich in uw lokale tijdzone bevindt. Gebruik in plaats daarvan calendar.timegm:

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

Antwoord 8, autoriteit 2%

Nou, bij het converteren naar een unix-tijdstempel gaat python in feite uit van UTC, maar bij het terug converteren krijg je een datum die is geconverteerd naar je lokale tijdzone.

Zie deze vraag/antwoord;
Tijdzone ophalen die wordt gebruikt door datetime.datetime.fromtimestamp()


Antwoord 9, autoriteit 2%

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

Antwoord 10

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)

Als u een UTC-tijdstempel wilt:time.mktimealleen voor lokaaldt. Gebruik calendar.timegmis veilig, maar dt moet de utc-zone zijn dus verander de zone naar utc. Als dt in UTC is, gebruik dan gewoon calendar.timegm.


Antwoord 11

Deze klasse zal aan uw behoeften voldoen, u kunt de variabele doorgeven aan ConvertUnixToDatetime & roep op welke functie je wilt dat het werkt.

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

Other episodes