Existe alguma maneira de usar uma função strftime-like para datas antes de 1900 em Python?
-
10-07-2019 - |
Pergunta
Eu não percebi isso, mas aparentemente função strftime
do Python não suporta datas antes de 1900:
>>> from datetime import datetime
>>> d = datetime(1899, 1, 1)
>>> d.strftime('%Y-%m-%d')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: year=1899 is before 1900; the datetime strftime() methods require year >= 1900
Eu tenho certeza que eu poderia cortar juntos algo me a fazer isso, mas eu acho que a função strftime
está lá por uma razão (e há também uma razão pela qual não pode suportar pré-1900 datas). Eu preciso ser capaz de suportar datas antes de 1900. Eu tinha acabado de usar str
, mas não há muita variação. Em outras palavras, ele pode ou não pode ter microssegundos ou pode ou não pode ter um fuso horário. Existe alguma solução para isso?
Se ele faz a diferença, eu estou fazendo isso para que eu possa gravar os dados em um arquivo de texto e carregá-lo em um banco de dados usando o Oracle SQL * Loader.
I essencialmente acabou fazendo a resposta de Alex Martelli. Aqui está uma implementação mais completa:
>>> from datetime import datetime
>>> d = datetime.now()
>>> d = d.replace(microsecond=0, tzinfo=None)
>>> str(d)
'2009-10-29 11:27:27'
A única diferença é que str(d)
é equivalente a d.isoformat(' ')
.
Solução
isoformat funciona em instâncias datetime
w / o limitação do intervalo:
>>> import datetime
>>> x=datetime.datetime(1865, 7, 2, 9, 30, 21)
>>> x.isoformat()
'1865-07-02T09:30:21'
Se precisar de uma cadeia diferente do formato que não é muito difícil de fatia, dados e peças de remix da sequência que começa a partir de isoformat
, que é muito consistente (YYYY-MM-DDTHH:MM:SS.mmmmmm
, com o ponto e seguintes microssegundos omitido se microssegundos são zero).
Outras dicas
A documentação parece bastante claro sobre isso:
O intervalo exato de anos para os quais
strftime()
funciona também varia entre plataformas. Independentemente da plataforma, anos antes de 1900 não pode ser usado.
Assim lá não vai ser uma solução que usa strftime()
. Felizmente, é bastante simples de fazer isso "à mão":
>>> "%02d-%02d-%02d %02d:%02d" % (d.year,d.month,d.day,d.hour,d.minute)
'1899-01-01 00:00'
mxDateTime
pode lidar com datas arbitrárias. módulos time
e datetime
do Python usar UNIX timestamps internamente, é por isso que eles têm alcance limitado.
In [5]: mx.DateTime.DateTime(1899)
Out[5]: <mx.DateTime.DateTime object for '1899-01-01 00:00:00.00' at 154a960>
In [6]: DateTime.DateTime(1899).Format('%Y-%m-%d')
Out[6]: 1899-01-01
Esta é a partir do fonte matplotlib . Poderia fornecer um bom ponto de partida para rolar seus próprios.
def strftime(self, dt, fmt):
fmt = self.illegal_s.sub(r"\1", fmt)
fmt = fmt.replace("%s", "s")
if dt.year > 1900:
return cbook.unicode_safe(dt.strftime(fmt))
year = dt.year
# For every non-leap year century, advance by
# 6 years to get into the 28-year repeat cycle
delta = 2000 - year
off = 6*(delta // 100 + delta // 400)
year = year + off
# Move to around the year 2000
year = year + ((2000 - year)//28)*28
timetuple = dt.timetuple()
s1 = time.strftime(fmt, (year,) + timetuple[1:])
sites1 = self._findall(s1, str(year))
s2 = time.strftime(fmt, (year+28,) + timetuple[1:])
sites2 = self._findall(s2, str(year+28))
sites = []
for site in sites1:
if site in sites2:
sites.append(site)
s = s1
syear = "%4d" % (dt.year,)
for site in sites:
s = s[:site] + syear + s[site+4:]
return cbook.unicode_safe(s)
Este é o "recurso" da biblioteca ctime (UTF). Além disso, você pode ter problema acima 2038.