Esiste un modo per utilizzare una funzione simile a strftime per le date precedenti al 1900 in Python?
-
10-07-2019 - |
Domanda
Non me ne sono reso conto, ma a quanto pare la funzione strftime
di Python non supporta le date precedenti al 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
Sono sicuro di poter hackerare insieme qualcosa per farlo, ma immagino che la funzione strftime
sia lì per un motivo (e c'è anche un motivo per cui non può supportare pre 1900 date). Devo essere in grado di supportare date precedenti al 1900. Utilizzerei solo str
, ma ci sono troppe variazioni. In altre parole, può avere o meno microsecondi oppure può avere o meno un fuso orario. C'è una soluzione a questo?
Se fa la differenza, lo sto facendo in modo da poter scrivere i dati in un file di testo e caricarli in un database usando Oracle SQL * Loader.
Ho essenzialmente finito per rispondere ad Alex Martelli. Ecco un'implementazione più completa:
>>> from datetime import datetime
>>> d = datetime.now()
>>> d = d.replace(microsecond=0, tzinfo=None)
>>> str(d)
'2009-10-29 11:27:27'
L'unica differenza è che str (d)
è equivalente a d.isoformat ('')
.
Soluzione
isoformat funziona su datetime
istanze senza limitazione dell'intervallo:
>>> import datetime
>>> x=datetime.datetime(1865, 7, 2, 9, 30, 21)
>>> x.isoformat()
'1865-07-02T09:30:21'
Se hai bisogno di una stringa di diverso formato non è troppo difficile tagliare, tagliare e remixare i pezzi della stringa che ottieni da isoformat
, che è molto coerente ( YYYY-MM-DDTHH : MM: SS.mmmmmm
, con il punto e i seguenti microsecondi omessi se i microsecondi sono zero).
Altri suggerimenti
La sembra abbastanza chiara al riguardo:
L'intervallo esatto di anni per cui
strftime ()
varia anche tra le piattaforme. Indipendentemente dalla piattaforma, anni prima del 1900 non possono essere utilizzati.
Quindi non ci sarà una soluzione che utilizza strftime ()
. Fortunatamente, è abbastanza semplice fare questo "a mano":
>>> "%02d-%02d-%02d %02d:%02d" % (d.year,d.month,d.day,d.hour,d.minute)
'1899-01-01 00:00'
mxDateTime
può gestire date arbitrarie . I moduli time
e datetime
di Python usano i timestamp UNIX internamente, ecco perché hanno un raggio limitato.
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
Questo è dal fonte matplotlib . Potrebbe fornire un buon punto di partenza per il tuo.
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)
Questa è la funzione " " della libreria ctime (UTF). Inoltre potresti avere problemi al di sopra del 2038.