DateTimeOffset? configStartDate = null;
var jst = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time");
var jstNow = TimeZoneInfo.ConvertTime(DateTimeOffset.Now, jst);
var startDate = configStartDate ?? jstNow.Date; // 👈
Console.WriteLine(startDate.ToString("o"));
// configStartDateのTZが不定だから表示用にJSTに矯正しとこ
var jstStartDate = TimeZoneInfo.ConvertTime(startDate, jst);
Console.WriteLine(jstStartDate.ToString("o"));
何かの開始日を生成するのに、登録された値がなかったら今日からってコードってよく書くと思う。
実行結果
JST
2025-06-22T00:00:00.0000000+09:00
2025-06-22T00:00:00.0000000+09:00
UTC
2025-06-22T00:00:00.0000000+00:00
2025-06-22T09:00:00.0000000+09:00 #🤯
やっちまったなあ!見事にずれてまっせ。
根源
バグは既に示してるけど、DateTimeOffset型のjstNowを日付欲しさにDateしてるところ。ここでDateTimeOffsetからDateTime型になっていてオフセットが落ちてる。 自分のPCはJSTだから全然気づかないけどデプロイしてから発覚するやつ。 DateTimeからDateTimeOffsetへの暗黙的型変換にはローカルタイムゾーンが使われると思うけど、dotnetのプログラム内で参照するタイムゾーンを変更する方法がない(知らないだけかも)からUTCにしたかったらマシンの設定を変更しなくちゃいけないし大変。 8でTimeProviderとか追加されたけど、これは暗黙的型変換で起きてる問題だから出る幕ない。 つまるところ、DateTimeOffsetにDateTimeをオフセットしていなしに代入できるのがよくないんじゃない? RoslynAnalyzer書けばいいけど、面倒だから、コンパイルオプションとか警告オプションを標準で出せるようになって欲しいと思う今日この頃です。
一応Issueはあって、Analayzerでやる形ですすんでいるみたい。2022年で止まってるけど。
Add analyzer for DateTimeOffset implicit operator with DateTime. · Issue #75400 · dotnet/runtime
おまけ
var jst = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time");
var jstNow = TimeZoneInfo.ConvertTime(DateTimeOffset.Now, jst);
var jstDate = new DateTimeOffset(jstNow.Date, jstNow.Offset); // OffsetつけなおしてDateTimeOffsetに戻そうね
var startDate = configStartDate ?? jstDate;
Console.WriteLine(startDate.ToString("o"));
var jstStartDate = TimeZoneInfo.ConvertTime(startDate, jst);
Console.WriteLine(jstStartDate.ToString("o"));