Datetime.date dosyasını Python'da UTC zaman damgasına dönüştürme


295

Python tarihleri ​​ile ilgileniyorum ve Javascript içinde kullanılacak UTC zaman damgalarına dönüştürmek gerekiyor. Aşağıdaki kod çalışmıyor:

>>> d = datetime.date(2011,01,01)
>>> datetime.datetime.utcfromtimestamp(time.mktime(d.timetuple()))
datetime.datetime(2010, 12, 31, 23, 0)

Tarih nesnesini önce datetime değerine dönüştürmek de yardımcı olmaz. Ben bu bağlantıdan örnek denedim , ama:

from pytz import utc, timezone
from datetime import datetime
from time import mktime
input_date = datetime(year=2011, month=1, day=15)

ve şimdi ya:

mktime(utc.localize(input_date).utctimetuple())

veya

mktime(timezone('US/Eastern').localize(input_date).utctimetuple())

çalışır.

Genel soru: UTC'ye göre dönemden bu yana saniyeye dönüştürülen bir tarihi nasıl edinebilirim?



29
Bir kopya olarak işaretlemeyi kabul edeceğime emin değilim. Çözümler benzer olsa da, sorular değildir. Biri (bu) a'dan bir zaman damgası yaratmaya çalışıyor datetime.date, diğeri bir dize temsilini bir zaman diliminden diğerine dönüştürmeye çalışıyor. Bu soruna bir çözüm arayan biri olarak, aradığım cevabı aradığım sonucuna varamayabilirim.
DRH

5
datetime (date.year, date.month, date.day) .timestamp ()
Julian

4
Olası bir Python
Trevor Boyd Smith

Yanıtlar:


462

Eğer d = date(2011, 1, 1)UTC geçerli:

>>> from datetime import datetime, date
>>> import calendar
>>> timestamp1 = calendar.timegm(d.timetuple())
>>> datetime.utcfromtimestamp(timestamp1)
datetime.datetime(2011, 1, 1, 0, 0)

Eğer dyerel saat diliminde geçerli:

>>> import time
>>> timestamp2 = time.mktime(d.timetuple()) # DO NOT USE IT WITH UTC DATE
>>> datetime.fromtimestamp(timestamp2)
datetime.datetime(2011, 1, 1, 0, 0)

timestamp1ve timestamp2yerel saat dilimindeki gece yarısı UTC'deki gece yarısı ile aynı saat örneği değilse farklılık gösterebilir.

mktime()eğer bir yanlış sonuç döndürebilir dbir karşılık gelir (DST geçiş sırasında örneğin) belirsiz yerel saat veya eğer dofset utc farklı olabilirdi geçmiş (gelecek) tarihtir ve C mktime()erişimi yok tz veritabanında verilen platformda . Sen olabilir kullanmak pytz(aracılığıyla, örneğin modülü tzlocal.get_localzone()tüm platformlarda tz veritabanına erişmek için) . Ayrıca, utcfromtimestamp()başarısız olabilir vemktime()"right" saat dilimi kullanılırsa POSIX dışı zaman damgası döndürebilir .


datetime.dateUTC'de olmayan tarihi temsil eden nesneyi dönüştürmek içincalendar.timegm() :

DAY = 24*60*60 # POSIX day in seconds (exact value)
timestamp = (utc_date.toordinal() - date(1970, 1, 1).toordinal()) * DAY
timestamp = (utc_date - date(1970, 1, 1)).days * DAY

UTC'ye göre çağdan bu yana bir tarihi nasıl saniyeye dönüştürürüm?

Dönüştürmek için datetime.datetime(değildatetime.dateUTC'de zamanı temsil eden nesneyi karşılık gelen POSIX zaman damgasına (a float) ).

Python 3.3+

datetime.timestamp():

from datetime import timezone

timestamp = dt.replace(tzinfo=timezone.utc).timestamp()

Not: Tedarik etmek gerekir timezone.utc Aksi halde .timestamp()naif datetime nesnenizin yerel saat diliminde olduğunu varsayalım.

Python 3 (<3.3)

İçin dokümanlardan datetime.utcfromtimestamp():

Zaman damgasını datetime örneğinden edinmenin bir yöntemi yoktur, ancak datetime örneğine dt karşılık gelen POSIX zaman damgası aşağıdaki gibi kolayca hesaplanabilir. Saf bir dt için:

timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)

Ve farkında bir dt için:

timestamp = (dt - datetime(1970,1,1, tzinfo=timezone.utc)) / timedelta(seconds=1)

İlginç okuma: Dönem zamanı ile günün saati arasındaki fark Saat kaçta ? ve kaç saniye geçti?

Ayrıca bakınız: datetime bir "epoch" yöntemine ihtiyaç duyar

Python 2

Yukarıdaki kodu Python 2'ye uyarlamak için:

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

Burada timedelta.total_seconds(), (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6gerçek bölüm etkinken hesaplanan ile eşdeğerdir .

Misal

from __future__ import division
from datetime import datetime, timedelta

def totimestamp(dt, epoch=datetime(1970,1,1)):
    td = dt - epoch
    # return td.total_seconds()
    return (td.microseconds + (td.seconds + td.days * 86400) * 10**6) / 10**6 

now = datetime.utcnow()
print now
print totimestamp(now)

Kayan nokta sorunlarına dikkat edin .

Çıktı

2012-01-08 15:34:10.022403
1326036850.02

Bilinçli bir datetimenesneyi POSIX zaman damgasına dönüştürme

assert dt.tzinfo is not None and dt.utcoffset() is not None
timestamp = dt.timestamp() # Python 3.3+

Python 3'te:

from datetime import datetime, timedelta, timezone

epoch = datetime(1970, 1, 1, tzinfo=timezone.utc)
timestamp = (dt - epoch) / timedelta(seconds=1)
integer_timestamp = (dt - epoch) // timedelta(seconds=1)

Python 2'de:

# utc time = local time              - utc offset
utc_naive  = dt.replace(tzinfo=None) - dt.utcoffset()
timestamp = (utc_naive - datetime(1970, 1, 1)).total_seconds()

2
Python 2 durumda, neden olmasın: timestamp = (dt - datetime.fromtimestamp(0)).total_seconds()?
m01

7
@ m01: datetime(1970, 1, 1)daha açık. fromtimestamp()burada yanlış ( dtUTC'de olduğundan utcfromtimestamp(), bunun yerine kullanılmalıdır).
jfs

1
@fedorqui totimestamp()cevap fonksiyonuna bakın .
jfs

14
Python'u sevdiğim kadarıyla, tarih-zaman lib'i ciddi şekilde bozuldu.
Realfun

3
@ Realfun: zaman dilimleri, DST geçişleri, tz veritabanı, artık saniye Python'dan bağımsızdır.
jfs

81

For Unix sistemleri sadece :

>>> import datetime
>>> d = datetime.date(2011,01,01)
>>> d.strftime("%s")  # <-- THIS IS THE CODE YOU WANT
'1293832800'

Not 1: Baş dönmesi bunun lokalize zaman dilimlerini uyguladığını gözlemledi . Üretimde kullanmayın.

Not 2: Jakub Narębski bunun ofset farkında tarih bile (Python 2.7 için test edilmiş) saat dilimi bilgilerini yok saydığını .


4
Kodunuzun hangi sistem altında çalışacağını biliyorsanız iyi bir yanıttır, ancak '% s' biçim dizesinin tüm işletim sistemlerinde bulunmadığına dikkat etmek önemlidir, bu nedenle bu kod taşınabilir değildir. Desteklenip desteklenmediğini kontrol etmek istiyorsanız man strftime, Unix benzeri sistemleri kontrol edebilirsiniz .
Alice Heaton

5
Bunun kesirli saniye bölümünü (mikrosaniye veya herhangi bir şey) düşürdüğü belirtilmelidir.
Alfe

11
UYARI: Bu, yerelleştirilmiş zaman dilimleri için geçerlidir! Makine zamanına bağlı olarak aynı tarih-saat nesneleri için farklı strftime davranışları elde
edeceksiniz

3
Üstelik bu, saat dilimi bilgisini yok sayar ve tzinfo seti ile tarih- saatin ofset-farkında tarih saatinde bile yerel saat diliminde olduğunu varsayar . En azından Python 2.7'de.
Jakub Narębski

1
javascript zaman damgası = python zaman damgası * 1000
Trinh Hoang Nhu

38
  • Varsayım 1: Bir tarihi zaman damgasına dönüştürmeye çalışıyorsunuz, ancak bir tarih 24 saatlik bir dönemi kapsadığından, bu tarihi temsil eden tek bir zaman damgası yoktur. Bu tarihin zaman damgasını gece yarısı (00: 00: 00.000) temsil etmek istediğinizi varsayacağım.

  • Varsayım 2: Sunduğunuz tarih belirli bir saat dilimi ile ilişkili değildir, ancak belirli bir saat diliminden (UTC) sapmayı belirlemek istersiniz. Tarihin bulunduğu saat dilimini bilmeden, belirli bir saat dilimi için bir zaman damgası hesaplamak mümkün değildir. Tarihi yerel sistem saat dilimindeymiş gibi ele almak istediğinizi varsayacağım.

İlk olarak, date örneğini timetuple()üyeyi kullanarak çeşitli zaman bileşenlerini temsil eden bir tuple biçimine dönüştürebilirsiniz :

dtt = d.timetuple() # time.struct_time(tm_year=2011, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=5, tm_yday=1, tm_isdst=-1)

Daha sonra bunu kullanarak bir zaman damgasına dönüştürebilirsiniz time.mktime:

ts = time.mktime(dtt) # 1293868800.0

Bu yöntemi dönem zamanının kendisi (1970-01-01) ile test ederek doğrulayabilirsiniz; bu durumda işlev, o tarihte yerel saat dilimi için saat dilimi sapmasını döndürmelidir:

d = datetime.date(1970,1,1)
dtt = d.timetuple() # time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=-1)
ts = time.mktime(dtt) # 28800.0

28800.0 Pasifik saat dilimi için doğru olan 8 saattir (burada olduğum yer).


Bunun neden reddedildiğinden emin değilim. OP sorununu ele alır (OP'nin "çalışmıyor" olarak etiketlenmiş çalışma kodu). Soruma cevap vermiyor ( UTC datetime.datetime öğesini zaman damgasına dönüştür ), ama yine de… oylama.
Thanatos

9
Dikkatli ol. "Tarihi yerel sistem saat dilimindeymiş gibi ele almak istediğiniz varsayımı, python'da saat dilimi ile ilgili tüm sorunların köküdür. Komut dosyanızı çalıştıracak makinenin yerelleştirilmesinden% 100 emin değilseniz ve özellikle dünyanın herhangi bir yerinden gelebilecek müşterilere hizmet verirseniz, DAİMA tarihlerin UTC olduğunu varsayar ve dönüşümü mümkün olduğunca erken
Romain G

8

python2.7 belgesini izleyin, time.mktime () yerine calendar.timegm () yöntemini kullanmanız gerekir

>>> d = datetime.date(2011,01,01)
>>> datetime.datetime.utcfromtimestamp(calendar.timegm(d.timetuple()))
datetime.datetime(2011, 1, 1, 0, 0)

3
nasıl farklıysa cevabım ise dUTC nedir?
jfs

8

Kendi iki fonksiyonumu tanımladım

  • utc_time2datetime (utc_time, tz = Yok)
  • datetime2utc_time (tarih saat)

buraya:

import time
import datetime
from pytz import timezone
import calendar
import pytz


def utc_time2datetime(utc_time, tz=None):
    # convert utc time to utc datetime
    utc_datetime = datetime.datetime.fromtimestamp(utc_time)

    # add time zone to utc datetime
    if tz is None:
        tz_datetime = utc_datetime.astimezone(timezone('utc'))
    else:
        tz_datetime = utc_datetime.astimezone(tz)

    return tz_datetime


def datetime2utc_time(datetime):
    # add utc time zone if no time zone is set
    if datetime.tzinfo is None:
        datetime = datetime.replace(tzinfo=timezone('utc'))

    # convert to utc time zone from whatever time zone the datetime is set to
    utc_datetime = datetime.astimezone(timezone('utc')).replace(tzinfo=None)

    # create a time tuple from datetime
    utc_timetuple = utc_datetime.timetuple()

    # create a time element from the tuple an add microseconds
    utc_time = calendar.timegm(utc_timetuple) + datetime.microsecond / 1E6

    return utc_time

1
Örneğinizin hemen önüne göz attım .. Bu kadar basit bir şey için dağınık ve karmaşık bir yol ... Pitonik değil.
Kızgın 84

@Mayhem: Biraz temizledim ve yorum ekledim. Zaman dilimini ayarlayabileceğiniz daha iyi ve daha genel bir çözümünüz varsa, saat dilimini ayarlayabilmeniz için lütfen bize bildirin. Ayrıca kodumun daha pythonic bir örneğinin nasıl olması gerektiğini bana bildirin .
agittarius

3

soru biraz karışık. zaman damgaları UTC değildir - bunlar bir Unix olayıdır. tarih UTC olabilir? varsayalım ve Python 3.2+ kullanıyorsanız, basit tarih bunu önemsiz kılar:

>>> SimpleDate(date(2011,1,1), tz='utc').timestamp
1293840000.0

aslında yıl, ay ve güne sahipseniz aşağıdakileri oluşturmanız gerekmez date:

>>> SimpleDate(2011,1,1, tz='utc').timestamp
1293840000.0

ve tarih başka bir saat dilimindeyse (bu, önemli bir saat olmadan gece yarısı varsaydığımız için önemlidir ):

>>> SimpleDate(date(2011,1,1), tz='America/New_York').timestamp
1293858000.0

[basit tarihin arkasındaki fikir, tüm python'un tarih ve saat öğelerini tek bir sınıfta toplamaktır, böylece herhangi bir dönüşüm yapabilirsiniz. yani, örneğin, diğer yöne de gidecektir:

>>> SimpleDate(1293858000, tz='utc').date
datetime.date(2011, 1, 1)

]


SimpleDate(date(2011,1,1), tz='America/New_York')yükseltir NoTimezoneederken, pytz.timezone('America/New_York')(herhangi bir istisna yükseltmek değil simple-date==0.4.8, pytz==2014.7).
jfs

İle ilgili bir hata alıyorum pip install simple-date sadece python3 / pip3 gibi görünüyor.
NoBugs

3

Ok paketini kullanarak :

>>> import arrow
>>> arrow.get(2010, 12, 31).timestamp
1293753600
>>> time.gmtime(1293753600)
time.struct_time(tm_year=2010, tm_mon=12, tm_mday=31, 
    tm_hour=0, tm_min=0, tm_sec=0, 
    tm_wday=4, tm_yday=365, tm_isdst=0)

not: arrowkullanır dateutil ve yıllardır zaman dilimi işleme ile ilgili hatalarıdateutil biliyor . Sabit olmayan bir UTC ofseti olan zaman dilimleri için doğru sonuçlara ihtiyacınız varsa bunu kullanmayın (UTC saat dilimi için kullanmanız uygundur, ancak stdlib UTC durumunu tamamlar).
jfs

@JFSebastian Bu hata yalnızca bir geçiş sırasında belirsiz bir zamanda ortaya çıkar.
Paul

Hata 28 Mart'ta giderildi gibi görünüyor
Mathieu Longtin

Görünüşe göre, en iyi ve çapraz python çözümü. Sadece oku kullan . Teşekkürler;)
maxkoryukov

@MathieuLongtin dateutil başka sorunları
jfs

1

Tam bir zaman dizesi şunları içerir:

  • tarih
  • zaman
  • UTCOFFSET [+HHMM or -HHMM]

Örneğin:

1970-01-01 06:00:00 +0500 == 1970-01-01 01:00:00 +0000 == UNIX timestamp:3600

$ python3
>>> from datetime import datetime
>>> from calendar import timegm
>>> tm = '1970-01-01 06:00:00 +0500'
>>> fmt = '%Y-%m-%d %H:%M:%S %z'
>>> timegm(datetime.strptime(tm, fmt).utctimetuple())
3600

Not:

UNIX timestamp, UTC'den beri çağdan bu yana saniye cinsinden ifade edilen kayan nokta sayısıdır .


Düzenle:

$ python3
>>> from datetime import datetime, timezone, timedelta
>>> from calendar import timegm
>>> dt = datetime(1970, 1, 1, 6, 0)
>>> tz = timezone(timedelta(hours=5))
>>> timegm(dt.replace(tzinfo=tz).utctimetuple())
3600

6
Ve bu sorumu nasıl cevaplıyor?
Andreas Jung

1
@ user908088 dönüştürme 1970-01-01 06:00:00 +0500için 3600istediğin gibi.
kev

1
@ user908088 hiçbir Orada timezoneiçinde python2(eğer hesaplama yapabilirsiniz, 06:00:00- +0500= 01:00:00) manuel.
kev

5
neden bu cevap -1 oy olsa bile, SO ile yanlış bir şey
Umair

1

Adlı bir datetimenesneniz olduğu düşünüldüğünde d, UTC'de zaman damgası almak için aşağıdakileri kullanın:

d.strftime("%Y-%m-%dT%H:%M:%S.%fZ")

Ve zıt yön için aşağıdakileri kullanın:

d = datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%fZ")

0

Derin tartışmalardan etkilendim.

benim 2 sent:

datetime ithalatından datetime içe aktarma zamanı

utc içindeki zaman damgası:

timestamp = \
(datetime.utcnow() - datetime(1970,1,1)).total_seconds()

veya,

timestamp = time.time()

şimdi datetime.now () 'dan kaynaklanıyorsa, aynı DST'de

utcoffset = (datetime.now() - datetime.utcnow()).total_seconds()
timestamp = \
(now - datetime(1970,1,1)).total_seconds() - utcoffset
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.