Slide 1

Slide 1 text

Djangoでタイムゾーンと うまく付き合う 2019/11/13 Stapy @mizzsugar0425

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

しれっと使ってる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/

Slide 5

Slide 5 text

なぜPython標準ライブラリの datetime.datetime.now()ではないの?

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

内部ではどうなっているの? >>> 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って!?

Slide 10

Slide 10 text

前提知識: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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

内部的な話① ● テンプレート上やフォームではタイムゾーンが現地のawareなdatetimeオブジェ クト ex:2019年10月10日 19時0分0秒, datetime.datetime(2019, 10, 10, 19, 0, 0, tzinfo=) ● モデルのインスタンスのpublished_dateアトリビュートを取り出すとタイムゾーン がUTCのawareなdatetimeオブジェクト ex: datetime.datetime(2019, 10, 10, 10, 0, 0, tzinfo=) ● データベース上ではタイムゾーンなしの時間(値としてはUTCでの時間) ex:2019-10-10 10:00:00 ※PostgreSQLだと2019-10-10 10:00:00+00

Slide 13

Slide 13 text

内部的な話② ● Djangoでは、タイムゾーンサポートを有効にした場合、datetimeオブジェクトは タイムゾーンがsettings.pyのTIME_ZONEで指定した箇所のawereなdatetime オブジェクトとして処理される ● 内部的な処理にはタイムゾーンがUTCのawareなdatetimeオブジェクトを使い、 エンドユーザー入出力を行うレイヤー(テンプレートやフォームなど)では現地時 間でやり取りする仕組み ● 内部処理にタイムゾーンがUTCのdatetimeオブジェクトを使うと、複数のタイム ゾーンに柔軟かつ安全に変換できるのが良いという思想

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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=)

Slide 16

Slide 16 text

USE_TZ=Trueでnativeなオブジェクトを使うと RuntimeWarning: DateTimeField received a naive datetime * to while time zone support is active. Djangoから「タイムゾーンサポートが有効な時にnativeなdatetimeオブジェク トを使わないでください」と注意されます。

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

もっと詳しくはブログで! https://mizzsugar.hatenablog.com/entry/2019/11/07/094230 「テンプレートでは日本時間が表示さ れるのがわかった!では APIでは?」 などなど具体的な話も書きました。

Slide 20

Slide 20 text

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