2009-10-29 8 views
19

non mi rendevo conto questo, ma a quanto pare la funzione di Python strftime non supporta le date prima del 1900:C'è un modo per usare una funzione simile a strftime per date precedenti al 1900 in Python?

>>> 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 che avrei potuto incidere qualcosa insieme a me stesso di fare questo, ma immagino che la funzione è strftime c'è una ragione (e c'è anche una ragione per cui non può supportare le date precedenti al 1900). Devo essere in grado di supportare le date prima del 1900. Vorrei solo usare str, ma c'è troppa variazione. In altre parole, potrebbe avere o meno microsecondi o potrebbe avere o meno un fuso orario. c'è qualche soluzione a questo?

Se fa la differenza, lo sto facendo in modo che possa scrivere i dati in un file di testo e caricarlo in un database utilizzando Oracle SQL * Loader.

In sostanza ho finito per fare la risposta di 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(' ').

risposta

15

isoformat opere datetime casi w/o limitazione della gamma:

>>> import datetime 
>>> x=datetime.datetime(1865, 7, 2, 9, 30, 21) 
>>> x.isoformat() 
'1865-07-02T09:30:21' 

Se avete bisogno di una stringa differente formato non è troppo difficile da tagliare, dadi e pezzi remix della stringa che si ottiene da isoformat, che è molto coerente (YYYY-MM-DDTHH:MM:SS.mmmmmm, con il punto e i seguenti microsecondi omessi se i microsecondi sono pari a zero).

+0

Questo è fondamentalmente quello che ho finito per fare. –

1

Questa è la "funzione" della libreria ctime (UTF). Inoltre si può avere problema di cui sopra 2038.

+0

Vedo. Quindi il problema è che la data non può essere al di fuori più o meno 32 bit? –

+1

Esattamente, nessuna soluzione diretta. – bua

11

Il documentation seems pretty clear about this:

La gamma esatto di anni per i quali strftime() lavori varia anche attraverso le piattaforme. Indipendentemente dalla piattaforma, anni prima del 1900 non possono essere utilizzati.

Quindi non ci sarà una soluzione che utilizza strftime(). Per fortuna, è abbastanza semplice per farlo "a mano":

>>> "%02d-%02d-%02d %02d:%02d" % (d.year,d.month,d.day,d.hour,d.minute) 
'1899-01-01 00:00' 
+1

Questo non mi aiuta molto ... –

+1

Ho pubblicato un codice di esempio che mostra perché non hai davvero bisogno di strftime(). –

3

mxDateTime in grado di gestire le date arbitrarie. I moduli Python time e datetime usano internamente i timestamp UNIX, 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 
+0

Urgh ... Proprio quando pensavo di essere in grado di rimuovere le cose mx * come dipendenza quando non usiamo mxODBC. :-( –

3

Questo è dallo matplotlib source. Potrebbe fornire un buon punto di partenza per il tuo personale.

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) 
+2

Ahh, derivato dal mio contributo a matplotlib.* sniff * :) –

+0

@dalke, è fantastico. Piuttosto un piccolo mondo qui su Stack Overflow. – Mark

Problemi correlati