- PR -

DateTime型をエポック値に変換してから戻す際の誤差について

投稿者投稿内容
みやぼん
会議室デビュー日: 2005/06/11
投稿数: 5
投稿日時: 2008-12-23 06:41
いつもお世話になっております。
みやぼんです。
VisualStudio2008(.NET3.5)で開発しております。

DateTime型⇔エポック値の変換ができるような関数を作成しましたが
1年1月1日のみ時刻部分が09:00と返ってきてしまうことに
疑問を覚えましたので投稿させて頂きました。
どなたかご存知の方がおられましたら、ご教示頂けませんでしょうか?

【ソースコード】
private void button1_Click(object sender, EventArgs e)
{
DateTime abc = new DateTime(1, 1, 1);
long cde = toEpochTime(abc);
DateTime efg = fromEpochTime(cde);
this.textBox1.Text = efg.ToString();
      //↑ここで表示される値が0001/01/01 9:00:00になります。
      //↑0001年01月02日の場合は、0001/01/02 0:00:00になります。

}

private static long toEpochTime(DateTime dt)
{
long epo = (dt.ToUniversalTime().Ticks - 621355968000000000) / 10000;
return epo;

}

private static DateTime fromEpochTime(long epo)
{
DateTime dt = new DateTime(epo * 10000 + 621355968000000000);
return dt.ToLocalTime();
}

Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2008-12-23 07:29
universal に変換しているから。
みやぼん
会議室デビュー日: 2005/06/11
投稿数: 5
投稿日時: 2008-12-23 08:34
いつもお世話になっております。
みやぼんです。

Jittaさん、ご回答ありがとうございます。

下記のようにすれば、1年1月1日について誤差がなくなりました。
private static long toEpochTime(DateTime dt)
{
long epo = (dt.ToUniversalTime().Ticks - 621355968000000000) / 10000;
return epo;
}
private static DateTime fromEpochTime(long epo) {
DateTime dt = new DateTime(epo * 10000 + 621355968000000000);
return dt.ToUniversalTime();
}

説明不足で申し訳ございませんが、
私が聞きたかったのは、最初のコードで
 DateTime abc = new DateTime(1, 1, 1);
とすると
 結果値が0001/01/01 9:00:00となり
DateTime abc = new DateTime(1, 1, 2);
とすると
 結果値が0001/01/02 0:00:00
となる。
1月1日と1月2日でなぜ9時間ずれるのかということです。
同じuniversal変換なのになぜ、差異が出てしまうのかを疑問視しております。
スフレ
ぬし
会議室デビュー日: 2005/05/27
投稿数: 281
お住まい・勤務地: 東京
投稿日時: 2008-12-23 11:27
西暦1年1月1日 00:00:00 JST がサポート範囲外だからでしょう。
DateTimeの最小値は西暦1年1月1日 00:00:00 UTC (= 09:00:00 JST) です。

Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2008-12-23 11:56
スフレさんの通りです。

西暦1年1月1日 00:00:00 JST を UTCに変換(ToUniversalTime)したところで 西暦-1年12月31日 15:00:00 UTC になるんですね。これは範囲外なので 西暦1年1月1日 00:00:00 UTC に修正されて(OutOfRangeException が発生していたら気がつけた?)、これを JST に変換(dt.ToLocalTime)しているので、9時間の誤差がでます。なので、正確には
西暦1年1月1日 00:00:00 JST 〜 西暦1年1月1日 09:00:00 JST が、西暦1年1月1日 09:00:00 JST に復元されてしまう。
という現象だったはずです。
みやぼん
会議室デビュー日: 2005/06/11
投稿数: 5
投稿日時: 2008-12-23 16:55
スフレさん、Jittaさん
ご回答、誠にありがとうございます。

>西暦1年1月1日 00:00:00 JST がサポート範囲外だからでしょう。
まったく知りませんでした。。
>OutOfRangeException が発生していたら気がつけた?
はい、調査のきっかけになっていたと思います。

本当にご回答ありがとうございます!
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2008-12-23 17:46
引用:

みやぼんさんの書き込み (2008-12-23 16:55) より:
スフレさん、Jittaさん
ご回答、誠にありがとうございます。

>西暦1年1月1日 00:00:00 JST がサポート範囲外だからでしょう。
まったく知りませんでした。。
>OutOfRangeException が発生していたら気がつけた?
はい、調査のきっかけになっていたと思います。

本当にご回答ありがとうございます!



ん?解決した?本当に?

long epo = (dt.ToUniversalTime().Ticks - 621355968000000000) / 10000;
ローカル時間からユニバーサル時間を出して変換。

DateTime dt = new DateTime(epo * 10000 + 621355968000000000).ToUniversalTime();
ユニバーサル時間のエポック値をローカル時間として扱って DateTime を構築。それをユニバーサル時間に変換。

合計で、18時間の誤差が出ません?

本当は、最初のであっていて、西暦1年1月1日 00:00:00 JST 〜 西暦1年1月1日 09:00:00 JST の範囲については、「範囲外の例外」としなければならないのでは?
みやぼん
会議室デビュー日: 2005/06/11
投稿数: 5
投稿日時: 2008-12-24 23:57
ご返信が遅くなりまして、申し訳ございません。
解決しました。

>本当は、最初のであっていて
その通りです。
最初の処理で且つ、西暦1年1月1日 00:00:00 JST〜西暦1年1月1日 09:00:00 JSTは
誤差が出ることで納得頂きました。

>DateTimeの最小値は西暦1年1月1日 00:00:00 UTC (= 09:00:00 JST)
が決め手になりました。

ありがとうございます!

スキルアップ/キャリアアップ(JOB@IT)