☀️

Duration(days: n)とサマータイム

2023/11/13に公開

突然ですが、下記のコードの結果を予想してみましょう。
コピペで dartpad.dev で実行できるコードです

void main() {
  print(DateTime.parse("2023-10-03").add(Duration(days: 27)));
}

このコードはmainで DateTime(year: 2023, month: 10, day: 3) の日付に27日足した結果をprintしています。もちろん答えは 2023-10-30 が出ることを期待します。3に27を足すと30日。10月は31日までなので11月にもなっていない。完璧な計算だ

ファッ!!

サマータイム

日本にいると意識しないのですが、世の中にはサマータイム(夏時間)という制度がありそれはプログラミングでも日時を扱う際に意識する必要があります。先ほどのDartコードは OSの時刻の設定からタイムゾーンを Europe/Paris に変更して実行しました。

サマータイムについては詳しくは言及しませんがまだよく知らない方はググってください

きっかけ

Pilllというアプリを個人開発しています。これは日付関連の処理が多く、場合により日時の日付部分に焦点を当て、計算してロジックを実現することもあります。前述したように .add(Duration(days:)) を使用しているところがあり、ユーザーからの問い合わせをきっかけにサマータイムの時に問題出ることに気づきました。

解決策

.add(Duration(days:)) がサマータイムを考慮した結果を返すことがわかりました。ただ、アプリのロジックは純粋に10月7日から23日後の日付を表示したいものでした。このミスマッチを解消するために、Duration(期間)に変換された値ではなく、純粋にDateTimeの日付部分だけの足し算を行なった結果を返したいため、下記のように新しくDateTimeを作るインスタンスメソッドを作って解決しました。

extension DateTimeAdd on DateTime {
  DateTime addDays(int offset) {
    return DateTime(
      year,
      month,
      day + offset,
      hour,
      minute,
      second,
      millisecond,
      microsecond,
    );
  }
}

こちらを使った結果がこちらです。無事に2023-10-30で日付がprintされることが確認できました

おまけ

後から知ったのですが同じ悩みで同じアプローチをとっている記事を見かけました。実は全部読んでないのですが参考までにリンクを貼ります

https://medium.com/pinch-nl/datetime-and-daylight-saving-time-in-dart-9c9468633b5d

まとめ

サマータイムに苦しめられました。サマータイムもうマヂ無理ぃ。
サマータイムは廃止をしようとしている国も多いみたいですね。早く無くなることを祈っています。

この記事がサマータイムに苦しむ人たちの一助になれば幸いです(切実)

おしまい\(^o^)/

Discussion