Python3.3: 使用unicode format_spec进行.format()格式化

7
我有一个日期时间对象,并且我的用户提供自己的格式字符串来以他们喜欢的方式格式化时间。一种方法是使用 '{:...}'.format(mydatetime)
lt = time.localtime(time.time())
d = datetime. datetime.fromtimestamp(time.mktime(lt))
print(userString.format(datetime=d))

英语用户可以提供'{datetime:%B %d, %Y}',它的格式为December 24, 2013。

中文用户可以提供'{datetime:%Y年%m月%d日}'(使用YYYYMMDD格式,其中年表示年份,月表示月份,日表示日期)。

但是,在执行'{datetime:%Y年%m月%d日}'.format(datetime=d)时,Python会抛出UnicodeEncodingError错误:'locale' codec can't encode character '\u5e74' in position 2: Illegal byte sequence

我知道有一个解决方法,即让我的中文用户提供类似于'{datetime:%Y}年{datime:%m}月{datetime:%d}日'这样的格式字符串,但是不能在format_spec中显示unicode字符。如何解决这个问题?

我正在使用Windows操作系统。

谢谢


1
import sys; sys.getdefaultencoding() 的输出是什么? - Simeon Visser
在PY3中,sys.getdefaultencoding()始终为UTF-8。使用locale.getlocale()获取当前的LC_CTYPE类别区域设置,这是wcstombs使用的区域设置。 - Eryk Sun
@SimeonVisser sys.getdefaultencoding() 返回 utf-8。 - Gqqnbig
@eryksun,我是Python的新手。你是指 locale.getlocale(locale.LC_CTYPE) 吗?它返回 (None, None) - Gqqnbig
是的,我使用Windows。在 locale.setlocale(locale.LC_CTYPE, 'chinese') 之后,'{datetime:%Y年%m月%d日}' 运行良好。此外,我还可以在 format_spec 中放置日语字符。非常感谢! - Gqqnbig
1个回答

5

datetime.__format__调用datetime.strftime,它会进行一些预处理,然后调用time.strftime(CPython 3.3.3源代码)。

在Windows上,time.strftime使用C运行时的多字节字符串函数strftime而不是宽字符字符串函数wcsftime。首先,它必须根据当前区域设置编码格式字符串,通过调用PyUnicode_EncodeLocale来完成。这又调用了CRT函数wcstombs(MSDN),该函数使用当前配置的区域设置来进行LC_CTYPE类别。如果进程当前正在使用默认的"C"区域设置,则wcstombs将Latin-1(代码<256)直接转换为字节,而其他任何内容都是一个EILSEQ错误,即“非法字节序列”。

使用locale模块来设置新的区域设置。实际的区域设置名称因平台而异,但使用Microsoft的setlocale,您应该能够只设置一个语言字符串并使用给定语言的默认代码页。通常情况下,您不应该为库而破坏它,而应用程序应在启动时配置区域设置。例如:

>>> import datetime, locale

>>> oldlocale = locale.setlocale(locale.LC_CTYPE, None)
>>> oldlocale
'C'
>>> newlocale = locale.setlocale(locale.LC_CTYPE, 'chinese')

>>> d = datetime.datetime.now()
>>> '{datetime:%Y\\u5e74%m\\u6708%d\\u65e5}'.format(datetime=d)
'2013\\u5e7412\\u670825\\u65e5'

如果您希望格式化的时间使用本地特定的名称(例如月份和日期),则还需要设置LC_TIME类别:
>>> newlocale = locale.setlocale(locale.LC_TIME, 'chinese')
>>> '{datetime:%B %d, %Y}'.format(datetime=d)              
'\u5341\u4e8c\u6708 25, 2013'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接