很多人掉進了odoo的時間坑
odoo約定關於日期的數據,存放在數據庫時,以 utc0 時區也就是不帶時區存放,應用程序讀取日期展示日期時,轉換成用戶的時區展示。用戶的時區通過context傳遞。
odoo本身能很好的處理 這, 例如 每個模型都自帶的 create_date / write_date
代碼
它在處理這些的時候,會 使用 utc-0 時區 存數據庫。
在 web client 以及 其他界面 展示這些日期 信息時, 能 根據用戶的 時區, 例如 上海時區 【東8區】
如果用戶的時區 切換到 其他, 例如 fiji [ utc-12 區] 與 上海時間 相差 4小時。
展示的時間 為 當地時間, 在上海時間基礎上 加 4小時, 所以是 5/13 01:46
而訂單存放數據庫的 時間是 utc-0
但是 某些應用 在往數據庫存 這些時間的時候, 有的沒有處理好。
例如,stock picking 的字段 date_done是分揀完成時的日期,分揀完成時讀取系統時間,此時本應該轉換為 utc-0 並寫入數據庫作為 date_done.. 的數據
但是 odoo sa的程序員在寫這個邏輯的時候,並沒有轉換為utc-0
代碼
self.write(cr, uid, [picking.id], {'date_done': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}, context=context)
time.strftime() 讀取odoo服務器的當前時間【帶時區】,如果服務器運行在 utc-8 ,則數據庫存的日期也是 with utc-8,也就是下圖示的前 2筆交易[ id = 15, 16]
這樣,當用戶從應用程序讀取改數據時,在此數據基礎上 +時差,變成了。
造成時差 8 小時
原因是, odoo代碼里面的相關日期處理是不正確的,沒有遵循在存數據前去掉時區信息。
要解決這個問題, 2個 方式
1, 遵守約定,存數據庫時使用 utc-0
例如 stock 有問題部分的代碼修改,已經提交 PR [ https://github.com/odoo/odoo/pull/12063 ]
@@ -506,7 +506,7 @@ def _quant_create(self, cr, uid, qty, move, lot_id=False, owner_id=False, src_pa
'qty': float_round(qty, precision_rounding=rounding),
'cost': price_unit,
'history_ids': [(4, move.id)],
- 'in_date': datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT),
+ 'in_date': datetime.utcnow().strftime(DEFAULT_SERVER_DATETIME_FORMAT),
'company_id': move.company_id.id,
'lot_id': lot_id,
'owner_id': owner_id,
2, 使用workaround 解決此問題,那就是將 odoo 服務器的時區設置為 utc -0
使用 dpkg-reconfigure tzdata 設置時區
設置為 utc-0 之后的測試
服務器設置為 utc-0 之后, datetime.datetime.now() 和 datetime.datetime.utcnow() 以及 time 獲取的時間都是不帶時區信息,這樣就能避免時差問題。