Upload
atsushi-kambara
View
1.804
Download
1
Embed Size (px)
DESCRIPTION
「『プログラミング .NET Framework 第4版 』座談会」発表資料です。 http://atnd.org/event/E0019986/0
Citation preview
グローバル化はなぜ日時処理問題を引き起こすのか
Titled by ホッテントリメーカー
@atsukanrock
2013/10/26
C#ユーザー会
@atsukanrockhttp://d.hatena.ne.jp/atsukanrock/
Enterprise Application Architectになりたい DDD Lover
@atsukanrockhttp://d.hatena.ne.jp/atsukanrock/
Enterprise Application Architectになりたい DDD Lover
http://jigokuno.com/?eid=162
ゴール
この辺を伝えたい:
• 時差とは?
• タイムゾーンとは?
• UTCとは?
• 夏時間とは?
• .NET での日時処理
時差
外資系あるある
ピンチ!!外人からメール来た!!
トレーニングのお誘いかー
28日の 7時から…
もー!はえーよー!!
ε-(´∀`*)ホッ
解読成功♪
ファッ!?
7 時じゃなくて 23時!?
時差のせいです。
時差アメリカ西海岸では 7:00
東京では 23:00
カリフォルニアとか
タイムゾーン
男闘呼組じゃないよ
東京の僕たちが23時に酒を飲んでいる頃
California の Charles は7 時に Bacon Eggの
Breakfast を Eating
僕たちは東京標準時(Tokyo Standard Time (UTC+9))に生きていて
Charles は太平洋夏時間(Pacific Daylight Time (UTC-7))
に生きている
タイムゾーンとはこの:
•東京標準時
•太平洋夏時間
とかのことで、
タイムゾーンが違うと
同じ瞬間なのに時刻が違う
タイムゾーンあるある
I永さん:2013/10/26 13:00からC#ユーザー会やります!!
Charles:Hey, どの Time Zone だい?
ただ「2013/10/25 13:00」と言ってもどのタイムゾーンかによってどの瞬間かが異なる
様々なタイムゾーンの基準になる時間がないと何かと不便
そこで考えだされたのが UTC
1963年発足らしい
すべてのタイムゾーンはUTC を基準にして何時間進んでいるかor 何時間遅れているかで表される
東京標準時:UTC+9太平洋夏時間:UTC-7
進んでる
遅れてる
プログラムの世界ではUTCのおかげでとても楽になる
Charles (非 UTC Ver.):Tokyo を 9 am に Departure してCalifornia に 7 am に Arriveしたんだよ
何時間かかったか分からない
Charles (UTC Ver.):Tokyo を 12 am に Departure してCalifornia に 2 PM に Arriveしたんだよ
14時間かかったんだねおつかれさま
時刻を全て UTCで表せば
瞬間に基づく:
•足し算や引き算
•比較
•並べ替え
が簡単になる
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 `ー‐―''" ⌒'ー--‐'´`ヽ、_ _,ノ ノ
 ̄ ̄ | /
夏時間
Charles:Listen してくれ、Todayから DSTなんだ。
DST: Daylight Saving Time•日本語では夏時間
•先ほどから登場している「太平洋夏時間」は「太平洋標準時」の DST
例えば Charlesが住んでいるCaliforniaでは
次の 2つを使い分ける:
•太平洋夏時間:UTC-7=> 3 月から 11月 (夏)
•太平洋標準時:UTC-8=> 11 月から 3 月 (冬)
3 月に夏時間に切り替える時
時計の針を 1 時間進める
↓
時間がスキップされる
1:59:59の1秒後が3:00:00!!
11 月に標準時間に切り替える時
時計の針を 1 時間戻す
↓
時間が繰り返す
1時から2時が2回!!
この
•スキップされる時間
•繰り返す時間
は .NET の世界でとても厄介な問題を引き起こします…。
後ほど
.NET での日時処理
ポイントになる型:•DateTime
•DateTimeOffset
•TimeZoneInfo
DateTime•.NET 1.1 からある
•素朴な日時型
•時差、タイムゾーン、夏時間サポートなし
DateTime(おそらく時差、タイムゾーンサポートのため) .NET 2.0 (SP1?) で Kindプロパティが追加された
↓
使えない。ていうか邪魔
DateTime.KindDateTimeの基準を表す:
•Utc:UTC
•Local:現地時刻
•Unspecified:未指定
ただし具体的にどのタイムゾーンかは分からない (= 使えない)
DateTime.Kindちょくちょく邪魔する:
•TimeZoneInfoの UTC => Local 変換メソッドにKindが Localの DateTimeを渡したら死亡※DateTime.(Today|Now)の Kindは Local
•WCFのクライアントとサーバーのタイムゾーンが異なり、受け渡す DateTimeの Kindが Localだと、時差に応じて勝手に値が変換される
DateTime.Kind結論:
認知度低いくせにちょくちょく邪魔する
↓
対策:
プロジェクト内で認知度高めてバグを防ぎましょう/(^o^)\
DateTimeOffset• .NET 3.5 からできた
•MS的には「DateTimeよりこっち推奨」
•日時の値に加えて UTC からの時差情報も持つ => 時差、タイムゾーンを部分的にサポート
•夏時間はサポートなし
•SQL Serverなら DateTimeOffset型あり
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))
DateTimeOffset•結局 UTCとの時差情報は DateTimeOffsetの外から与える必要あり
•DateTimeOffset自身はローカルシステムのタイムゾーンの時差情報しか調べられない。別タイムゾーンの時差情報は外から与えることになる
DateTimeOffset結論:
DateTimeより有能だけど、グローバル対応 (ローカルシステム以外のタイムゾーンを扱う)プログラムでは補助が必要
TimeZoneInfo• .NET 3.5 から
•タイムゾーン情報を得るためのオブジェクト
•世界中のタイムゾーンを扱ったり、夏時間をサポートするにはこのクラスしかない
TimeZoneInfo•ConvertTimeToUtc:Local => Utc変換
•ConvertTimeFromUtc:Utc => Local変換
•GetUtcOffset:指定された日時におけるUTCとの時差を返す※夏時間にも対応=> DateTimeOffsetに外から与える時差情報はこれで取れる!!
ここまでのまとめというわけで
•DateTimeは窓から投げ捨ててDateTimeOffsetを使おう!!
•ローカルシステム以外のタイムゾーンの時差情報は TimeZoneInfo.GetUtcOffsetで取得!!
メデタシメデタシ…
と思わせておいてまだ未解決問題があります。覚えてますか…?
標準時間夏時間切り替え問題
スキップされる時間
繰り返す時間
スキップされる時間• .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
スキップされる時間TimeZoneInfoクラスの Local Timeを欲しがっているメソッドに Invalid Timeを渡すと容赦なく死ぬ。例えば:
•ConvertTimeToUtc
• IsDaylightSavingTime
繰り返す時間• .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
繰り返す時間•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:こっちやろ
スキップされる時間再びTimeZoneInfoクラスに IsInvalidTimeメソッドはあるが、Invalid Timeの範囲を調べるメソッドがない (公開されてない)
作るしかない
作りますた (http://pastebin.com/GX3EYKbG)
システムが Invalid Time を自動訂正できる
DB設計
ちょびっと
複数のタイムゾーンを扱うシステムでDBに日時をどう保存するか
2つの選択肢A) UTCで保存
B) DateTimeOffsetで保存
A案でよさげ
DBには UTCで保存根拠:
•プログラムでの UTCの扱いやすさ (前述)
•DBの値が Invalid/Ambiguous Timeでないことが保証される (UTC => Local 変換は失敗しない)
•DateTimeOffsetだと、結局夏時間対応のため別フィールドでタイムゾーン情報を持つ必要がある
DBには UTCで保存しんどいところ:
•DBを検索する時も DBに保存する時も Local => UTC 変換が必要。となるとInvalid/Ambiguous Time対応が必要になる※DateTimeOffsetでも必要なのは同じ
質疑応答