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

グローバル化はなぜ日時処理問題を引き起こすのか

Embed Size (px)

DESCRIPTION

「『プログラミング .NET Framework 第4版 』座談会」発表資料です。 http://atnd.org/event/E0019986/0

Citation preview

Page 1: グローバル化はなぜ日時処理問題を引き起こすのか

グローバル化はなぜ日時処理問題を引き起こすのか

Titled by ホッテントリメーカー

@atsukanrock

2013/10/26

C#ユーザー会

Page 2: グローバル化はなぜ日時処理問題を引き起こすのか

@atsukanrockhttp://d.hatena.ne.jp/atsukanrock/

Enterprise Application Architectになりたい DDD Lover

Page 3: グローバル化はなぜ日時処理問題を引き起こすのか

@atsukanrockhttp://d.hatena.ne.jp/atsukanrock/

Enterprise Application Architectになりたい DDD Lover

http://jigokuno.com/?eid=162

Page 4: グローバル化はなぜ日時処理問題を引き起こすのか

ゴール

Page 5: グローバル化はなぜ日時処理問題を引き起こすのか

この辺を伝えたい:

• 時差とは?

• タイムゾーンとは?

• UTCとは?

• 夏時間とは?

• .NET での日時処理

Page 6: グローバル化はなぜ日時処理問題を引き起こすのか

時差

Page 7: グローバル化はなぜ日時処理問題を引き起こすのか

外資系あるある

Page 8: グローバル化はなぜ日時処理問題を引き起こすのか

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

Page 9: グローバル化はなぜ日時処理問題を引き起こすのか

トレーニングのお誘いかー

28日の 7時から…

もー!はえーよー!!

Page 10: グローバル化はなぜ日時処理問題を引き起こすのか

ε-(´∀`*)ホッ

解読成功♪

Page 11: グローバル化はなぜ日時処理問題を引き起こすのか

ファッ!?

Page 12: グローバル化はなぜ日時処理問題を引き起こすのか

7 時じゃなくて 23時!?

Page 13: グローバル化はなぜ日時処理問題を引き起こすのか

時差のせいです。

Page 14: グローバル化はなぜ日時処理問題を引き起こすのか

時差アメリカ西海岸では 7:00

東京では 23:00

カリフォルニアとか

Page 15: グローバル化はなぜ日時処理問題を引き起こすのか

タイムゾーン

男闘呼組じゃないよ

Page 16: グローバル化はなぜ日時処理問題を引き起こすのか

東京の僕たちが23時に酒を飲んでいる頃

California の Charles は7 時に Bacon Eggの

Breakfast を Eating

Page 17: グローバル化はなぜ日時処理問題を引き起こすのか

僕たちは東京標準時(Tokyo Standard Time (UTC+9))に生きていて

Charles は太平洋夏時間(Pacific Daylight Time (UTC-7))

に生きている

Page 18: グローバル化はなぜ日時処理問題を引き起こすのか

タイムゾーンとはこの:

•東京標準時

•太平洋夏時間

とかのことで、

タイムゾーンが違うと

同じ瞬間なのに時刻が違う

Page 19: グローバル化はなぜ日時処理問題を引き起こすのか
Page 20: グローバル化はなぜ日時処理問題を引き起こすのか

タイムゾーンあるある

Page 21: グローバル化はなぜ日時処理問題を引き起こすのか

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

Page 22: グローバル化はなぜ日時処理問題を引き起こすのか

Charles:Hey, どの Time Zone だい?

Page 23: グローバル化はなぜ日時処理問題を引き起こすのか

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

Page 24: グローバル化はなぜ日時処理問題を引き起こすのか

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

Page 25: グローバル化はなぜ日時処理問題を引き起こすのか

そこで考えだされたのが UTC

1963年発足らしい

Page 26: グローバル化はなぜ日時処理問題を引き起こすのか

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

Page 27: グローバル化はなぜ日時処理問題を引き起こすのか

東京標準時:UTC+9太平洋夏時間:UTC-7

進んでる

遅れてる

Page 28: グローバル化はなぜ日時処理問題を引き起こすのか

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

Page 29: グローバル化はなぜ日時処理問題を引き起こすのか

Charles (非 UTC Ver.):Tokyo を 9 am に Departure してCalifornia に 7 am に Arriveしたんだよ

何時間かかったか分からない

Page 30: グローバル化はなぜ日時処理問題を引き起こすのか

Charles (UTC Ver.):Tokyo を 12 am に Departure してCalifornia に 2 PM に Arriveしたんだよ

14時間かかったんだねおつかれさま

Page 31: グローバル化はなぜ日時処理問題を引き起こすのか

時刻を全て UTCで表せば

瞬間に基づく:

•足し算や引き算

•比較

•並べ替え

が簡単になる

Page 32: グローバル化はなぜ日時処理問題を引き起こすのか

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 `ー‐―''" ⌒'ー--‐'´`ヽ、_ _,ノ ノ

 ̄ ̄ | /

Page 33: グローバル化はなぜ日時処理問題を引き起こすのか

夏時間

Page 34: グローバル化はなぜ日時処理問題を引き起こすのか

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

Page 35: グローバル化はなぜ日時処理問題を引き起こすのか

DST: Daylight Saving Time•日本語では夏時間

•先ほどから登場している「太平洋夏時間」は「太平洋標準時」の DST

Page 36: グローバル化はなぜ日時処理問題を引き起こすのか

例えば Charlesが住んでいるCaliforniaでは

次の 2つを使い分ける:

•太平洋夏時間:UTC-7=> 3 月から 11月 (夏)

•太平洋標準時:UTC-8=> 11 月から 3 月 (冬)

Page 37: グローバル化はなぜ日時処理問題を引き起こすのか

3 月に夏時間に切り替える時

時計の針を 1 時間進める

時間がスキップされる

1:59:59の1秒後が3:00:00!!

Page 38: グローバル化はなぜ日時処理問題を引き起こすのか

11 月に標準時間に切り替える時

時計の針を 1 時間戻す

時間が繰り返す

1時から2時が2回!!

Page 39: グローバル化はなぜ日時処理問題を引き起こすのか

この

•スキップされる時間

•繰り返す時間

は .NET の世界でとても厄介な問題を引き起こします…。

後ほど

Page 40: グローバル化はなぜ日時処理問題を引き起こすのか

.NET での日時処理

Page 41: グローバル化はなぜ日時処理問題を引き起こすのか

ポイントになる型:•DateTime

•DateTimeOffset

•TimeZoneInfo

Page 42: グローバル化はなぜ日時処理問題を引き起こすのか

DateTime•.NET 1.1 からある

•素朴な日時型

•時差、タイムゾーン、夏時間サポートなし

Page 43: グローバル化はなぜ日時処理問題を引き起こすのか

DateTime(おそらく時差、タイムゾーンサポートのため) .NET 2.0 (SP1?) で Kindプロパティが追加された

使えない。ていうか邪魔

Page 44: グローバル化はなぜ日時処理問題を引き起こすのか

DateTime.KindDateTimeの基準を表す:

•Utc:UTC

•Local:現地時刻

•Unspecified:未指定

ただし具体的にどのタイムゾーンかは分からない (= 使えない)

Page 45: グローバル化はなぜ日時処理問題を引き起こすのか

DateTime.Kindちょくちょく邪魔する:

•TimeZoneInfoの UTC => Local 変換メソッドにKindが Localの DateTimeを渡したら死亡※DateTime.(Today|Now)の Kindは Local

•WCFのクライアントとサーバーのタイムゾーンが異なり、受け渡す DateTimeの Kindが Localだと、時差に応じて勝手に値が変換される

Page 46: グローバル化はなぜ日時処理問題を引き起こすのか

DateTime.Kind結論:

認知度低いくせにちょくちょく邪魔する

対策:

プロジェクト内で認知度高めてバグを防ぎましょう/(^o^)\

Page 47: グローバル化はなぜ日時処理問題を引き起こすのか

DateTimeOffset• .NET 3.5 からできた

•MS的には「DateTimeよりこっち推奨」

•日時の値に加えて UTC からの時差情報も持つ => 時差、タイムゾーンを部分的にサポート

•夏時間はサポートなし

•SQL Serverなら DateTimeOffset型あり

Page 48: グローバル化はなぜ日時処理問題を引き起こすのか

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

Page 49: グローバル化はなぜ日時処理問題を引き起こすのか

DateTimeOffset•結局 UTCとの時差情報は DateTimeOffsetの外から与える必要あり

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

Page 50: グローバル化はなぜ日時処理問題を引き起こすのか

DateTimeOffset結論:

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

Page 51: グローバル化はなぜ日時処理問題を引き起こすのか

TimeZoneInfo• .NET 3.5 から

•タイムゾーン情報を得るためのオブジェクト

•世界中のタイムゾーンを扱ったり、夏時間をサポートするにはこのクラスしかない

Page 52: グローバル化はなぜ日時処理問題を引き起こすのか

TimeZoneInfo•ConvertTimeToUtc:Local => Utc変換

•ConvertTimeFromUtc:Utc => Local変換

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

Page 53: グローバル化はなぜ日時処理問題を引き起こすのか

ここまでのまとめというわけで

•DateTimeは窓から投げ捨ててDateTimeOffsetを使おう!!

•ローカルシステム以外のタイムゾーンの時差情報は TimeZoneInfo.GetUtcOffsetで取得!!

メデタシメデタシ…

Page 54: グローバル化はなぜ日時処理問題を引き起こすのか

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

Page 55: グローバル化はなぜ日時処理問題を引き起こすのか

標準時間夏時間切り替え問題

スキップされる時間

繰り返す時間

Page 56: グローバル化はなぜ日時処理問題を引き起こすのか

スキップされる時間• .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

Page 57: グローバル化はなぜ日時処理問題を引き起こすのか

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

•ConvertTimeToUtc

• IsDaylightSavingTime

Page 58: グローバル化はなぜ日時処理問題を引き起こすのか

繰り返す時間• .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

Page 59: グローバル化はなぜ日時処理問題を引き起こすのか

繰り返す時間•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:こっちやろ

Page 60: グローバル化はなぜ日時処理問題を引き起こすのか

スキップされる時間再びTimeZoneInfoクラスに IsInvalidTimeメソッドはあるが、Invalid Timeの範囲を調べるメソッドがない (公開されてない)

作るしかない

作りますた (http://pastebin.com/GX3EYKbG)

システムが Invalid Time を自動訂正できる

Page 61: グローバル化はなぜ日時処理問題を引き起こすのか

DB設計

ちょびっと

Page 62: グローバル化はなぜ日時処理問題を引き起こすのか

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

Page 63: グローバル化はなぜ日時処理問題を引き起こすのか

2つの選択肢A) UTCで保存

B) DateTimeOffsetで保存

A案でよさげ

Page 64: グローバル化はなぜ日時処理問題を引き起こすのか

DBには UTCで保存根拠:

•プログラムでの UTCの扱いやすさ (前述)

•DBの値が Invalid/Ambiguous Timeでないことが保証される (UTC => Local 変換は失敗しない)

•DateTimeOffsetだと、結局夏時間対応のため別フィールドでタイムゾーン情報を持つ必要がある

Page 65: グローバル化はなぜ日時処理問題を引き起こすのか

DBには UTCで保存しんどいところ:

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

Page 66: グローバル化はなぜ日時処理問題を引き起こすのか

質疑応答