有人能解释在Python中格式化日期时间字符串的最佳方法,其中日期值在1900年之前吗? strftime
要求的日期晚于1900年。
答案 0 :(得分:4)
这有点麻烦,但它有效(至少在稳定版本的python中):
>>> ts = datetime.datetime(1895, 10, 6, 16, 4, 5)
>>> '{0.year}-{0.month:{1}}-{0.day:{1}} {0.hour:{1}}:{0.minute:{1}}'.format(ts, '02')
'1895-10-06 16:04'
请注意str
仍会生成可读字符串:
>>> str(ts)
'1895-10-06 16:04:05'
修改强>
最接近模拟默认行为的方法是对字典进行硬编码,例如:
>>> d = {'%Y': '{0.year}', '%m': '{0.month:02}'} # need to include all the formats
>>> '{%Y}-{%m}'.format(**d).format(ts)
'1895-10'
您需要使用简单的正则表达式将所有格式说明符括在花括号中:
>>> re.sub('(%\w)', r'{\1}', '%Y-%m-%d %H sdf')
'{%Y}-{%m}-{%d} {%H} sdf'
最后我们得到了简单的代码:
def ancient_fmt(ts, fmt):
fmt = fmt.replace('%%', '%')
fmt = re.sub('(%\w)', r'{\1}', fmt)
return fmt.format(**d).format(ts)
def main(ts, format):
if ts.year < 1900:
return ancient_format(ts, fmt)
else:
return ts.strftime(fmt)
其中d
是一个全局字典,其键与strftime
table中的某些说明符相对应。
编辑2
澄清一下:这种方法仅适用于以下说明符:%Y, %m, %d, %H, %M, %S, %f
,即那些数字,如果您需要文本信息,最好使用babel或任何其他解决方案。
答案 1 :(得分:1)
babel
国际化图书馆似乎没有任何问题。请参阅babel.dates
的{{3}}
答案 2 :(得分:1)
日历每400年完全相同。因此,在调用year >= 1900
之前,将年份更改为datetime.strftime()
的倍数就足够了。
代码显示了这种方法存在的问题:
#/usr/bin/env python2.6
import re
import warnings
from datetime import datetime
def strftime(datetime_, format, force=False):
"""`strftime()` that works for year < 1900.
Disregard calendars shifts.
>>> def f(fmt, force=False):
... return strftime(datetime(1895, 10, 6, 11, 1, 2), fmt, force)
>>> f('abc %Y %m %D')
'abc 1895 10 10/06/95'
>>> f('%X')
'11:01:02'
>>> f('%c') #doctest:+NORMALIZE_WHITESPACE
Traceback (most recent call last):
ValueError: '%c', '%x' produce unreliable results for year < 1900
use force=True to override
>>> f('%c', force=True)
'Sun Oct 6 11:01:02 1895'
>>> f('%x') #doctest:+NORMALIZE_WHITESPACE
Traceback (most recent call last):
ValueError: '%c', '%x' produce unreliable results for year < 1900
use force=True to override
>>> f('%x', force=True)
'10/06/95'
>>> f('%%x %%Y %Y')
'%x %Y 1895'
"""
year = datetime_.year
if year >= 1900:
return datetime_.strftime(format)
# make year larger then 1900 using 400 increment
assert year < 1900
factor = (1900 - year - 1) // 400 + 1
future_year = year + factor * 400
assert future_year > 1900
format = Specifier('%Y').replace_in(format, year)
result = datetime_.replace(year=future_year).strftime(format)
if any(f.ispresent_in(format) for f in map(Specifier, ['%c', '%x'])):
msg = "'%c', '%x' produce unreliable results for year < 1900"
if not force:
raise ValueError(msg + " use force=True to override")
warnings.warn(msg)
result = result.replace(str(future_year), str(year))
assert (future_year % 100) == (year % 100) # last two digits are the same
return result
class Specifier(str):
"""Model %Y and such in `strftime`'s format string."""
def __new__(cls, *args):
self = super(Specifier, cls).__new__(cls, *args)
assert self.startswith('%')
assert len(self) == 2
self._regex = re.compile(r'(%*{0})'.format(str(self)))
return self
def ispresent_in(self, format):
m = self._regex.search(format)
return m and m.group(1).count('%') & 1 # odd number of '%'
def replace_in(self, format, by):
def repl(m):
n = m.group(1).count('%')
if n & 1: # odd number of '%'
prefix = '%'*(n-1) if n > 0 else ''
return prefix + str(by) # replace format
else:
return m.group(0) # leave unchanged
return self._regex.sub(repl, format)
if __name__=="__main__":
import doctest; doctest.testmod()
答案 3 :(得分:1)
为了好玩,我非常关注这个解决方案。
a = datetime.datetime(1322, 10, 10)
# %Y%m%d
''.join(map(lambda x: '{:02}'.format(getattr(a, x)), ('year', 'month', 'day')))
# %Y-%m-%d
'-'.join(map(lambda x: '{:02}'.format(getattr(a, x)), ('year', 'month', 'day')))
# %Y%m%d%H%M%S
''.join(map(lambda x: '{:02}'.format(getattr(a, x)), ('year', 'month', 'day', 'hour', 'minute', 'second')))