I didn't realize this, but apparently Python's strftime
function doesn't support dates before 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
I'm sure I could hack together something myself to do this, but I figure the strftime
function is there for a reason (and there also is a reason why it can't support pre-1900 dates). I need to be able to support dates before 1900. I'd just use str
, but there's too much variation. In other words, it may or may not have microseconds or it may or may not have a timezone. Is there any solution to this?
If it makes a difference, I'm doing this so that I can write the data to a text file and load it into a database using Oracle SQL*Loader.
I essentially ended up doing Alex Martelli's answer. Here's a more complete implementation:
>>> from datetime import datetime
>>> d = datetime.now()
>>> d = d.replace(microsecond=0, tzinfo=None)
>>> str(d)
'2009-10-29 11:27:27'
The only difference is that str(d)
is equivalent to d.isoformat(' ')
.
isoformat works on datetime
instances w/o limitation of range:
>>> import datetime
>>> x=datetime.datetime(1865, 7, 2, 9, 30, 21)
>>> x.isoformat()
'1865-07-02T09:30:21'
If you need a different-format string it's not too hard to slice, dice and remix pieces of the string you get from isoformat
, which is very consistent (YYYY-MM-DDTHH:MM:SS.mmmmmm
, with the dot and following microseconds omitted if microseconds are zero).
The documentation seems pretty clear about this:
The exact range of years for which strftime()
works also varies across platforms. Regardless of platform, years before 1900 cannot be used.
So there isn't going to be a solution that uses strftime()
. Luckily, it's pretty straightforward to do this "by hand":
>>> "%02d-%02d-%02d %02d:%02d" % (d.year,d.month,d.day,d.hour,d.minute)
'1899-01-01 00:00'
mxDateTime
can handle arbitrary dates. Python's time
and datetime
modules use UNIX timestamps internally, that's why they have limited range.
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
This is from the matplotlib source. Could provide a good starting point for rolling your own.
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)
This is the "feature" of the ctime library (UTF).
Also You may have problem above 2038.