今天工做上遇到一个 locale
相关的问题,关于字符串格式化的。不过让咱们先从 locale
提及。html
locale 这个单词中文翻译成地区或者地域,其实这个单词包含的意义要宽泛不少。locale 是根据计算机用户所使用的语言,所在国家或者地区,以及当地的文化传统所定义的一个软件运行时的语言环境。一般状况下它能够按照涉及使用习惯分为12大类:python
- 语言符号及其分类(LC_CTYPE) - 数字(LC_NUMBERIC) - 比较习惯(LC_COLLATE) - 时间显示格式(LC_TIME) - 货币单位(LC_MONETARY) - 信息主要是提示信息,错误信息,状态信息,标题,标签,按钮和菜单等(LC_MESSAGES) - 行么书写方式(LC_NAME) - 地址书写方式(LC_ADDRESS) - 电话号码书写方式(LC_TELEPHONE) -度量衡表达方式(LC_MEASUREMENT) - 默认纸张尺寸大小(LC_PAPER) - 对locale 自身包含信息的概述(LC_IDENTIFICATION) - 除此以外还有一个LANGUAGE参数,它与LC_MESSAGES类似
好比像下面的例子里:git
在“简体中文”环境,运行date 命令,显示的是: 2016年11月24日 星期四 22时59分26秒 CST 而在英文环境下,运行date 命令,显示的是 Thu Nov 24 23:05:12 CST 2016
简单来讲, locale
为计算机上提供了国际化和本地化转化的环境github
在Unix下能够经过命令 locale
来查看当前语言环境,个人Mac上的显示以下:shell
➜ locale LANG= LC_COLLATE="zh_CN.UTF-8" LC_CTYPE="zh_CN.UTF-8" LC_MESSAGES="zh_CN.UTF-8" LC_MONETARY="zh_CN.UTF-8" LC_NUMERIC="zh_CN.UTF-8" LC_TIME="zh_CN.UTF-8" LC_ALL="zh_CN.UTF-8"
locale值格式相似为: 语言_地区.字符集
安全
能够这样来查看系统支持locals值服务器
locale -a
能够用以下的方式来临时改变shell的locale设定:python2.7
➜ test git:(master) ✗ LC_ALL=C ➜ test git:(master) ✗ export LC_ALL ➜ test git:(master) ✗ locale LANG= LC_COLLATE="C" LC_CTYPE="C" LC_MESSAGES="C" LC_MONETARY="C" LC_NUMERIC="C" LC_TIME="C" LC_ALL="C"
设置的时候注意如下几点:函数
LANG,LC*的默认值,是最低级别的设置,若是LC*没有设置,则使用该值。相似于 LCALL阿里云
LCALL,它是一个宏,若是该值设置了,则该值会覆盖全部LC*的设置值。注意,LANG的值不受该宏影响
LCALL=C 意思是去除全部本地化的设置
python提供了 locale
这个模块,能够用来操做locale相关数据,官方文档参见这里。
其中主要的结果方法以下
import locale # 返回当前环境locale categorg相关的设定,category默认为 LC_CTYPE # LC_CTYPE 决定字符处理函数相关行为,好比 string 函数 locale.getlocale([category]) # 尝试判断默认的locale设置,而且以元组的形式返回(language code, encoding) locale.getdefaultlocale([envvars]) # 修改locale category 的设定为 locale的值, 好比locale.setlocale(locale.LC_ALL, 'C'), C 表明去除全部本地化设置 # 若是第二个参数locale没有提供,那么会返回category的设置 locale.setlocale(category[, locale]) # 不少程序会像下面这样开头,这样作会将全部的locale设置成用户默认的设置(一般是环境变量LANF的值)。 # 但setlocale() 不能在全部系统上保证线程安全性,这点要注意 import locale locale.setlocale(locale.LC_ALL, '')
当在shell里启动python repl(交互器)时,默认的环境local设置为'C', 也就是没有本地化设置,这时候能够经过 locale.getdefaultlocale()
来查看shell当前环境的locale设置, 并经过 locale.setlocale(locale.LC_ALL, '')
将python解释器的locale设置成shell环境的locale,具体事例以下:
Python 2.7.10 (default, Oct 23 2015, 19:19:21) [GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import locale >>> locale.getlocale() (None, None) >>> locale.getdefaultlocale() ('zh_CN', 'UTF-8') >>> locale.setlocale(locale.LC_ALL, '') 'zh_CN.UTF-8' >>> locale.getdefaultlocale() ('zh_CN', 'UTF-8') >>> locale.getlocale() ('zh_CN', 'UTF-8')
正所谓当局者迷,今天当我遇到一样的代码,不一样的环境(shell执行和pycharm执行)竟然有不一样的执行结果时,我百思不得其姐(嘿嘿)。
代码片断是关于 strptime
的:
import time time.strptime('Thu, 24 Nov 2016 07:01:59 GMT', '%a, %d %b %Y %H:%M:%S GMT')
其实呢,strptime或者strftime格式化参数里有一些是跟locale相关的,好比这里的 %a %b
等,因此在不对的 locale
环境下,格式化出现了错误。
能够参考下面的示例:
Python 2.7.10 (default, Oct 23 2015, 19:19:21) [GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import time >>> time.strptime('Thu, 24 Nov 2016 07:01:59 GMT', '%a, %d %b %Y %H:%M:%S GMT') time.struct_time(tm_year=2016, tm_mon=11, tm_mday=24, tm_hour=7, tm_min=1, tm_sec=59, tm_wday=3, tm_yday=329, tm_isdst=-1) >>> import locale >>> locale.setlocale(locale.LC_ALL, '') 'zh_CN.UTF-8' >>> time.strptime('Thu, 24 Nov 2016 07:01:59 GMT', '%a, %d %b %Y %H:%M:%S GMT') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/_strptime.py", line 467, in _strptime_time return _strptime(data_string, format)[0] File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/_strptime.py", line 325, in _strptime (data_string, format)) ValueError: time data 'Thu, 24 Nov 2016 07:01:59 GMT' does not match format '%a, %d %b %Y %H:%M:%S GMT' >>> time.strptime('2016 07:01:59', '%Y %H:%M:%S') time.struct_time(tm_year=2016, tm_mon=1, tm_mday=1, tm_hour=7, tm_min=1, tm_sec=59, tm_wday=4, tm_yday=1, tm_isdst=-1) >>>
用阿里云oss-python-SDK上传文件时,当我本地locale设置成 zh_CN.UTF-8
时,就回一直出问题,缘由就在于上述的 strptime
, 阿里云sdk代码片断以下:
def to_unixtime(time_string, format_string): with _STRPTIME_LOCK: return int(calendar.timegm(time.strptime(time_string, format_string)))
然而从oss服务器上得到的timestring是这样的: Thu, 24 Nov 2016 07:01:59 GMT
, 因此在个人环境里作格式化就会出错,因此我对代码作了以下修改:
def to_unixtime(time_string, format_string): with _STRPTIME_LOCK: time_locale = locale.setlocale(locale.LC_TIME) if time_locale.find('en') != 0 and time_locale != 'C': locale.setlocale(locale.LC_TIME, 'en_US') unixtime = int(calendar.timegm(time.strptime(time_string, format_string))) locale.setlocale(locale.LC_TIME, time_locale) else: unixtime = int(calendar.timegm(time.strptime(time_string, format_string))) return unixtime
在调用 strptime
这个方法前增长了兼容,先检查locale,若是不是英文类型而且不是默认的"C"类型时,将 LC_TIME
切换成英文,执行完 strptime 后再还原回来。