$30 off During Our Annual Pro Sale. View Details »

DjangogirlsTutorialに出てくるtimezone.nowの秘密

mizzsugar
November 16, 2019

 DjangogirlsTutorialに出てくるtimezone.nowの秘密

mizzsugar

November 16, 2019
Tweet

More Decks by mizzsugar

Other Decks in Programming

Transcript

  1. DjangogirlsTutorialに出てくる
    timezone.nowの秘密
    2019/11/16 Djangogirls
    @mizzsugar0425

    View Slide

  2. お前、誰よ
    ● みずきと申します。
    ● やっていること↓
    ○ 昼:データ分析のデータ基盤のデータマネジメント (GCP: 特にBigQuery)
    ○ 夜:PythonでWebアプリ開発(Pyramid, PostgreSQL, Nuxt.js, TypeScript)
    ○ つい最近まで仕事で Djagoいじってたので趣味で Django触ったりもします
    ○ Twitter -> @mizzsugar0425
    ● コーヒーと自転車が好き

    View Slide

  3. DjangogirlsTutorialの復習をしていたときのこと

    View Slide

  4. しれっと使ってるdjango.utils.timezone.now
    from django.conf import settings
    from django.db import models
    from django.utils import timezone
    class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
    title = models.CharField(max_length=200)
    text = models.TextField()
    created_date = models.DateTimeField(default=timezone.now)
    published_date = models.DateTimeField(blank=True, null=True)
    def publish(self):
    self.published_date = timezone.now()
    self.save()
    https://tutorial.djangogirls.org/ja/django_models/
    timezone.nowは
    現在の日時を返すよ

    View Slide

  5. なぜPython標準ライブラリの
    datetime.datetime.nowではないの?
    datetime.datetime.nowも
    現在の日時を返すのに!!

    View Slide

  6. 秘密はここにあった!
    USE_TZ = True
    settings.py

    View Slide

  7. USE_TZ=Trueだとタイムゾーンサポートが有効
    今19時
    だよー
    今10時
    だよー

    View Slide

  8. タイムゾーンサポートがあるなら
    settings.pyで TIMEZONE = ‘Asia/Tokyo’と設定している場合・・・
    ● テンプレート上で日本時間を表示してくれて便利!
    ● settings.pyのTIMEZONEを変更したらその場所の現地時間を表示
    ● 複数のタイムゾーンを使う場合、どのタイムゾーンの時間を表示するか設定す
    ればどのタイムゾーンの時間を表示するかそれぞれ振り分けてくれる※
    ※公式ドキュメントにタイムゾーンを選択して表示するための実装例があります ↓
    https://docs.djangoproject.com/ja/2.2/topics/i18n/timezones/#selecting-the-current-time-zone

    View Slide

  9. 内部ではどうなっているの?
    >>> from django.contrib.auth.models import User
    >>> from blog.models import Post
    >>>
    >>> author = User.objects.create(username='dummy', email='[email protected]')
    >>> post = Post.objects.create(
    author=author,
    title='dummy',
    text='dummy'
    )
    >>> post.publish() # 日本時間で2019/10/10 19:00:00に実行
    >>> post.published_date
    datetime.datetime(2019, 10, 10, 10, 0, 0, tzinfo=)
    19時じゃない!
    UTCって!?
    を実行したら・・・
    python manage.py shell

    View Slide

  10. 前提知識:nativeとawareという概念
    ざっくりPythonでは
    日時を扱うdatetimeモジュールのdatetimeオブジェクトを
    ● タイムゾーンなしのdatetimeオブジェクトはnative
    ex: datetime.datetime(2019, 10, 10, 19, 0, 0)
    ● タイムゾーンありのdatetimeオブジェクトはaware
    ex: datetime.datetime(2019, 10, 10, 19, 0, 0, tzinfo=)
    と分けている
    もっと詳しい説明は公式ドキュメントで ↓
    https://docs.python.org/ja/3/library/datetime.html#aware-and-naive-objects

    View Slide

  11. UTCとは
    ● 協定世界時(Coordinated Universal Time)のこと
    ● 今の世界で標準時として使っている時間のこと
    ● 日本の場合だと、世界の標準時間より9時間早い
    https://wa3.i-3-i.info/word11831.html

    View Slide

  12. 内部的な話
    使う場所 表示形式
    表示例
    (日本時間2019/10/10 19時を例に)
    テンプレート・フォーム 現地時間(日本なら日本時間)
    テンプレート:2019年10月10日 19時0分0秒
    フォーム: datetime.datetime(2019, 10, 10,
    19, 0, 0, tzinfo=JST+9:00:00 STD>)
    内部の処理 UTC時間
    datetime.datetime(2019, 10, 10, 10, 0, 0,
    tzinfo=)
    データベース
    タイムゾーンなしの時間
    (値としてはUTCでの時間)
    2019-10-10 10:00:00 ※PostgreSQLだと
    2019-10-10 10:00:00+00

    View Slide

  13. 1つのタイムゾーンでしか使わなくても
    ● native -> awareに変換した際に意図しない値に変換してしまうバグを防げる
    ● Djangoがawareなdatetimeオブジェクトを想定している処理でnativeなオブジェ
    クトを使うことによるバグを防げる
    ● django-admin startprojectコマンドで作られるプロジェクトでタイムゾーンサ
    ポートありになっていることからもタイムゾーンサポートありの方がいいと主張し
    ていることがうかがえる

    View Slide

  14. datetime.datetime.nowの話に戻ると・・・
    >>> from django.utils import timezone
    >>> import datetime
    >>>
    >>> from django.utils import timezone
    >>>
    >>> # nativeなdatetimeオブジェクト
    >>> datetime.datetime.now()
    datetime.datetime(2019, 11, 12, 18, 0, 39, 452139)
    >>>
    >>> # タイムゾーンがUTCであるawareなdatetimeオブジェクト
    >>> timezone.now()
    datetime.datetime(2019, 11, 12, 9, 0, 46, 708708, tzinfo=)

    View Slide

  15. USE_TZ=Trueでnativeなオブジェクトを使うと
    RuntimeWarning: DateTimeField received a naive datetime * to while time zone support is
    active.
    Djangoから「タイムゾーンサポートが有効な時にnativeなdatetimeオブジェク
    トを使わないでください」と注意されます。
    エラーやワーニングは意地悪じゃなくて
    安全なシステムを作るための優しさで
    出来ているよ。

    View Slide

  16. つまりdatetime.datetime.nowは使わない訳は
    タイムゾーンサポートが有効な設定をしているから
    使っても動きはするけれども native -> awareの変換周りで苦労するやも

    View Slide

  17. まとめ
    ● Pythonのdatetimeオブジェクトにはnativeとawareという概念があり、前者
    がタイムゾーンなしで後者がタイムゾーンありの日時(ざっくり)
    ● Djangoではタイムゾーンサポートを有効にした方が安全
    ● タイムゾーンサポートを有効にした場合、Djangoでは内部的な処理ではタ
    イムゾーンがUTCの日時を使い、画面やフォームで現地時間に柔軟に変
    換できるようにしている
    ● エラーやワーニングは意地悪じゃなくて優しさ

    View Slide

  18. ありがとうございました!

    View Slide