今天工做上遇到一個 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 後再還原回來。