Python'da datetime ile UTC zaman damgasını alın


83

Tarihi belirterek UTC zaman damgasını almanın bir yolu var mı? Beklediğim şey:

datetime(2008, 1, 1, 0, 0, 0, 0)

sonuçlanmalı

 1199145600

Naif bir datetime nesnesi oluşturmak, saat dilimi bilgisi olmadığı anlamına gelir. Datetime.utcfromtimestamp belgelerine bakarsam, bir UTC zaman damgası oluşturmak, saat dilimi bilgilerini dışarıda bırakmak anlamına gelir. Bu yüzden, saf bir datetime nesnesi oluşturmanın (benim yaptığım gibi) bir UTC zaman damgası ile sonuçlanacağını tahmin ediyorum. Ancak:

then = datetime(2008, 1, 1, 0, 0, 0, 0)
datetime.utcfromtimestamp(float(then.strftime('%s')))

sonuçlanır

2007-12-31 23:00:00

Datetime nesnesinde hala gizli saat dilimi bilgisi var mı? Neyi yanlış yapıyorum?


sorun then.strftime('%s')yerel saati beklemesidir , ancak zaman damgası bunun datetime(2008, 1, 1)UTC'de olduğunu gösterir .
jfs

Yanıtlar:


91

Naif datetimeve farkındadatetime

Varsayılan datetimenesnelerin "naif" olduğu söylenir: zaman bilgisini saat dilimi bilgisi olmadan tutarlar. Naifliği datetime, +4net bir kökeni olmayan göreceli bir sayı (yani :) olarak düşünün (aslında kökeniniz sistem sınırınızda ortak olacaktır).

Aksine, farkındalığı tüm dünya için ortak bir kökene sahip datetimemutlak sayılar (yani :) olarak düşünün 8.

Saat dilimi bilgisi olmadan olamaz olmayan herhangi naif zaman temsilinize datetime "naif" dönüştürmek (yapar +4biz başlangıç olarak bilmiyorsanız hedefler?). Bu yüzden bir datetime.datetime.toutctimestamp()yönteme sahip olamazsın . (cf: http://bugs.python.org/issue1457227 )

datetime dtSaf olup olmadığını kontrol etmek için , kontrol et dt.tzinfo, eğer None, o zaman saf:

datetime.now()        ## DANGER: returns naïve datetime pointing on local time
datetime(1970, 1, 1)  ## returns naïve datetime pointing on user given time

Saf zamanlarım var, ne yapabilirim?

Bağlamınıza bağlı olarak bir varsayımda bulunmalısınız: Kendinize sormanız gereken soru şudur: datetimeUTC'de miydiniz ? yoksa yerel saat miydi?

  • UTC kullanıyorsanız (başınız belada ):

    import calendar
    
    def dt2ts(dt):
        """Converts a datetime object to UTC timestamp
    
        naive datetime will be considered UTC.
    
        """
    
        return calendar.timegm(dt.utctimetuple())
    
  • Eğer UTC KULLANMIYORSAN , cehenneme hoş geldin.

    Sen senin yapmak zorunda datetimekendi amaçlanan dilimini geri vererek, eski işlevini kullanarak olmayan naif önce.

    Şunlar gerekir diliminin adını ve DST yürürlükte olsaydı hakkında bilgi hedef naif başlangıç tarihi (DST hakkında son bilgiler cornercases için gereklidir) üretirken:

    import pytz     ## pip install pytz
    
    mytz = pytz.timezone('Europe/Amsterdam')             ## Set your timezone
    
    dt = mytz.normalize(mytz.localize(dt, is_dst=True))  ## Set is_dst accordingly
    

    Sağlamamanın sonuçları is_dst :

    Kullanmıyor is_dst , geriye doğru bir DST yerleştirilirken hedef tarih saati üretilirse (örneğin, DST saatini bir saati kaldırarak değiştirmek) yanlış zaman (ve UTC zaman damgası) oluşturur.

    Yanlış is_dstirade sağlamak elbette sadece DST çakışması veya boşluklarda yanlış zaman (ve UTC zaman damgası) oluşturur. Ve "deliklerde" meydana gelen yanlış zamanı da sağlarken (DST'nin ileri kayması nedeniyle asla var olmayan zaman), is_dstbu sahte zamanın nasıl dikkate alınacağına dair bir yorum verecektir ve bu, .normalize(..) gerçekten bir şeyler yapacak , çünkü daha sonra bunu gerçek bir geçerli zaman olarak çevirecektir (gerekirse tarih saatini VE DST nesnesini değiştirerek). .normalize()Sonunda doğru bir UTC zaman damgasına sahip olmak için gerekli olmadığını unutmayın , ancak değişkenlerinizde sahte zamanlar olması fikrinden hoşlanmıyorsanız, özellikle de bu değişkeni başka bir yerde yeniden kullanıyorsanız, muhtemelen önerilir.

    ve AŞAĞIDAKİLERİ KULLANMAKTAN KAÇININ : (cf: Pytz kullanarak Tarih Saat Zaman Dilimi dönüşümü )

    dt = dt.replace(tzinfo=timezone('Europe/Amsterdam'))  ## BAD !!
    

    Neden? çünkü hedef zamanı hesaba katmadan .replace()körü körüne değiştirir tzinfove kötü bir DST nesnesi seçer. Oysa doğru DST nesnesini seçmek .localize()için hedef zamanı ve is_dstipucunuzu kullanır .

ESKİ yanlış cevap (bunu gündeme getirdiğin için teşekkürler @ JFSebastien):

İnşallah, naif datetimenesnenizi oluşturduğunuzda saat dilimini (yerel kökeninizi) tahmin etmek oldukça kolaydır çünkü bu, naif datetime nesnesi oluşturma ve elde etmek istediğiniz an arasında DEĞİŞTİRMEYECEĞİNİZ sistem yapılandırmasıyla ilgilidir. UTC zaman damgası. Bu numara, kusurlu bir soru vermek için kullanılabilir .

Kullanarak time.mktimebir oluşturabiliriz utc_mktime:

def utc_mktime(utc_tuple):
    """Returns number of seconds elapsed since epoch

    Note that no timezone are taken into consideration.

    utc tuple must be: (year, month, day, hour, minute, second)

    """

    if len(utc_tuple) == 6:
        utc_tuple += (0, 0, 0)
    return time.mktime(utc_tuple) - time.mktime((1970, 1, 1, 0, 0, 0, 0, 0, 0))

def datetime_to_timestamp(dt):
    """Converts a datetime object to UTC timestamp"""

    return int(utc_mktime(dt.timetuple()))

datetimeNesnenizin, sizin oluşturduğunuz ile aynı saat diliminde oluşturulduğundan emin olmalısınız datetime.

Bu son çözüm yanlıştır çünkü şu andan itibaren UTC sapmasının EPOCH'dan UTC sapması ile aynı olduğunu varsaymaktadır. Pek çok zaman dilimi için durum böyle değildir (Yaz Saati Uygulaması (DST) ofsetleri için yılın belirli bir anında).


4
Saf tarih saat nesnesi, zamanı her zaman UTC olarak temsil etmelidir. Diğer saat dilimleri yalnızca G / Ç (ekran) için kullanılmalıdır. datetime.timestamp()Python 3.3'te yöntem var .
jfs

2
time.mktime()yalnızca yerel saat için kullanılmalıdır. calendar.timegm()utc zaman dizisini posix zaman damgasına dönüştürmek için kullanılabilir. Ya da daha iyisi, yalnızca tarih saat yöntemlerini kullanın. Cevabımı
jfs

4
-1. Kodunuz, utc_offset (şimdi) ve utc_offset (epoch) değerlerinin yerel saat diliminde aynı olduğunu varsayar. 116 saat diliminde durum böyle değildir (430 ortak saat diliminden).
jfs

1
yine -1: .replace()gibi sabit olmayan bir utc uzaklığına sahip bir saat dilimi ile kullanmayın 'Europe/Amsterdam'. Pytz kullanarak Tarih Saat Zaman Dilimi dönüşümüne bakın .
jfs

1
1- Neden kullanmamanız gerektiğini anlıyor musunuz .replace(tzinfo=get_localzone())? 2- zaten timegm()geri dönüyor int. Sarmanıza gerek yok int. Ayrıca, .timetuple()saniyenin kesirlerini düşürür.
jfs

30

Başka bir olasılık şudur:

d = datetime.datetime.utcnow()
epoch = datetime.datetime(1970,1,1)
t = (d - epoch).total_seconds()

Bu, hem "d" hem de "epoch" naif veri zamanları olduğundan çalışır, "-" operatörünü geçerli kılar ve bir aralık döndürür. total_seconds()aralığı saniyeye çevirir. total_seconds()Bir kayan nokta döndürdüğünü unutmayın.d.microsecond == 0


12
Aslında değil, fikir aynı ama bunu anlamak daha kolay :)
Natim

3
Zaman kütüphanesinde tek bir yöntem olacağını düşünürdünüz ...
sheesh

Zaman damgasını almak için, datetime.datetime.utcnow (). Timestamp ()
Eugene

21

Ayrıca , bu blog girişinde açıklandığı gibi calendar.timegm () işlevine de dikkat edin :

import calendar
calendar.timegm(utc_timetuple)

Çıktı, vaab çözümüne uygun olmalıdır.


13

Girdi tarih saat nesnesi UTC ise:

>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0)
>>> timestamp = (dt - datetime(1970, 1, 1)).total_seconds()
1199145600.0

Not: float döndürür, yani mikrosaniyeler bir saniyenin kesirleri olarak temsil edilir.

Giriş tarihi nesnesi UTC’deyse:

>>> from datetime import date
>>> utc_date = date(2008, 1, 1)
>>> timestamp = (utc_date.toordinal() - date(1970, 1, 1).toordinal()) * 24*60*60
1199145600

Python'da datetime.date'i UTC zaman damgasına dönüştürme bölümünde daha fazla ayrıntıya bakın .


8

Ana cevabın hala çok net olmadığını düşünüyorum ve zamanı ve saat dilimlerini anlamak için zaman ayırmaya değer .

Zamanla uğraşırken anlaşılması gereken en önemli şey, zamanın göreceli olduğudur !

  • 2017-08-30 13:23:00: (saf bir tarih-saat), dünyanın herhangi bir yerinde yerel bir saati temsil eder , ancak 2017-08-30 13:23:00Londra'nın San Francisco'daki gibi AYNI ZAMAN DEĞİLDİR2017-08-30 13:23:00 .

Aynı zaman dizisi, dünyanın neresinde olduğunuza bağlı olarak farklı zamanda farklı noktalar olarak yorumlanabildiğinden, mutlak bir zaman kavramına ihtiyaç vardır .

Bir UTC zaman damgası saniye (veya milisaniye) bir sayıdır gelen Epoch (olarak tanımlanır 1 January 1970 00:00:00deGMT : 00, saat dilimi farkı +00).

Epoch, GMT saat dilimine bağlıdır ve bu nedenle zaman içinde mutlak bir noktadır. Bir UTC zaman damgası , mutlak bir zamandan bir uzaklık olan bu nedenle, zaman içinde mutlak bir noktayı tanımlar .

Bu, olayları zamanında sipariş etmeyi mümkün kılar.

Zaman dilimi bilgisi olmadan, zaman görecelidir ve saf tarih saatinin hangi saat dilimine bağlı olması gerektiğine dair bir gösterge sağlamadan mutlak bir zaman kavramına dönüştürülemez .

Bilgisayar sisteminde kullanılan zaman türleri nelerdir?

  • naive datetime : genellikle işletim sisteminin programa saat dilimi bilgilerini sağlayabileceği yerel saatte (yani tarayıcıda) görüntüleme içindir.

  • UTC zaman damgaları : Bir UTC zaman damgası, yukarıda belirtildiği gibi, zaman içinde mutlak bir noktadır, ancak belirli bir saat dilimine sabitlenmiştir, bu nedenle bir UTC zaman damgası herhangi bir saat diliminde bir tarih saatine dönüştürülebilir , ancak saat dilimi bilgisi içermez . Bu ne anlama geliyor? Bu, 1504119325'in 2017-08-30T18:55:24Zveya 2017-08-30T17:55:24-0100veya aynı zamanda karşılık geldiği anlamına gelir 2017-08-30T10:55:24-0800. Size kaydedilen tarih saatinin nereden geldiğini söylemez . Genellikle kayıt olaylar (günlükleri, vb ...) veya dönüştürmek için kullanılan sunucu tarafında kullanılan zaman dilimi farkında datetime bir karşı zamanında mutlak nokta ve hesaplama zamanı farklılıkları .

  • ISO-8601 tarih saat dizesi: ISO-8601, saat dilimiyle tarih saati kaydetmek için standartlaştırılmış bir biçimdir. (Aslında birkaç format, buradan okuyun: https://en.wikipedia.org/wiki/ISO_8601 ) Sistemler arasında serileştirilebilir bir şekilde zaman dilimine duyarlı tarih-saat bilgisini iletmek için kullanılır.

Hangisi ne zaman kullanılır? Daha doğrusu saat dilimlerini ne zaman önemsemeniz gerekiyor?

  • Herhangi bir şekilde günün saatini önemsemeye ihtiyacınız varsa , saat dilimi bilgilerine ihtiyacınız vardır. Bir takvim veya alarm, dünyadaki herhangi bir kullanıcı için günün doğru saatinde bir toplantı ayarlamak için günün saatine ihtiyaç duyar. Bu veriler bir sunucuya kaydedilirse, sunucunun tarih saatinin hangi saat dilimine karşılık geldiğini bilmesi gerekir.

  • Dünyanın farklı yerlerinden gelen olaylar arasındaki zaman farklarını hesaplamak için UTC zaman damgası yeterlidir, ancak olayların günün hangi saatinde gerçekleştiğini analiz etme yeteneğini kaybedersiniz (yani, web analizi için, kullanıcıların ne zaman geleceğini bilmek isteyebilirsiniz. kendi yerel saatlerinde site : sabah veya akşam daha fazla kullanıcı görüyor musunuz? Günün saati bilgisi olmadan bunu çözemezsiniz.

Bir tarih dizesinde saat dilimi uzaklığı :

Önemli olan bir diğer nokta da, bir tarih dizisindeki saat dilimi uzaklığının sabit olmamasıdır . Bu 2017-08-30T10:55:24-0800, ofset -0800veya 8 saat geri söylediği için , bunun her zaman olacağı anlamına gelmediği anlamına gelir!

Yaz aylarında, gün ışığından yararlanma saatinde olabilir ve -0700

Bunun anlamı, saat dilimi farkı (+0100) ile saat dilimi adıyla (Avrupa / Fransa) veya hatta saat dilimi tanımıyla (CET) aynı değildir.

America/Los_Angelessaat dilimi dünyadaki bir yerdir , ancak PSTkışın (Pasifik Standart Saati) saat dilimi ofset gösterimine ve yazın PDT(Pasifik Yaz Saati) saatine dönüşür .

Bu nedenle, saat diliminin tarih halkasından uzaklığını almanın yanı sıra, saat diliminin adını da doğru olarak almalısınız.

Çoğu paket, sayısal sapmaları kendi başlarına yaz saati uygulamasından standart saate dönüştürebilecek, ancak bu sadece dengeleme ile önemsiz değildir. Örneğin WAT, Batı Afrika'daki saat dilimi tanımı, UTC + 0100 şeklindedir.CET Fransa'daki saat dilimi , ancak Fransa gün ışığından yararlanma saatini gözlemlerken, Batı Afrika bunu yapmaz (çünkü ekvatora yakınlar)

Yani kısacası karmaşık. ÇOK karmaşık ve bu yüzden bunu kendiniz yapmamalısınız, ancak bunu sizin için yapan bir pakete güvenin ve BU GÜNCEL TUTUN!


Farklı paketlerin tuzaklarını anlamak için Python'daki tarih ve saat hakkındaki blog yazıma bakın medium.com/@eleroy/…
MrE

3

Harici modüller kullanmadan basit bir çözüm:

from datetime import datetime, timezone

dt = datetime(2008, 1, 1, 0, 0, 0, 0)
int(dt.replace(tzinfo=timezone.utc).timestamp())


1

Sanırım sorunuzu ifade etmenin doğru yolu Is there a way to get the timestamp by specifying the date in UTC? , çünkü zaman damgası sadece mutlak bir sayıdır, göreli değil. Göreceli (veya saat dilimi farkında olan) parça tarihtir.

Pandaları zaman damgaları için çok uygun buluyorum, bu nedenle:

import pandas as pd
dt1 = datetime(2008, 1, 1, 0, 0, 0, 0)
ts1 = pd.Timestamp(dt1, tz='utc').timestamp()
# make sure you get back dt1
datetime.utcfromtimestamp(ts1)  

Pandaları kullanmak IMHO'nun doğru yaklaşımıdır, şu an için doğrudan doğru zamanı elde etmek için t = Timestamp.utcnow () da vardır :)
ntg

0

Kabul edilen cevap benim için işe yaramıyor gibi görünüyor. Çözümüm:

import time
utc_0 = int(time.mktime(datetime(1970, 01, 01).timetuple()))
def datetime2ts(dt):
    """Converts a datetime object to UTC timestamp"""
    return int(time.mktime(dt.utctimetuple())) - utc_0

dtyerel saat diliminin mevcut ( ) UTC farkı ile 1970'teki farklıysa başarısız olur . mktime()yerel saat bekleniyor.
jfs

0

En basit yol:

>>> from datetime import datetime
>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0)
>>> dt.strftime("%s")
'1199163600'

Düzenleme: @Daniel doğru, bu onu makinenin saat dilimine dönüştürür. İşte gözden geçirilmiş bir cevap:

>>> from datetime import datetime, timezone
>>> epoch = datetime(1970, 1, 1, 0, 0, 0, 0, timezone.utc)
>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0, timezone.utc)
>>> int((dt-epoch).total_seconds())
'1199145600'

Aslında, belirtmek bile gerekli değildir timezone.utc, çünkü her ikisi datetimede aynı saat dilimine sahip olduğu (veya saat dilimi olmadığı) sürece saat farkı aynıdır .

>>> from datetime import datetime
>>> epoch = datetime(1970, 1, 1, 0, 0, 0, 0)
>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0)
>>> int((dt-epoch).total_seconds())
1199145600

bu yöntem utc döndürmez, bunun yerine tarih saatini geçerli saat dilimine ayarlar. yani. şimdi tz + 3'te 00:00 ise, çağda 09:00 döndürür.
Daniel Dubovski

Ah haklısın. Saat dilimim UTC idi - bu yüzden işe yaradı.
Mike Furlender

Eğer (Python 3.2 ve daha yeni) kullanacağız Eğer timezone.utcnesne, o zaman sadece o kullanmak .timestamp(): datetime(2008, 1, 1, tzinfo=timezone.utc).timestamp(). Epoch nesnesi oluşturup çıkarmaya gerek yok ..
Martijn Pieters
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.