Python'un türü gibi RFC 3339 dizeleri ayrıştırmak gerekiyor ."2008-09-03T20:56:35.450686Z"
datetime
strptime
Python standart kütüphanesinde buldum , ama çok uygun değil.
Bunu yapmanın en iyi yolu nedir?
Python'un türü gibi RFC 3339 dizeleri ayrıştırmak gerekiyor ."2008-09-03T20:56:35.450686Z"
datetime
strptime
Python standart kütüphanesinde buldum , ama çok uygun değil.
Bunu yapmanın en iyi yolu nedir?
Yanıtlar:
Piton-dateutil paket söz konusu gibi sadece RFC 3339 tarih saat dizeleri ayrıştırmak, ancak aynı zamanda diğer ISO 8601 hiçbir UTC olanlar ofset RFC 3339 uymayan tarih ve saat dizeleri (örneğin, ya da olanları temsil ettiğini yalnızca bir tarih).
>>> import dateutil.parser
>>> dateutil.parser.isoparse('2008-09-03T20:56:35.450686Z') # RFC 3339 format
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=tzutc())
>>> dateutil.parser.isoparse('2008-09-03T20:56:35.450686') # ISO 8601 extended format
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
>>> dateutil.parser.isoparse('20080903T205635.450686') # ISO 8601 basic format
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
>>> dateutil.parser.isoparse('20080903') # ISO 8601 basic format, date only
datetime.datetime(2008, 9, 3, 0, 0)
Not dateutil.parser.isoparse
daha hacky daha muhtemelen sıkı olduğunu dateutil.parser.parse
, ancak bunların her ikisi de oldukça bağışlayıcı ve siz geçmek olduğunu dizeyi yorumlamaya çalışacaktır. Eğer herhangi bir olsa yanlış olasılığını ortadan kaldırmak için, bunlardan birini daha birşey sıkı kullanmak gerekir fonksiyonlar.
Pypi adı python-dateutil
değil dateutil
(teşekkürler code3monk3y ):
pip install python-dateutil
Python 3.7 kullanıyorsanız, bir göz bu cevabı hakkında datetime.datetime.fromisoformat
.
python-dateutil
değil dateutil
yani: pip install python-dateutil
.
dateutil.parser
Kasıtlı olarak hileli olduğu konusunda uyarıda bulunun: formatı tahmin etmeye çalışır ve belirsiz durumlarda kaçınılmaz varsayımlar yapar (sadece elle özelleştirilebilir). Bu nedenle, SADECE bilinmeyen formattaki girdileri ayrıştırmanız gerekiyorsa ve ara sıra yanlışları tolere etmek için uygunsa kullanın.
datetime
Standart kütüphane inversini bir işlevi tanıtıldı datetime.isoformat()
.
classmethod
datetime.fromisoformat(date_string)
:Bir Dönüş
datetime
Bir tekabüldate_string
yaydığı biçimlerden birindedate.isoformat()
vedatetime.isoformat()
.Özellikle, bu işlev biçim (ler) deki dizeleri destekler:
YYYY-MM-DD[*HH[:MM[:SS[.mmm[mmm]]]][+HH:MM[:SS[.ffffff]]]]
nerede
*
herhangi bir tek karakteri eşleşebilir.Dikkat : Bu, keyfi ISO 8601 dizelerinin ayrıştırılmasını desteklemez - yalnızca ters işlemi olarak tasarlanmıştır
datetime.isoformat()
.
Kullanım örneği:
from datetime import datetime
date = datetime.fromisoformat('2017-01-01T12:30:59.000000')
datetime
içerebilir tzinfo
ve bu nedenle bir saat dilimi çıktısı alabilir, ancak datetime.fromisoformat()
tzinfo'yu ayrıştırmaz mı? bir böcek gibi görünüyor ..
isoformat
. Söz konusu örnek kabul etmez "2008-09-03T20:56:35.450686Z"
çünkü Römorkun Z
ama kabul etmez "2008-09-03T20:56:35.450686"
.
Z
Giriş betiğini uygun şekilde desteklemek için ile değiştirilebilir date_string.replace("Z", "+00:00")
.
Python 2.6+ ve Py3K'da% f karakteri mikrosaniye yakalar.
>>> datetime.datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%fZ")
Soruna buradan bakın
strptime
.
datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%f')
bu hile yaptı
Buradaki birkaç cevap, RFC 3339 veya ISO 8601'i zaman zamanlarında, örneğin soruda gösterilenler gibi ayrıştırmayı kullanmayı önermektedir : datetime.datetime.strptime
2008-09-03T20:56:35.450686Z
Bu kötü bir fikir.
Sıfır dışında UTC ofsetleri için destek de dahil olmak üzere tam RFC 3339 biçimini desteklemek istediğinizi varsayarsak, bu yanıtların önerdiği kod çalışmaz. Gerçekten de, yapamam kullanarak RFC 3339 sözdizimi ayrıştırma, çünkü çalışma strptime
imkansızdır. Python'un datetime modülü tarafından kullanılan biçim dizeleri, RFC 3339 sözdizimini açıklayamaz.
Sorun UTC ofsetleridir. RFC 3339 Internet Tarih / Saat Biçimi her tarih-saat, bir UTC ayarı içerdiğini gerektirir ve bu uzaklıklar ya olabileceğini Z
(kısa "Zulu zamanı") veya +HH:MM
veya -HH:MM
format gibi +05:00
ya-10:30
.
Sonuç olarak, bunların hepsi geçerli RFC 3339 tarihleridir:
2008-09-03T20:56:35.450686Z
2008-09-03T20:56:35.450686+05:00
2008-09-03T20:56:35.450686-10:30
Ne yazık ki, tarafından kullanılan biçim dizeleri strptime
ve strftime
RFC 3339 biçimindeki UTC ofsetlerine karşılık gelen bir yönergesi yoktur. Destekledikleri direktiflerin tam bir listesini https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior adresinde bulabilirsiniz ve listedeki tek UTC ofset yönergesi %z
:
% z
+ HHMM veya -HHMM (nesnenin saf olması durumunda boş dize) biçimindeki UTC uzaklığı.
Örnek: (boş), +0000, -0400, +1030
Bu bir RFC 3339 ofsetinin biçimiyle eşleşmiyor ve gerçekten %z
de biçim dizesinde kullanmaya ve bir RFC 3339 tarihini ayrıştırmaya çalışırsak başarısız oluruz:
>>> from datetime import datetime
>>> datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%f%z")
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686Z' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
>>> datetime.strptime("2008-09-03T20:56:35.450686+05:00", "%Y-%m-%dT%H:%M:%S.%f%z")
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686+05:00' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
(Aslında, yukarıdaki sadece Python 3'te göreceğiniz şeydir. Python 2'de daha basit bir nedenden dolayı başarısız olacağız, bu da Python 2'de direktifi strptime
uygulamaz.%z
.)
Burada , soru sorucusunun örnek datetime dizesiyle eşleşen (ve atar, saat dilimi olmayan bir nesne üreterek) biçim dizesine strptime
bir değişmez değer ekleyerek bu sorunu çözen tüm yanıtlar :Z
Z
datetime
>>> datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%fZ")
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
Bu, orijinal datetime dizesine dahil olan saat dilimi bilgilerini attığından, bu sonucu bile doğru olarak kabul edip etmeyeceğimiz sorgulanabilir. Ancak daha da önemlisi, bu yaklaşım belirli bir UTC ofsetini format dizesine kodlamayı gerektirdiğinden , herhangi bir RFC 3339 tarih saatini farklı bir UTC ofseti ile ayrıştırmaya çalıştığı anı boğacaktır:
>>> datetime.strptime("2008-09-03T20:56:35.450686+05:00", "%Y-%m-%dT%H:%M:%S.%fZ")
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686+05:00' does not match format '%Y-%m-%dT%H:%M:%S.%fZ'
Vermenize sürece belirli yalnızca RFC diğer zaman dilimi uzaklıklar ile 3339 Zulu sürede tarihsaat değil, olanları desteklemek gerektiğini, kullanmayın strptime
. Bunun yerine burada yanıtlarda açıklanan diğer birçok yaklaşımdan birini kullanın.
strptime()
Python 3.7'de artık bu cevapta imkansız olarak tanımlanan her şeyi destekliyor ('Z' değişmez değeri ve ':' saat dilimi dengesinde). Ne yazık ki, RFC 3339'u ISO 8601 ile temel olarak uyumsuz hale getiren başka bir köşe durumu var, birincisi, negatif bir boş saat dilimi -00: 00 ve daha sonra değil.
İso8601 modülünü deneyin ; tam olarak bunu yapıyor.
Python.org wiki'sindeki WorkingWithTime sayfasında belirtilen birkaç seçenek daha vardır .
iso8601.parse_date("2008-09-03T20:56:35.450686Z")
import re, datetime s = "2008-09-03T20: 56: 35.450686Z" d = datetime.datetime (* harita (int, re.split ('[^ \ d]', s) [: - 1]))
datetime.datetime(*map(int, re.findall('\d+', s))
Aldığınız tam hata nedir? Aşağıdaki gibi mi?
>>> datetime.datetime.strptime("2008-08-12T12:20:30.656234Z", "%Y-%m-%dT%H:%M:%S.Z")
ValueError: time data did not match format: data=2008-08-12T12:20:30.656234Z fmt=%Y-%m-%dT%H:%M:%S.Z
Cevabınız evetse, giriş dizginizi "." Üzerine bölebilir ve sonra mikrosaniyeyi aldığınız tarih saatine ekleyebilirsiniz.
Bunu dene:
>>> def gt(dt_str):
dt, _, us= dt_str.partition(".")
dt= datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S")
us= int(us.rstrip("Z"), 10)
return dt + datetime.timedelta(microseconds=us)
>>> gt("2008-08-12T12:20:30.656234Z")
datetime.datetime(2008, 8, 12, 12, 20, 30, 656234)
""
veya dışında "Z"
bir şeyse, saat / dakika cinsinden bir uzaklık olmalıdır; bu dattime nesnesine doğrudan eklenebilir / bu nesneden çıkarılabilir. Eğer olabilir idare etmek alt sınıf tzinfo bir oluşturmak, ama muhtemelen kurumlarda değil.
Python 3.7'den başlayarak, strptime, UTC ofsetlerindeki ( kaynak ) kolon sınırlayıcılarını destekler . Böylece şunları kullanabilirsiniz:
import datetime
datetime.datetime.strptime('2018-01-31T09:24:31.488670+00:00', '%Y-%m-%dT%H:%M:%S.%f%z')
DÜZENLE:
Martijn tarafından belirtildiği gibi, datetime nesnesini isoformat () kullanarak oluşturduysanız, datetime.fromisoformat () yöntemini kullanabilirsiniz.
datetime.fromisoformat()
otomatik girişi gibi hangi kolları dizeleri: datetime.datetime.isoformat('2018-01-31T09:24:31.488670+00:00')
.
datetime.fromisoformat()
vedatetime.isoformat()
Bu günlerde Arrow ayrıca üçüncü taraf bir çözüm olarak da kullanılabilir:
>>> import arrow
>>> date = arrow.get("2008-09-03T20:56:35.450686Z")
>>> date.datetime
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=tzutc())
Sadece python-dateutil
modülü kullanın :
>>> import dateutil.parser as dp
>>> t = '1984-06-02T19:05:00.000Z'
>>> parsed_t = dp.parse(t)
>>> print(parsed_t)
datetime.datetime(1984, 6, 2, 19, 5, tzinfo=tzutc())
455051100
(kontrol epochconverter.com ben bir şey eksik sürece ,,,)?
Dateutil kullanmak istemiyorsanız, bu işlevi deneyebilirsiniz:
def from_utc(utcTime,fmt="%Y-%m-%dT%H:%M:%S.%fZ"):
"""
Convert UTC time string to time.struct_time
"""
# change datetime.datetime to time, return time.struct_time type
return datetime.datetime.strptime(utcTime, fmt)
Ölçek:
from_utc("2007-03-04T21:08:12.123Z")
Sonuç:
datetime.datetime(2007, 3, 4, 21, 8, 12, 123000)
strptime
. Bu kötü bir fikir çünkü herhangi bir tarih saatini farklı bir UTC ofsetiyle ayrıştıramayacak ve bir istisna oluşturamayacaktır. RFC 3339'u strptime ile ayrıştırmanın aslında imkansız olduğunu açıklayan cevabımı görün .
toISOString
yöntemiyle oluşturulduğunu biliyorsanız durum böyle olabilir . Ancak bu cevapta Zulu zaman tarihlerinin kısıtlılığından bahsetmiyoruz ya da soru, tüm gereken bu değil ve sadece kullanmanın dateutil
genellikle eşit derecede uygun ve ayrıştırılabileceği şeyde daha az dar olduğunu belirtmedi.
Django ile çalışıyorsanız , saat dilimi dahil ISO biçimine benzer bir dizi biçimi kabul eden dateparse modülünü sağlar .
Django kullanmıyorsanız ve burada belirtilen diğer kitaplıklardan birini kullanmak istemiyorsanız, büyük olasılıkla dateparse için Django kaynak kodunu projenize uyarlayabilirsiniz .
DateTimeField
Bir dize değeri ayarladığınızda Django's bunu kullanır.
ISO 8601 zaman damgalarını ayrıştırmanın en hızlı yolu olarak ciso8601'i buldum . Adından da anlaşılacağı gibi, C dilinde uygulanır.
import ciso8601
ciso8601.parse_datetime('2014-01-09T21:48:00.921000+05:30')
GitHub Repo README diğer yanıtlar listelenen diğer kütüphanelerin tüm karşı kendi> 10x hıza gösterir.
Kişisel projem birçok ISO 8601 ayrıştırma işini içeriyordu. Sadece aramayı değiştirmek ve 10 kat daha hızlı gitmek güzeldi. :)
Düzenleme: O zamandan beri ciso8601'in bir koruyucusu oldum. Şimdi her zamankinden daha hızlı!
datetime.strptime()
sonraki en hızlı çözüm olduğunu göstermek için kavrayışa sahipti . Tüm bu bilgileri bir araya getirdiğiniz için teşekkürler!
datetime.strptime()
tam bir ISO 8601 ayrıştırma kütüphanesi olmadığını unutmayın. Python 3.7 üzerindeyseniz, datetime.fromisoformat()
biraz daha esnek olan yöntemi kullanabilirsiniz . Yakında ciso8601 README ile birleştirilmesi gereken ayrıştırıcıların bu tam listesi ile ilgilenebilirsiniz .
Bu, Python 3.2'den sonraki stdlib için çalışır (tüm zaman damgalarının UTC olduğu varsayılarak):
from datetime import datetime, timezone, timedelta
datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S.%fZ").replace(
tzinfo=timezone(timedelta(0)))
Örneğin,
>>> datetime.utcnow().replace(tzinfo=timezone(timedelta(0)))
... datetime.datetime(2015, 3, 11, 6, 2, 47, 879129, tzinfo=datetime.timezone.utc)
strptime
. Bu kötü bir fikir çünkü herhangi bir tarih saatini farklı bir UTC ofsetiyle ayrıştıramayacak ve bir istisna oluşturamayacaktır. RFC 3339'u strptime ile ayrıştırmanın aslında imkansız olduğunu açıklayan cevabımı görün .
timezone.utc
yerine kullanabilirsiniz timezone(timedelta(0))
. Ayrıca, Python kod çalışır 2.6+ eğer (en azından) tedarik utc
tzinfo nesne
%Z
Python en son sürümlerinde Zaman dilimi için.
İso8601 utils yazarıyım. Bu bulunabilir GitHub üzerinde veya üzerinde PyPI . Örneğinizi nasıl ayrıştırabileceğiniz aşağıda açıklanmıştır:
>>> from iso8601utils import parsers
>>> parsers.datetime('2008-09-03T20:56:35.450686Z')
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
ISO 8601 benzeri bir tarih dizesini, datetime.datetime
üçüncü taraf modülleri yüklemeden desteklenen tüm Python sürümlerinde UNIX zaman damgasına veya nesneye dönüştürmenin basit bir yolu , SQLite'ın tarih ayrıştırıcısını kullanmaktır .
#!/usr/bin/env python
from __future__ import with_statement, division, print_function
import sqlite3
import datetime
testtimes = [
"2016-08-25T16:01:26.123456Z",
"2016-08-25T16:01:29",
]
db = sqlite3.connect(":memory:")
c = db.cursor()
for timestring in testtimes:
c.execute("SELECT strftime('%s', ?)", (timestring,))
converted = c.fetchone()[0]
print("%s is %s after epoch" % (timestring, converted))
dt = datetime.datetime.fromtimestamp(int(converted))
print("datetime is %s" % dt)
Çıktı:
2016-08-25T16:01:26.123456Z is 1472140886 after epoch
datetime is 2016-08-25 12:01:26
2016-08-25T16:01:29 is 1472140889 after epoch
datetime is 2016-08-25 12:01:29
ISO 8601 standardı için bir ayrıştırıcı kodladım ve GitHub'a koydum: https://github.com/boxed/iso8601 . Bu uygulama, Python'un datetime modülünün desteklenen tarih aralığının dışındaki süreler, aralıklar, periyodik aralıklar ve tarihler hariç spesifikasyondaki her şeyi destekler.
Testler dahildir! : P
Django'nun parse_datetime () işlevi UTC ötelemeli tarihleri destekler:
parse_datetime('2016-08-09T15:12:03.65478Z') =
datetime.datetime(2016, 8, 9, 15, 12, 3, 654780, tzinfo=<UTC>)
Bu nedenle, tüm proje içindeki alanlarda ISO 8601 tarihlerini ayrıştırmak için kullanılabilir:
from django.utils import formats
from django.forms.fields import DateTimeField
from django.utils.dateparse import parse_datetime
class DateTimeFieldFixed(DateTimeField):
def strptime(self, value, format):
if format == 'iso-8601':
return parse_datetime(value)
return super().strptime(value, format)
DateTimeField.strptime = DateTimeFieldFixed.strptime
formats.ISO_INPUT_FORMATS['DATETIME_INPUT_FORMATS'].insert(0, 'iso-8601')
Çünkü ISO 8601, temel olarak isteğe bağlı iki nokta üst üste ve tire çeşitlerinin mevcut olmasına izin verir CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]
. Eğer strptime kullanmak istiyorsanız, önce bu varyasyonları çıkarmanız gerekir.
Amaç bir utc datetime nesnesi oluşturmaktır.
2016-06-29T19:36:29.3453Z
:
datetime.datetime.strptime(timestamp.translate(None, ':-'), "%Y%m%dT%H%M%S.%fZ")
2016-06-29T19:36:29.3453-0400
veya 2008-09-03T20:56:35.450686+05:00
kullanmak istiyorsanız . Bunlar, tüm varyasyonları 20080903T205635.450686+0500
, ayrıştırmayı daha tutarlı / kolay hale getirmek gibi değişken sınırlayıcılar olmadan bir şeye dönüştürecektir .
import re
# this regex removes all colons and all
# dashes EXCEPT for the dash indicating + or - utc offset for the timezone
conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))", '', timestamp)
datetime.datetime.strptime(conformed_timestamp, "%Y%m%dT%H%M%S.%f%z" )
%z
strptime yönergesini desteklemiyorsa ( şuna benzer bir şey görürsünüz ValueError: 'z' is a bad directive in format '%Y%m%dT%H%M%S.%f%z'
) saati Z
(UTC) ile manuel olarak dengelemeniz gerekir . Not %z
, sistem / python oluşturma türüne (yani Jython, Cython vb.) Göre değişen c kütüphane desteğine bağlı olarak <3 python sürümlerinde sisteminizde çalışmayabilir.
import re
import datetime
# this regex removes all colons and all
# dashes EXCEPT for the dash indicating + or - utc offset for the timezone
conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))", '', timestamp)
# split on the offset to remove it. use a capture group to keep the delimiter
split_timestamp = re.split(r"[+|-]",conformed_timestamp)
main_timestamp = split_timestamp[0]
if len(split_timestamp) == 3:
sign = split_timestamp[1]
offset = split_timestamp[2]
else:
sign = None
offset = None
# generate the datetime object without the offset at UTC time
output_datetime = datetime.datetime.strptime(main_timestamp +"Z", "%Y%m%dT%H%M%S.%fZ" )
if offset:
# create timedelta based on offset
offset_delta = datetime.timedelta(hours=int(sign+offset[:-2]), minutes=int(sign+offset[-2:]))
# offset datetime with timedelta
output_datetime = output_datetime + offset_delta
2.X standart kitaplığıyla çalışan bir şey için şunu deneyin:
calendar.timegm(time.strptime(date.split(".")[0]+"UTC", "%Y-%m-%dT%H:%M:%S%Z"))
calendar.timegm, time.mktime öğesinin eksik gm sürümüdür.
Geçersiz tarih dizeleri ayrıştırılırsa python-dateutil bir istisna atar, bu nedenle istisnayı yakalamak isteyebilirsiniz.
from dateutil import parser
ds = '2012-60-31'
try:
dt = parser.parse(ds)
except ValueError, e:
print '"%s" is an invalid date' % ds
Günümüzde popüler İstekler: HTTP for Humans ™ paketinin yazarından Maya: Datetimes for Humans ™ var :
>>> import maya
>>> str = '2008-09-03T20:56:35.450686Z'
>>> maya.MayaDT.from_rfc3339(str).datetime()
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=<UTC>)
Başka bir yol, ISO-8601 için özel ayrıştırıcı kullanmak , dateutil ayrıştırıcının izoparse işlevini kullanmaktır :
from dateutil import parser
date = parser.isoparse("2008-09-03T20:56:35.450686+01:00")
print(date)
Çıktı:
2008-09-03 20:56:35.450686+01:00
Bu işlev, standart Python işlevi datetime.fromisoformat ile ilgili belgelerde de belirtilmiştir :
Daha kapsamlı bir ISO 8601 ayrıştırıcısı olan dateutil.parser.isoparse, üçüncü taraf paket dateutil'de mevcuttur.
Harika Mark Amery'nin cevabı sayesinde , tarih saatinin tüm olası ISO formatlarını hesaba katmak için fonksiyon tasarladım:
class FixedOffset(tzinfo):
"""Fixed offset in minutes: `time = utc_time + utc_offset`."""
def __init__(self, offset):
self.__offset = timedelta(minutes=offset)
hours, minutes = divmod(offset, 60)
#NOTE: the last part is to remind about deprecated POSIX GMT+h timezones
# that have the opposite sign in the name;
# the corresponding numeric value is not used e.g., no minutes
self.__name = '<%+03d%02d>%+d' % (hours, minutes, -hours)
def utcoffset(self, dt=None):
return self.__offset
def tzname(self, dt=None):
return self.__name
def dst(self, dt=None):
return timedelta(0)
def __repr__(self):
return 'FixedOffset(%d)' % (self.utcoffset().total_seconds() / 60)
def __getinitargs__(self):
return (self.__offset.total_seconds()/60,)
def parse_isoformat_datetime(isodatetime):
try:
return datetime.strptime(isodatetime, '%Y-%m-%dT%H:%M:%S.%f')
except ValueError:
pass
try:
return datetime.strptime(isodatetime, '%Y-%m-%dT%H:%M:%S')
except ValueError:
pass
pat = r'(.*?[+-]\d{2}):(\d{2})'
temp = re.sub(pat, r'\1\2', isodatetime)
naive_date_str = temp[:-5]
offset_str = temp[-5:]
naive_dt = datetime.strptime(naive_date_str, '%Y-%m-%dT%H:%M:%S.%f')
offset = int(offset_str[-4:-2])*60 + int(offset_str[-2:])
if offset_str[0] == "-":
offset = -offset
return naive_dt.replace(tzinfo=FixedOffset(offset))
def parseISO8601DateTime(datetimeStr):
import time
from datetime import datetime, timedelta
def log_date_string(when):
gmt = time.gmtime(when)
if time.daylight and gmt[8]:
tz = time.altzone
else:
tz = time.timezone
if tz > 0:
neg = 1
else:
neg = 0
tz = -tz
h, rem = divmod(tz, 3600)
m, rem = divmod(rem, 60)
if neg:
offset = '-%02d%02d' % (h, m)
else:
offset = '+%02d%02d' % (h, m)
return time.strftime('%d/%b/%Y:%H:%M:%S ', gmt) + offset
dt = datetime.strptime(datetimeStr, '%Y-%m-%dT%H:%M:%S.%fZ')
timestamp = dt.timestamp()
return dt + timedelta(hours=dt.hour-time.gmtime(timestamp).tm_hour)
Dizenin bitip bitmediğine bakmamız gerektiğini Z
, kullanarak ayrıştırabileceğimizi unutmayın %z
.
Başlangıçta ile denedim:
from operator import neg, pos
from time import strptime, mktime
from datetime import datetime, tzinfo, timedelta
class MyUTCOffsetTimezone(tzinfo):
@staticmethod
def with_offset(offset_no_signal, signal): # type: (str, str) -> MyUTCOffsetTimezone
return MyUTCOffsetTimezone((pos if signal == '+' else neg)(
(datetime.strptime(offset_no_signal, '%H:%M') - datetime(1900, 1, 1))
.total_seconds()))
def __init__(self, offset, name=None):
self.offset = timedelta(seconds=offset)
self.name = name or self.__class__.__name__
def utcoffset(self, dt):
return self.offset
def tzname(self, dt):
return self.name
def dst(self, dt):
return timedelta(0)
def to_datetime_tz(dt): # type: (str) -> datetime
fmt = '%Y-%m-%dT%H:%M:%S.%f'
if dt[-6] in frozenset(('+', '-')):
dt, sign, offset = strptime(dt[:-6], fmt), dt[-6], dt[-5:]
return datetime.fromtimestamp(mktime(dt),
tz=MyUTCOffsetTimezone.with_offset(offset, sign))
elif dt[-1] == 'Z':
return datetime.strptime(dt, fmt + 'Z')
return datetime.strptime(dt, fmt)
Ama bu olumsuz zaman dilimlerinde işe yaramadı. Ancak bu Python 3.7.3 iyi çalıştım:
from datetime import datetime
def to_datetime_tz(dt): # type: (str) -> datetime
fmt = '%Y-%m-%dT%H:%M:%S.%f'
if dt[-6] in frozenset(('+', '-')):
return datetime.strptime(dt, fmt + '%z')
elif dt[-1] == 'Z':
return datetime.strptime(dt, fmt + 'Z')
return datetime.strptime(dt, fmt)
Bazı testler, çıkışın sadece mikrosaniyelerin hassasiyetinden farklı olduğunu unutmayın. Makinemde 6 basamak hassasiyet var, ancak YMMV:
for dt_in, dt_out in (
('2019-03-11T08:00:00.000Z', '2019-03-11T08:00:00'),
('2019-03-11T08:00:00.000+11:00', '2019-03-11T08:00:00+11:00'),
('2019-03-11T08:00:00.000-11:00', '2019-03-11T08:00:00-11:00')
):
isoformat = to_datetime_tz(dt_in).isoformat()
assert isoformat == dt_out, '{} != {}'.format(isoformat, dt_out)
frozenset(('+', '-'))
? Normal bir grup ('+', '-')
aynı şeyi başaramaz mı?