Slide 1

Slide 1 text

グローバル化はなぜ 日時処理問題を 引き起こすのか Titledby ホッテントリメーカー @atsukanrock 2013/10/26 C#ユーザー会

Slide 2

Slide 2 text

@atsukanrock http://d.hatena.ne.jp/atsukanrock/ Enterprise Application Architect になりたい DDD Lover

Slide 3

Slide 3 text

@atsukanrock http://d.hatena.ne.jp/atsukanrock/ Enterprise Application Architect になりたい DDD Lover http://jigokuno.com/?eid=162

Slide 4

Slide 4 text

ゴール

Slide 5

Slide 5 text

この辺を伝えたい: • 時差とは? • タイムゾーンとは? • UTC とは? • 夏時間とは? • .NET での日時処理

Slide 6

Slide 6 text

時差

Slide 7

Slide 7 text

外資系あるある

Slide 8

Slide 8 text

ピンチ!! 外人からメール来た!!

Slide 9

Slide 9 text

トレーニングのお誘いかー 28 日の 7 時から… もー!はえーよー!!

Slide 10

Slide 10 text

ε-(´∀`*)ホッ 解読成功♪

Slide 11

Slide 11 text

ファッ!?

Slide 12

Slide 12 text

7 時じゃなくて 23 時!?

Slide 13

Slide 13 text

時差のせいです。

Slide 14

Slide 14 text

時差 アメリカ西海岸では 7:00 東京では 23:00 カリフォルニアとか

Slide 15

Slide 15 text

タイムゾーン 男闘呼組じゃないよ

Slide 16

Slide 16 text

東京の僕たちが 23時に酒を飲んでいる頃 California のCharles は 7 時にBaconEggの Breakfast をEating

Slide 17

Slide 17 text

僕たちは東京標準時 (Tokyo Standard Time (UTC+9)) に生きていて Charles は太平洋夏時間 (Pacific Daylight Time (UTC-7)) に生きている

Slide 18

Slide 18 text

タイムゾーンとはこの: •東京標準時 •太平洋夏時間 とかのことで、 タイムゾーンが違うと 同じ瞬間なのに時刻が違う

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

タイムゾーンあるある

Slide 21

Slide 21 text

I永さん: 2013/10/26 13:00から C#ユーザー会やります!!

Slide 22

Slide 22 text

Charles: Hey, どのTime Zone だい?

Slide 23

Slide 23 text

ただ「2013/10/25 13:00」 と言っても どのタイムゾーンかによって どの瞬間かが異なる

Slide 24

Slide 24 text

様々なタイムゾーンの 基準になる時間が ないと何かと不便

Slide 25

Slide 25 text

そこで考えだされたのがUTC 1963年発足らしい

Slide 26

Slide 26 text

すべてのタイムゾーンは UTC を基準にして 何時間進んでいるか or 何時間遅れているか で表される

Slide 27

Slide 27 text

東京標準時:UTC+9 太平洋夏時間:UTC-7 進んでる 遅れてる

Slide 28

Slide 28 text

プログラムの世界では UTCのおかげで とても楽になる

Slide 29

Slide 29 text

Charles (非UTC Ver.): Tokyo を9am にDeparture して California に7am にArrive したんだよ 何時間かかったか 分からない

Slide 30

Slide 30 text

Charles (UTC Ver.): Tokyo を12am にDeparture して California に2PM にArrive したんだよ 14時間かかったんだね おつかれさま

Slide 31

Slide 31 text

時刻を全て UTC で表せば 瞬間に基づく: •足し算や引き算 •比較 •並べ替え が簡単になる

Slide 32

Slide 32 text

lヽ ノ l l l l ヽ ヽ )'ーーノ( | | | 、 / l| l ハヽ |ー‐''"l / U | | |/| ハ / / ,/ /|ノ /l / l l l| l U ヽ l ・ i´ | ヽ、| |r|| | //--‐'" `'メ、_lノ| / ・ / | T l トー-トヽ| |ノ ''"´` rー-/// | T | | ・ |/ | l ||、 ''""" j ""''/ | |ヽl ・ | | C | | l | ヽ, ― / | | l C | | !! | / | | | ` ー-‐ ' ´|| ,ノ| || !! | ノー‐---、,| / │l、l |レ' ,ノノ ノハ、_ノヽ / / ノ⌒ヾ、 ヽ ノハ, | ,/ ,イーf'´ /´ \ | ,/´ |ヽl | /-ト、| ┼―- 、_ヽメr' , -=l''"ハ | l ,/ | ヽ \ _,ノーf' ´ ノノ ヽ | | 、_ _ ‐''l `ー‐―''" ⌒'ー--‐'´`ヽ、_ _,ノ ノ  ̄ ̄ | /

Slide 33

Slide 33 text

夏時間

Slide 34

Slide 34 text

Charles: Listen してくれ、 TodayからDSTなんだ。

Slide 35

Slide 35 text

DST: Daylight Saving Time •日本語では夏時間 •先ほどから登場している「太平 洋夏時間」は「太平洋標準 時」の DST

Slide 36

Slide 36 text

例えば Charles が住んでいる California では 次の 2 つを使い分ける: •太平洋夏時間:UTC-7 => 3 月から 11 月 (夏) •太平洋標準時:UTC-8 => 11 月から 3 月 (冬)

Slide 37

Slide 37 text

3 月に夏時間に切り替える時 時計の針を 1 時間進める ↓ 時間がスキップされる 1:59:59の1秒後が3:00:00!!

Slide 38

Slide 38 text

11 月に標準時間に切り替える時 時計の針を 1 時間戻す ↓ 時間が繰り返す 1時から2時が2回!!

Slide 39

Slide 39 text

この •スキップされる時間 •繰り返す時間 は .NET の世界でとても厄介な問題 を引き起こします…。 後ほど

Slide 40

Slide 40 text

.NET での日時処理

Slide 41

Slide 41 text

ポイントになる型: •DateTime •DateTimeOffset •TimeZoneInfo

Slide 42

Slide 42 text

DateTime •.NET 1.1 からある •素朴な日時型 •時差、タイムゾーン、夏時間サ ポートなし

Slide 43

Slide 43 text

DateTime (おそらく時差、タイムゾーンサ ポートのため) .NET 2.0 (SP1?) で Kind プロパティが追加された ↓ 使えない。ていうか邪魔

Slide 44

Slide 44 text

DateTime.Kind DateTime の基準を表す: •Utc:UTC •Local:現地時刻 •Unspecified:未指定 ただし具体的にどのタイムゾーンかは 分からない (= 使えない)

Slide 45

Slide 45 text

DateTime.Kind ちょくちょく邪魔する: •TimeZoneInfo の UTC => Local 変換メソッドに Kind が Local の DateTime を渡したら 死亡 ※DateTime.(Today|Now) の Kind は Local •WCF のクライアントとサーバーのタイムゾーン が異なり、受け渡す DateTime の Kind が Local だと、時差に応じて勝手に値が変換され る

Slide 46

Slide 46 text

DateTime.Kind 結論: 認知度低いくせにちょくちょく邪魔する ↓ 対策: プロジェクト内で認知度高めてバグを防ぎま しょう/(^o^)\

Slide 47

Slide 47 text

DateTimeOffset •.NET 3.5 からできた •MS 的には「DateTimeよりこっち推奨」 •日時の値に加えてUTC からの時差情 報も持つ=> 時差、タイムゾーンを部分 的にサポート •夏時間はサポートなし •SQL Server なら DateTimeOffset型あり

Slide 48

Slide 48 text

DateTimeOffset 例:Charlesの移動時間問題 Tokyo を 9 am (UTC+9) に Departure して California に 7 am (UTC-7) に Arrive ↓ DateTimeOffset なら普通に引き算可能 new DateTimeOffset(2013, 5, 28, 7, 0, 0, TimeSpan.FromHours(-7d)) – new DateTimeOffset(2013, 5, 28, 9, 0, 0, TimeSpan.FromHours(9d))

Slide 49

Slide 49 text

DateTimeOffset •結局 UTC との時差情報はDateTimeOffset の外から与える必要あり •DateTimeOffset 自身はローカルシステム のタイムゾーンの時差情報しか調べら れない。別タイムゾーンの時差情報は 外から与えることになる

Slide 50

Slide 50 text

DateTimeOffset 結論: DateTimeより有能だけど、グローバル対 応 (ローカルシステム以外のタイムゾーン を扱う) プログラムでは補助が必要

Slide 51

Slide 51 text

TimeZoneInfo •.NET 3.5 から •タイムゾーン情報を得るためのオブジェ クト •世界中のタイムゾーンを扱ったり、夏 時間をサポートするにはこのクラスしか ない

Slide 52

Slide 52 text

TimeZoneInfo •ConvertTimeToUtc:Local => Utc 変換 •ConvertTimeFromUtc:Utc=> Local 変換 •GetUtcOffset:指定された日時における UTC との時差を返す※夏時間にも対 応 => DateTimeOffset に外から与える時差 情報はこれで取れる!!

Slide 53

Slide 53 text

ここまでのまとめ というわけで •DateTimeは窓から投げ捨てて DateTimeOffset を使おう!! •ローカルシステム以外のタイムゾーンの 時差情報は TimeZoneInfo.GetUtcOffsetで 取得!! メデタシメデタシ…

Slide 54

Slide 54 text

と思わせておいて まだ未解決問題があります。 覚えてますか…?

Slide 55

Slide 55 text

標準時間  夏時間 切り替え問題 スキップされる時間 繰り返す時間

Slide 56

Slide 56 text

スキップされる時間 •.NET では Invalid Time と呼ぶ •TimeZoneInfo クラスに IsInvalidTime メソッド がある Local Time 00:00 01:00 02:00 03:00 04:00 UTC 02:00 03:00 03:00 04:00 05:00 DST (UTC-1) Invalid Time

Slide 57

Slide 57 text

スキップされる時間 TimeZoneInfo クラスの Local Time を欲しがっ ているメソッドにInvalid Time を渡すと容赦 なく死ぬ。例えば: •ConvertTimeToUtc •IsDaylightSavingTime

Slide 58

Slide 58 text

繰り返す時間 •.NET では Ambiguous Time と呼ぶ •TimeZoneInfo クラスに IsAmbiguousTimeメ ソッドがある Local Time 00:00 01:00 02:00 -> 01:00 02:00 03:00 UTC 01:00 02:00 03:00 04:00 05:00 Standard (UTC-2) Ambiguous Time

Slide 59

Slide 59 text

繰り返す時間 •TimeZoneInfo.ConvertTimeToUtcメソッドに Ambiguous Time を渡したら、標準時間だ と仮定して変換される Local Time 00:00 01:00 02:00 -> 01:00 02:00 03:00 UTC 01:00 02:00 03:00 04:00 05:00 Standard (UTC-2) Ambiguous Time .NET:こっちやろ

Slide 60

Slide 60 text

スキップされる時間再び TimeZoneInfo クラスに IsInvalidTime メソッドは あるが、Invalid Time の範囲を調べるメソッ ドがない (公開されてない) 作るしかない 作りますた(http://pastebin.com/GX3EYKbG) システムが Invalid Time を自動訂正で きる

Slide 61

Slide 61 text

DB設計 ちょびっと

Slide 62

Slide 62 text

複数のタイムゾーンを扱うシステムで DB に日時をどう保存するか

Slide 63

Slide 63 text

2つの選択肢 A) UTC で保存 B) DateTimeOffset で保存 A 案でよさげ

Slide 64

Slide 64 text

DBにはUTCで保存 根拠: •プログラムでの UTC の扱いやすさ (前述) •DB の値が Invalid/Ambiguous Time でないことが 保証される (UTC => Local 変換は失敗しな い) •DateTimeOffset だと、結局夏時間対応のた め別フィールドでタイムゾーン情報を持つ 必要がある

Slide 65

Slide 65 text

DBにはUTCで保存 しんどいところ: •DB を検索する時も DB に保存する時も Local => UTC 変換が必要。となると Invalid/Ambiguous Time 対応が必要になる ※DateTimeOffset でも必要なのは同じ

Slide 66

Slide 66 text

質疑応答