10
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

お題は不問!Qiita Engineer Festa 2023で記事投稿!

DartのDateTimeをうまく扱うコツ

Last updated at Posted at 2023-06-28

Flutterで「〇〇をした時間を保存しておきたい」という場面があると思います。
処理としてはDateTimeで現在時刻を取得し、Stringに変換して保存、
取り出すときはStringからDateTimeに変換して利用します。

公式ドキュメントを読みつつ、実際にどういう動きをするのか確認していきます。
https://api.dart.dev/stable/3.0.3/dart-core/DateTime-class.html

DateTimeからStringへの変換方法

Create a DateTime object by using one of the constructors or by parsing a correctly formatted string, which complies with a subset of ISO 8601.

単純に訳すと
DateTimeコンストラクターを使用またはISO8601のサブセットに準拠する正しくフォーマットされた文字列を解析することによって、オブジェクトを作成します。
とあります。

ドキュメント記載のようにtoIso8601String()というメソッドを利用するとISO8601に変換をすることができるため、こちらを用いてStringに変換します。

ISO8601変換時にタイムゾーンを考慮するには

toIso8601String()をそのまま利用するだけではタイムゾーン考慮はされません。
②のように、String変換前にtoUtc()のメソッドを利用しUTC変換することで、タイムゾーン考慮がされます。
コードで見てみると下記のようになります。

  final now = DateTime.now(); // この時点でローカルタイムのJSTが適用される

  print(now.toIso8601String()); // ①2023-06-08T09:31:35.001
  print(now.toUtc().toIso8601String()); // ②2023-06-08T00:31:35.001Z

①ではJSTで変換されています。
②では末尾に「Z」が入っていますので、UTCの時間帯だと言う情報が入っていることがわかります。

StringからDateTimeへの変換方法

戻す時はtoLocal()を利用してローカルタイムに戻すことを忘れないようにしましょう。

  print(DateTime.parse(now.toUtc().toIso8601String()).toLocal()); // 2023-06-08 09:49:31.199

toLocal()を忘れるとUTCが考慮されているISO8601はUTCの時間でDateTimeに変換されます。

  final now = DateTime.now(); 
  print(DateTime.parse(now.toUtc().toIso8601String())); // 2023-06-08 00:49:31.199Z

ではここでDateTime->String時にUTCへ変換しなかった場合はどうなるのでしょうか?

  final now = DateTime.now();
  final nowString = now.toIso8601String();
  print(DateTime.parse(nowString)); // 2023-06-08 09:49:31.199
  print(DateTime.parse(nowString).toLocal()); // 2023-06-08 09:49:31.199

utcでString形式にしなかった場合は
toLocal()をつけても、つけなくても同様にローカルタイムになります。
String変換時にローカルタイムで保存される影響です。

一見これでいいのでは?と思いますが、端末の時刻に左右されるため注意が必要です。
DateTime→Stringの変換の時に端末の時刻がGMT+8(時刻は09:49:31)
String→DateTimeの変換の時に端末の時刻がGMT+9(時刻は10:49:31)だった場合は下記のようになり時間が正しく表示することができません

  // GMT+8(シンガポールなど)の設定に変更する
  final now = DateTime.now();
  final nowString = now.toIso8601String(); // 2023-06-08 09:49:31.199
  // GMT+9(日本など)の設定に変更する
  print(DateTime.parse(nowString)); // ③2023-06-08 09:49:31.199
  print(DateTime.parse(nowString).toLocal()); // 2023-06-08 09:49:31.199

③の時点で、GMT+9を考慮し2023-06-08 10:49:31.199にならないといけないですが09:49:31.199のままになってしまいます。String変換時にUTCを考慮していないためtoLocal()をしても同様の結果になります。

結論

DateTimeからiso8601形式にするときはtoUtc()でutcの時間にしてから保存しましょう。
iso8601形式からDateTimeに戻すときはtoLocal()をつけて端末の時刻を保存しましょう。

10
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?