Python3的datetime.datetime.strftime无法接受UTF-8字符串格式。

8

Python3 datetime.datetime.strftime无法接受UTF-8字符串格式。

我的操作是:

# encoding: utf-8
import datetime

f = "%Y年%m月%d日"
now = datetime.datetime.now()
print( now.strftime(f) )

我得到的是:
D:\pytools>python a.py
Traceback (most recent call last):
  File "a.py", line 6, in <module>
    print( now.strftime(f) )
UnicodeEncodeError: 'locale' codec can't encode character '\u5e74' in position 2
: Illegal byte sequence

为什么会出现这个问题?我该如何解决?

你的Python3.3在Mac上可以运行。你使用的是哪个版本的Python? - FrostNovaZzz
变量 f 应该是 Unicode 编码,需要在前面添加 u 前缀:f = u"%Y年%m月%d日"。此外,文件的编码头不应该是这样的,据我所知应该是这样的:# -*- coding: utf-8 -*- - yedpodtrzitko
因为编码声明只需要匹配正则表达式 coding[=:]\s*([-\w.]+),所以您可以使用 utf-8 编码。 - truease.com
我在Windows 7上使用Python3.3。 - truease.com
5个回答

13

问题不在于datetime,而在于print。请参见PrintFails

啊,不完全是这样的——虽然原因相同,但在向标准输出写入Unicode时,你可能会遇到这个问题。(使用带有Python shell的IDE,例如最新版本的IDLE,则可以避免此问题。)

strftime()函数实际上是datetime.strftime()调用的一部分,它是C标准库的一部分,在Windows / MSVCRT下无法处理Unicode字符串。(尽管理论上可以通过将代码页设置为65001并使用UTF-8来解决它,但对于该代码页,C运行时存在严重的长期错误。)

在Python中的解决方法可能是在调用之后替换非ASCII字符:

strftime('%Y{0}%m{1}%d{2}').format(*'年月日')

或者避免使用strftime而自己实现。

这可能应该被视为time.strftime()中的一个错误,并通过以下方式进行修复。添加一个Python本地实现的strftime是有意义的,因为由于该功能中存在其他平台错误,他们已经不得不对strptime进行相同的操作。


我试过了,没有print语句仍然报同样的错误。 - longhua
在我的机器上,Python3的默认编码是utf-8。然而,默认的区域设置编码是cp936。我猜测这种差异导致了问题。 - longhua
这不是一个打印语句的问题。将 print( now.strftime(f) ) 改为 r = now.strftime(f) print r,你会发现异常出现在 r= now.strftime(f) 这一行。 - truease.com
我阅读了datetime.py文件并发现它调用了time.strftime函数,但是我测试后发现time.strftime存在缺陷。而且time模块是一个内置模块。现在我无能为力,只能使用一种解决方法。 - truease.com
我更改了计算机的区域设置以避免更改代码。您可以通过 locale.getdefaultlocale() 查看当前的区域设置。如果您使用的是Windows,以下链接可能会有所帮助:如何手动确定当前操作系统的CodePage和Locale如何查看和更改系统区域设置以使用我选择的语言? - Kirk
“添加一个Python本地的strftime实现是有道理的-他们已经不得不为strptime做同样的事情,因为在该功能中存在其他平台错误。” 相反,放弃那些函数,采用本地Python实现更好设计的Pythonic接口以及Pythonic命名是有意义的。 - Karl Knechtel

6
>>> now.strftime('%Y年%m月%d日 %H时%M分%S秒'.encode('unicode- 
 escape').decode()).encode().decode("unicode-escape")

'2018年04月12日 15时55分32秒'

太疯狂了,但它确实有效! - mythofechelon

1

我在Windows10上也遇到了同样的问题,解决方法如下:

import locale
locale.setlocale(locale.LC_CTYPE, 'chinese')
print(datetime.now().strftime('%Y年%m月%d日 %H时%M分%S秒'))

结果:2017年04月01日 15时56分34秒


1

我的解决方案

# -*- coding: utf-8 -*-
import datetime

now = datetime.datetime.now()
print( now )



import re

def strftime(datetimeobject, formatstring):
    formatstring = formatstring.replace("%%", "guest_u_never_use_20130416")
    ps = list(set(re.findall("(%.)", formatstring)))
    format2 = "|".join(ps)
    vs = datetimeobject.strftime(format2).split("|")
    for p, v in zip(ps, vs):
        formatstring = formatstring.replace(p, v)
    return formatstring.replace("guest_u_never_use_20130416", "%")

r = strftime(now, "%%%Y年%m月%d日 %%")
print(r)

结果是:
D:\Projects\pytools>python a.py
2013-04-16 20:14:22.518358
%2013年04月16日 %

0

对我来说它是有效的,见下文:

import datetime
from contextlib import contextmanager
import locale


@contextmanager
def locale_block(local_name: str, lc_var=locale.LC_ALL):
    org_local = locale.getlocale()
    try:
        yield locale.setlocale(lc_var, local_name)
    finally:
        locale.setlocale(lc_var, org_local)


with locale_block('zh'):
    print(datetime.datetime.now().strftime('%Y年%m月%d日'))

在离开with语句后,它将恢复区域设置的值。


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