我想创建一个“unicode三明治”,其中包含一些日期/时间值,并且与区域设置无关。对于初学者来说,术语unicode三明治描述了从字节转换为unicode并返回程序边界的做法,即外部的字节和内部的unicode。
我今天早上看了Ned Batchelder's excellent video on unicode,并试图将我的一些代码转换为与他明智的建议一致。
我遇到的问题是我无法确定如何确定str(date)
或其等价物返回的字符串的编码。我的想法是做这样的事情,为了清晰起见,有点冗长:
date_str_encoding = some_magical_method_I_have_yet_to_discover()
date = datetime.datetime(2013, 10, 16).date()
date_str = date.strftime('%A %B %d, &Y') # perhaps 'Sábado Octubre 19, 2013'
date_unicode = date_str.decode(date_str_encoding)
Ned的unicode“生活中的事实”之一是“你无法推断出字节的编码。你必须被告知或者你必须猜测。”不幸的是,我在日期时间的Python文档中找不到特定的细节。
另一篇SO帖子提到了locale.getlocale()的使用,但是我返回(None,None)。
如何在运行时可靠地发现Python日期字符串的编码?
答案 0 :(得分:4)
在CPython 2.7中,datetime.date.strftime
是time.strftime
的包装器,而后者又是posix strftime(3)
的包装器。原则上,这取决于LC_TIME
的区域设置类别。因此,您正在寻找的是:
import locale
def date_format_encoding():
return locale.getlocale(locale.LC_TIME)[1] or locale.getpreferredencoding()
以下是datetime.date.__str__
的解构,在编辑问题之前有相关内容。
在CPython 2.7中,datetime.date.__str__
在C中实现,它是:
static PyObject *
date_str(PyDateTime_Date *self)
{
return PyObject_CallMethod((PyObject *)self, "isoformat", "()");
}
datetime.date.isoformat
依次在C中实现:
static char *
isoformat_date(PyDateTime_Date *dt, char buffer[], int bufflen)
{
int x;
x = PyOS_snprintf(buffer, bufflen,
"%04d-%02d-%02d",
GET_YEAR(dt), GET_MONTH(dt), GET_DAY(dt));
assert(bufflen >= x);
return buffer + x;
}
基本上,str(datetime.date)
返回的字节绝不是数字和“ - ”的ascii代码以外的任何字节。 总是正确地说:
str(my_date).decode('ascii')
答案 1 :(得分:2)
为什么不完全跳过date_str
? unicode
构造函数接受日期对象。
>>> date_unicode = unicode(date)
>>> date_unicode
u'2013-10-16'
在内部,这会调用str(date)
。然后它解码这些字节。所以它相当于显式创建字节然后解码它们,但在我看来更清楚阅读。并且值得养成使用unicode
而不是显式使用str
和decode
的习惯,因为某些对象将定义一个__unicode__
方法,该方法可以返回规范的Unicode表示而不进行完全通过__str__
。日期没有。
文档说:
对于日期d,str(d)相当于d.isoformat()。
定义为:
返回表示ISO 8601格式的日期字符串'YYYY-MM-DD'。例如,date(2002,12,4).isoformat()=='2002-12-04'。
所以那也是ASCII。如果您的默认编码无法解码ASCII,那么您必须学习如何处理这种情况。