有没有办法在 Python 中对 1900 年之前的日期使用类似 strftime 的函数?
Posted
技术标签:
【中文标题】有没有办法在 Python 中对 1900 年之前的日期使用类似 strftime 的函数?【英文标题】:Is there any way to use a strftime-like function for dates before 1900 in Python? 【发布时间】:2010-12-11 06:24:00 【问题描述】:我没有意识到这一点,但显然 Python 的 strftime
函数不支持 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
我确信我可以自己拼凑一些东西来做到这一点,但我认为strftime
函数的存在是有原因的(而且它不能支持 1900 年之前的日期也是有原因的)。我需要能够支持 1900 年之前的日期。我只使用str
,但变化太多。换句话说,它可能有也可能没有微秒,或者它可能有也可能没有时区。有什么解决办法吗?
如果有影响,我这样做是为了将数据写入文本文件并使用 Oracle SQL*Loader 将其加载到数据库中。
我基本上最终做了 Alex Martelli 的回答。这是一个更完整的实现:
>>> from datetime import datetime
>>> d = datetime.now()
>>> d = d.replace(microsecond=0, tzinfo=None)
>>> str(d)
'2009-10-29 11:27:27'
唯一的区别是str(d)
等价于d.isoformat(' ')
。
【问题讨论】:
【参考方案1】:这是 ctime 库 (UTF) 的“功能”。 另外你可能在2038以上有问题。
【讨论】:
我明白了。所以问题是日期不能在正负 32 位之外? 没错,没有直接的解决方案。【参考方案2】:documentation seems pretty clear about this:
strftime()
工作的确切年份范围也因平台而异。无论平台如何,都不能使用 1900 年之前的年份。
所以不会有使用strftime()
的解决方案。幸运的是,“手动”执行此操作非常简单:
>>> "%02d-%02d-%02d %02d:%02d" % (d.year,d.month,d.day,d.hour,d.minute)
'1899-01-01 00:00'
【讨论】:
已经发布了这样的示例代码,说明了为什么你并不真正需要 strftime()。【参考方案3】:mxDateTime
可以处理任意日期。 Python 的 time
和 datetime
模块在内部使用 UNIX 时间戳,这就是它们范围有限的原因。
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
【讨论】:
呃...就在我认为当我们不使用 mxODBC 时我能够将 mx* 东西作为依赖项删除时。 :-(【参考方案4】:这是来自matplotlib source。可以为自己滚动提供一个很好的起点。
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)
【讨论】:
啊,源于我对 matplotlib 的贡献。 嗅探 :) @dalke,太棒了。 Stack Overflow 上的世界很小。【参考方案5】:isoformat 适用于 datetime
实例,没有范围限制:
>>> import datetime
>>> x=datetime.datetime(1865, 7, 2, 9, 30, 21)
>>> x.isoformat()
'1865-07-02T09:30:21'
如果您需要不同格式的字符串,则对从isoformat
获得的字符串进行切片、切块和重新混合并不难,这非常一致(YYYY-MM-DDTHH:MM:SS.mmmmmm
,如果微秒,则省略点和后面的微秒是零)。
【讨论】:
这基本上就是我最终要做的。以上是关于有没有办法在 Python 中对 1900 年之前的日期使用类似 strftime 的函数?的主要内容,如果未能解决你的问题,请参考以下文章
在 Python 中对 subprocess.PIPE 进行非阻塞读取
在 Python 中对 subprocess.PIPE 进行非阻塞读取
在 Python 中对 subprocess.PIPE 进行非阻塞读取
在 Python 中对 subprocess.PIPE 进行非阻塞读取