0

根據數據存儲區docs,日期時間始終以UTC存儲和返回。強制Google雲的數據存儲區日期時間默認爲UTC

但是,在雲儀表板中,我所有的日期時間都顯示在CEST中,即UTC+2

保存實體時,我不包含任何時區並使用datetime.utcnow()

更具體地講,這是我TimeZonedDateTimeProperty模型,擴展/部分壓倒一切的谷歌自己的db.DateTimeProperty

class TimeZonedDateTimeProperty(db.DateTimeProperty): 
    def __init__(self, *args, **kwargs): 
     super(TimeZonedDateTimeProperty, self).__init__(*args, **kwargs) 

    def __get__(self, model_instance, model_class): 
     """Returns the value for this property on the given model instance.""" 

     if model_instance is None: 
      return self 

     attr_to_return = None 

     try: 
      # access the db.DateTimeProperty's getter 

      attr_to_return = getattr(model_instance, super(TimeZonedDateTimeProperty, self)._attr_name()) 
     except AttributeError: 
      attr_to_return = None 

     if attr_to_return: 
      # super methods of db.DateTimeProperty will be calling this 
      # getter too and we don't wanna mess up 
      # the UTC convention when working with datetimes 

      includes_correct_caller = None 

      try: 
       # after noticing that this getter is also being called 
       # outside of user requests, inspect the caller and decide 
       # whether to offset the UTC datetime or not 

       includes_correct_caller = "main_class_name" in str(inspect.stack()[1][0].f_locals["self"].__class__) 
      except Exception: 
       includes_correct_caller = False 

      if includes_correct_caller: 
       return attr_to_return + relativedelta(hours=+2) 
      else: 
       return attr_to_return 
     else: 
      return None 

而這裏的一個子類db.Model用法的例子:

class Message(db.Model): 
    ... 
    sent = TimeZonedDateTimeProperty() 
    ... 


m = Message(... 
      sent=datetime.utcnow(), 
      ...) 
m.put() 

現在,如果我打電話在本地主機上運行的m.sent,事情按計劃進行,即sent屬性以UTC保存,並且getter返回偏移日期時間。

在現場/生產環境中,屬性爲而不是以UTC保存,因此重寫的獲取器不必要地增加2個小時。

所以:

  • 我怎樣才能迫使現場數據存儲始終使用UTC保存和服務我的日期時間是什麼時候?

  • 我的方法是否正確?假設它是,是否有一種更優雅的方式來處理GAE中的分時日期?

謝謝!

+2

關於雲儀表板,我認爲這只是一個代表性的問題。我們有(ndb)使用'ndb.DateTimeProperty(auto_add = True)'記錄時間戳記的模型;在雲儀表板中,時間戳顯示爲本地時間:2017-06-10(21:36:07.917)BST,但是如果我在遠程shell中打印時間戳,則時間與UTC相當:2017-06-10 20: 36:07.917540。 – snakecharmerb

+0

相關:https://stackoverflow.com/questions/29949938/why-do-datastore-datetimes-look-different-in-appengine-console-vs-appengine-dash –

+0

好的,儀表板的表示是可以理解的。 但它仍然好像我的getter被調用了put()或put_async() - 雖然我有一種預感,但這不是標準做法。但是對於重複+ 2小時的添加幾乎沒有任何解釋。 –

回答

1

要回答第一個問題,App Engine已經將時間存儲爲UTC。

爲了解決第二個問題,在這個問題的辦法和OP的回答將導致未來的問題:

  • 當歐洲中部夏令時間(CEST)結束,將產生不正確的價值觀和歐洲中部時間(CET)開始
  • 檢查堆棧,以避免混偏移可以不例如工作,如果Message.sent在另一個對象的put方法檢索
  • 會引起併發症,如果應用程序增長到使用更多的時區

這些問題可以通過將日期時間存儲在標準DateTimeProperty中,並在需要時將它們轉換爲可識別時區的日期時間來避免。

db docs建議爲OP的使用情況下的解決方案:

如果你只值轉換,並從一個特定的時間段,您可以 實現自定義datetime.tzinfo將值從 數據存儲轉換

實現自定義tzinfo的可能會很棘手,但tzinfos已經在dateutil包中實現。

該模型可以有一個返回時區感知日期時間的方法:

from dateutil import tz 
from google.appengine.ext import db 

class Message(db.Model): 

    sent = db.DateTimeProperty() 

    def local_sent(self, default_tz='Europe/Paris'): 
     """ 
     Returns a timezone-aware datetime for the local 
     timezone. 
     The default timezone can be overridden to support 
     other locales. 
     """ 
     utc = tz.gettz('UTC') 
     local = tz.gettz(tz) # or some other CET timezone 
     return self.sent.replace(tzinfo=utc).astimezone(local) 

用法:

m = Message(sent=datetime.datetime.utcnow()) 
m.sent 
datetime.datetime(2017, 6, 16, 18, 0, 12, 364017) 
m.local_sent() 
datetime.datetime(2017, 6, 16, 20, 0, 12, 364017, tzinfo=tzfile('/usr/share/zoneinfo/Europe/Paris')) 
m.local_sent.strftime('%Y-%m-%d %H:%M:%S.%f %z %Z') 
'2017-06-16 20:00:12.364017 +0200 CEST' 

m = Message(sent=datetime.datetime.utcnow()) 
2017-06-16 18:15:33.555208 
2017-06-16 18:15:33.555208 
m.local_sent('Asia/Beijing') 
datetime.datetime(2017, 6, 17, 2, 15, 33, 555208, tzinfo=tzfile('/usr/share/zoneinfo/Asia/Beijing')) 
m.local_sent('Asia/Beijing').strftime('%Y-%m-%d %H:%M:%S.%f %z %Z') 
'2017-06-17 02:15:33.555208 +0800 CST' 

這種方法提供了正確的夏令時的行爲,避免了潛在的脆弱的解決方法和處理大多數時區。

0

FIXED

基於一個事實,即吸氣確實被稱爲標準get要求之外,特別是在執行put(),只需觀察調用堆棧,並尋找put關鍵字。

換句話說,防止UTC時間戳修改才能正確保存在數據庫中。

... 

includes_correct_caller = None 

try: 
    _, _, _, stack_trace, _, _ = zip(*list(inspect.stack())) 
    includes_correct_caller = "put" not in stack_trace  
except Exception: 
    includes_correct_caller = False 

if includes_correct_caller: 
    return attr_to_return + relativedelta(hours=+2) 
else: 
    return attr_to_return 
0

谷歌數據存儲確實店的所有日期/ UTC中的時間(0)。但是,雲儀表板與計算機的時區保持一致,因此日期基於您的操作系統設置的時區顯示。如果您使用的是基於Window的系統,請嘗試更改時區,然後刷新儀表板。您會發現列表實體上的任何日期屬性都會更新以反映您系統的新時區。

相關問題