Tarih saatini Unix zaman damgasına ve python'a dönüştür


186

Ben var dt = datetime(2013,9,1,11)ve bu datetime nesnesinin bir Unix zaman damgası almak istiyorum.

Yaptığımda (dt - datetime(1970,1,1)).total_seconds()zaman damgasını aldım1378033200 .

Kullanarak geri dönüştürürken datetime.fromtimestampvardatetime.datetime(2013, 9, 1, 6, 0) .

Saat uyuşmuyor. Burada ne kaçırdım?



1
Bir yan not olarak, Python 3.3+ kullanıyorsanız, timestampyöntemi kendiniz yapmaya çalışmak yerine gerçekten kullanmak istersiniz . Bir kere, bu, farklı zaman dilimlerinden saf zamanların çıkarılması olasılığını tamamen önler.
abarnert

1
Nereden dtgeliyor? UTC'de yerel bir saat veya saat mi?
jfs

2
@abarnert Ayrıca tüm kod sayfalarını ve unicode sembollerini temizlemek, yani tüm ascii olmayan ve varsayılan olmayan kod sayfası dillerini yasaklamak için bir istek göndermek istiyorum. Sembollerin resimlerine hala izin verilmektedir.
Daniel F

6
@DanielF: İstek reddedildi. Burada tek dünya dili oluşturmakla ilgilenmiyorum ve yapsak bile tarihi dilbilimciler ve Tolkien alimleri için hayatı imkansız hale getirmek istemem. Unicode sorunu zaten çözüyor, ancak belirli kuruluşlar ve ürünler (TRON konsorsiyumu, UTF-8 üzerinde Shift-JIS kullanan Japon yazılımı, Microsoft hala kullanıcı metin dosyaları için cp1252 varsayılanı olan bir işletim sistemi ve bu UTF gibi davranan çeşitli SDK'lar sağlıyor -16 sabit genişlikli bir karakter setidir ve / veya Unicode ile aynı şeydir) bunları sıraya koymak için cezalandırılması gerekir.
abarnert

Yanıtlar:


106

Burada kaçırdığınız şey zaman dilimleri.

Muhtemelen UTC'den beş saat uzaktasınız, bu nedenle 2013-09-01T11: 00: 00 yerel ve 2013-09-01T06: 00: 00Z aynı saattir.

Üst kısmını okumalısın datetime dilimlerini ve "naif" ve "farkında" nesneleri açıklayan dokümanların .

Orijinal naif tarih saatiniz UTC ise, onu kurtarmanın yolu utcfromtimestampyerinefromtimestamp .

Öte yandan, orijinal naif tarih saatiniz yerel ise, ilk etapta bir UTC zaman damgası çıkarmamalısınız; kullanımdatetime.fromtimestamp(0) .

Ya da, farkında bir datetime nesneniz varsa, her iki tarafta da yerel (farkında) bir dönem kullanmanız veya açıkça UTC'ye ve UTC'den dönüştürmeniz gerekir.

Python 3.3 veya sonraki bir sürümüne sahipseniz veya bu sürüme yükseltebiliyorsanız, bunu timestampnasıl yapacağınızı anlamaya çalışmak yerine yalnızca yöntemi kullanarak tüm bu sorunlardan kaçınabilirsiniz . Ve yapmasanız bile , kaynak kodunu ödünç almayı düşünebilirsiniz .

(Ve Python 3.4 için bekleyebilirseniz, PEP 341'in son sürüme girmesi muhtemel görünüyor , bu da JF Sebastian ve ben yorumlarda bahsettiğim tüm şeylerin sadece stdlib ile yapılabileceği anlamına geliyor ve hem Unix hem de Windows'da aynı şekilde çalışıyor.)


1
Eğer dtyerel saat diliminde o zaman, söz konusu formül yanlış datetime.fromtimestamp(0)yerine kullanılması gereken (mevcut saat diliminde dönemi) datetime(1970, 1,1)(UTC Unix Zaman).
jfs

@JFSebastian: Üç olasılığın hepsini ayrıntılı olarak ele almak istemedim, ama sanırım haklısın, yapmalıyım.
abarnert

btw, fromtimestamp(0)sistem geçmiş saat dilimi bilgilerini örneğin Windows'ta depolamazsa başarısız olabilir. pytzbu durumda kullanılabilir.
jfs

@JFSebastian: Ancak pytzhangi saat diliminde olduğunuzu bilmiyorsanız yardımcı olmaz; bunu programlı olarak yapmak için, geçerli Windows saat dilimini alan ve bir pytzsaat dilimine dönüştüren ve / veya adıyla arayan farklı bir kitaplığa ihtiyacınız vardır .
abarnert

orada tzlocalda Windows üzerinde çalışır modülü. Utc zamanını yerel saate nasıl dönüştürebileceğiniz aşağıda açıklanmıştır .
jfs

141

çözüm

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

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

12
dyerel saati temsil eden naif bir tarih / datetime nesnesi olduğunu varsayar (işletim sistemi tarihsel bir tz db sağlamazsa belirsiz saatler veya geçmiş / gelecek tarihler için başarısız olabilir (UTC ofseti yerelde geçmişte farklı olabilir) saat dilimi)). Daha fazla seçenek .
jfs

6
Kimsenin kayan nokta çözümünü düşünmediği anlaşılıyor. Herkes için bu kadar açık mı?
Ivan Balashov

4
Bu mikrosaniye düşer. İlginç olabilir.
Alfe

Tek sorun, saat dilimini dikkate almamanızdır.
Blairg23

olmamalı. TZ'yi ayarlamanız gerekiyorsa, önce bunu yapmanız gerekir.
Marcin Orlowski

69

Dönemden beri bir python tarih saatini saniyeye dönüştürmek istiyorsanız, bunu açıkça yapmalısınız:

>>> 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+ sürümünde şunları kullanabilirsiniz timestamp():

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

5
Zaman dilimlerini dikkate almaz.
Blairg23

3
Şu %sanda bulunduğunuz sistemin saatine göre yerelleştirileceği için kullanmak istemezsiniz . Sadece .timestamp()doğru Epoch / UNIX saatini almak için kullanmalısınız .
Blairg23

3
%sWindows sistemlerinde çalışmaz ( ValueError: Invalid format string)
chrki

1
@ amitnair92 just put 8or9
Francisco Costa

54

Bu ifadeden POSIX zaman damgası oluşturmak yerine dt,

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

Bunu kullan:

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

İkinci yöntemi kullanarak örneğinizde doğru cevabı alıyorum.

DÜZENLEME: Bazı takip ... bazı yorumlar (aşağıya bakınız), ben destek veya belgelerin eksikliği konusunda meraklı sonra %siçinde strftime. İşte bulduğum:

In Python kaynağı için datetimeve timedize STRFTIME_FORMAT_CODESsöyler:

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

Yani şimdi man strftime(Mac OS X gibi BSD sistemlerinde), aşağıdakiler için destek bulacaksınız %s:

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

Her neyse, bu yüzden %syaptığı sistemler üzerinde çalışıyor. Ancak OP'nin sorununa daha iyi çözümler var (zaman dilimleri hesaba katılıyor). @ Abarnert'ın kabul edilen cevabına buradan bakın.


4
Bu belgesiz davranış (inanıyorum). Örneğin pencerelerde "Geçersiz biçim dizesi" ile sonuçlanır.
Crescent Fresh

@CrescentFresh, ilginç. Haklı olabilirsin. Ben görmüyorum iken strftime("%s")belgelerinde, sadece Mac ve Linux üzerinde çalışması için bu teyit etmedi. Teşekkürler.
Darren Stone

1
görünüşe göre tzinfo alanını yok sayar.
Daniel F

1
@DarrenStone: kaynağı okumanıza gerek yok. Hem time.strftime()ve datetime.strftimeplatformlara dokümantasyon temsilci strftime(3)desteklenmeyen direktifleri için çalışır. %sMac OS X'te bile başarısız olabilir, örn. datetime.strftime ('% s') tzinfo'ya saygı göstermelidir .
jfs

1
Asla kullanmamalısınız, %sçünkü yalnızca bulunduğunuz sistemin yerelleştirilmiş sistem saatini kullanırsınız. .timestamp()Gerçek UNIX zaman damgasını almaya çalışıyorsanız kullanmak istiyorsunuz.
Blairg23

6

UTC saat dilimleriyle çalışmak için:

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

datetime.utcfromtimestamp(time_stamp)

Bir saatlik aramadan sonra, işe yarayan tek cevap
buydu

4

Saat dilimi bilgilerini kaçırdınız (zaten yanıtlandı, kabul edildi)

arrowpaket , bu işkenceyi tarihlerle önlemek için izin verir; Zaten yazıldı, test edildi, pypi yayınlandı, çapraz python (2.6 - 3.xx).

İhtiyacınız olan her şey: pip install arrow(veya bağımlılıklara ekleyin)

Davanız için çözüm

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

Tarih saat nesneniz UTC saatini temsil ediyorsa, grubun yerel saat diliminizde olduğunu varsaydığı için time.mktime öğesini kullanmayın. Bunun yerine calendar.timegm komutunu kullanın:

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

UTC zaman damgası istiyorsanız: time.mktimesadece yerel dt için kullanın calendar.timegm. UTC'de dt sadece kullanın 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

Bu sınıf ihtiyaçlarınızı karşılayacak, değişkeni ConvertUnixToDatetime'a aktarabilir ve hangi fonksiyonun kapalı olarak çalışmasını istediğinizi çağırabilirsiniz.

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())
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.