¿Hay alguna forma de usar una función similar a strftime para fechas anteriores a 1900 en Python?

StackOverflow https://stackoverflow.com/questions/1643967

Pregunta

No me di cuenta de esto, pero aparentemente la función strftime de Python no admite fechas anteriores a 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

Estoy seguro de que podría hackear algo para hacer esto, pero creo que la función strftime está ahí por una razón (y también hay una razón por la que no puede admitir 1900 fechas). Necesito poder admitir fechas anteriores a 1900. Solo usaría str , pero hay demasiada variación. En otras palabras, puede o no tener microsegundos o puede o no tener 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 cargarlos en una base de datos usando Oracle SQL * Loader.

Básicamente terminé haciendo la respuesta de Alex Martelli. Aquí hay una implementació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 ('') .

¿Fue útil?

Solución

isoformat funciona en instancias de fecha y hora sin limitación de rango:

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

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

Otros consejos

La la documentación parece bastante clara al respecto:

  

El rango exacto de años para el que strftime () también varía entre plataformas. Independientemente de la plataforma, años antes de 1900 no se pueden usar.

Entonces no habrá una solución que use strftime () . Afortunadamente, es bastante sencillo hacer esto "a mano":

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

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

Esto es de fuente de matplotlib . Podría proporcionar un buen punto de partida para rodar 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)

Esta es la " característica " de la biblioteca ctime (UTF). También es posible que tenga un problema por encima de 2038.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top