2009-10-29 14 views
19

no me di cuenta de esto, pero parece que la función de Python strftime no es compatible con fechas anteriores al 1900:¿Hay alguna forma de utilizar una función similar a strftime para las fechas anteriores a 1900 en 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 

Estoy seguro de que podría cortar juntos algo a mí mismo para hacer esto, pero calculo es la función strftime allí por una razón (y también hay una razón por la cual no puede soportar fechas anteriores a 1900). Necesito poder admitir las fechas anteriores a 1900. Solo usaría str, pero hay demasiada variación. En otras palabras, puede o no tener microsegundos o puede tener o no una zona horaria. Hay alguna solución para esto?

Si hace la diferencia, estoy haciendo esto para poder escribir los datos en un archivo de texto y cargarlo en una base de datos utilizando Oracle SQL * Loader.

Básicamente terminé haciendo la respuesta de Alex Martelli. Aquí hay una aplicación más completa:

>>> from datetime import datetime 
>>> d = datetime.now() 
>>> d = d.replace(microsecond=0, tzinfo=None) 
>>> str(d) 
'2009-10-29 11:27:27' 

La única diferencia es que str(d) es equivalente a d.isoformat(' ').

Respuesta

15

isoformat trabajos sobre datetime casos w/o limitación de la gama:

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

Si necesita una cadena diferente formato que no es demasiado difícil de cortar, los dados y las piezas remezcla de la cadena que recibe desde isoformat, que es muy consistente (YYYY-MM-DDTHH:MM:SS.mmmmmm, con el punto y los microsegundos siguientes omitidos si los microsegundos son cero).

+0

Esto es básicamente lo que terminé haciendo. –

1

Esta es la "característica" de la biblioteca ctime (UTF). Es posible que además problema anterior 2038.

+0

Ya veo. Entonces, ¿el problema es que la fecha no puede estar afuera más o menos 32 bits? –

+1

Exactamente, no hay una solución directa. – bua

11

El documentation seems pretty clear about this:

El rango exacto de años que strftime() obras también varía a través de plataformas. Independientemente de la plataforma, años antes de 1900 no pueden ser utilizados.

Así que no va a haber una solución que use strftime(). Afortunadamente, es bastante sencillo de hacer esto "a mano":

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

Eso realmente no me ayuda ... –

+1

Han publicado código de ejemplo que muestra por qué realmente no necesita strftime(). –

3

mxDateTime puede manejar fechas arbitrarias. Los módulos time y datetime de Python usan marcas de tiempo UNIX internamente, por eso tienen un 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 
+0

Urgh ... Justo cuando pensaba que era capaz de eliminar las cosas mx * como una dependencia cuando no estamos usando mxODBC. :-( –

3

Esto es del matplotlib source. Podría proporcionar un buen punto de partida para lanzar el suyo.

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, derivado de mi contribución a matplotlib.* sniff * :) –

+0

@dalke, eso es increíble. Un pequeño mundo aquí en Stack Overflow. – Mark

Cuestiones relacionadas