転職したらスマレジだった件

スマレジのエンジニアやまてのテックブログです。マジレス大歓迎です。

Flutter|Dart で yyyy-MM-ddThh:mm:ss+9:00 という日付形式(ISO 8601)の文字列を生成する方法

スマレジの テックファーム(SES 部門) でWebエンジニアとして働いている やまて(@r_yamate) と申します。

実務では、2023 年 3 月末で SES の派遣先で、テーブルオーダーシステムの機能改修業務の設計などを担当していた業務を終えたところです。

4月からは、スマレジの関連アプリの開発業務を担当しています。触ったことのなかった Flutter での開発で、日々奮闘中です。

はじめに

本記事では、 Dart 言語で 2023-07-01T12:34:56+09:00 という ISO 8601 形式の文字列を生成をする方法について書きます。

環境

目次

1. そもそもなぜ自作するのか

「そもそもこのような共通の形式への変換を自作する必要あるの?」「Dart 言語に変換するためのメソッドがあるのでは?」と思うかもしれません。

結論としては、 2023-07-01T12:34:56+09:00+09:00タイムゾーンオフセット)がそのまま取得できるものはありませんでした。(2023/07/02 時点)

Dartタイムゾーンが判別できるメソッド

Dart では、タイムゾーンUTC であるか UTC 以外かを判定できる toIso8601String メソッドがあります。

api.flutter.dev

このメソッドを使って日本標準時JST)の時刻を取得すると、以下のような結果になります。

final now = DateTime.now();
print(now); // ① 2023-07-01 12:34:56.789012
print(now.toIso8601String()); // ② 2023-07-01T12:34:56.789012
print(now.toUtc().toIso8601String()); // ③ 2023-07-01T03:34:56.789012Z

表記は違いますが、同じ日付と時刻を示しています。②が ISO 8601 形式の文字列で、①のデフォルトでの表記との違いは T の有無です。

③ は同時刻の UTC での表記で、Z を末尾に付けて示しています。

しかし、 +09:00 のようなタイムゾーンオフセット表記を取得するには、独自のコードを実装する必要があります。

github.com

2. 実装したコード

上記の toIso8601String メソッドを踏まえて、 2023-07-01T12:34:56.789012+09:00 という形式に変換するためのコードは以下です。

/// DateTimeを拡張するためのクラス。
extension DateTimeStringExtension on DateTime {
  /// DateTimeオブジェクトを ISO 8601 形式の文字列に変換し、タイムゾーンオフセットを付加する。
  ///
  /// DateTime が UTC である場合は、タイムゾーンオフセットは付加せず、標準のISO 8601形式の文字列を返す。
  /// タイムゾーンオフセットは、時間と分が2桁にゼロ埋めされ、符号付きで表現される(例:"+09:00"、"-05:00")。
  /// 例: "2023-07-01T12:34:56+09:00"
  String toIso8601StringWithTimeZoneOffset() {
    if (isUtc) {
      return toIso8601String();
    }

    final offset = timeZoneOffset;
    final offsetSign = offset.isNegative ? '-' : '+';
    final offsetHours = offset.inHours.abs().toString().padLeft(2, '0');
    final offsetMinutes =
        (offset.inMinutes.abs() % 60).toString().padLeft(2, '0');
    final offsetFormat = '$offsetSign$offsetHours:$offsetMinutes';

    return '${toIso8601String()}$offsetFormat';
  }
}

3. 実装したコードの確認

UTC判定と変換

if (isUtc) {
  return toIso8601String();
}

DateTime オブジェクトが UTC であるかどうかを判定します。もし UTC であれば、そのまま ISO 8601 形式の文字列に変換して返します。

タイムゾーンオフセットの取得

final offset = timeZoneOffset;

DateTime オブジェクトのタイムゾーンオフセット(協定世界時との時差)を取得します。

オフセットの符号判定

final offsetSign = offset.isNegative ? '-' : '+';

タイムゾーンオフセットが負かどうかを判定し、その結果に基づいてオフセットの符号(+-)を決定します。

オフセットの時間部分の生成

final offsetHours = offset.inHours.abs().toString().padLeft(2, '0');

タイムゾーンオフセットを時間単位で取得します(絶対値)。それを 2 桁の文字列に変換します。時間が 1 桁の場合は左側にゼロを追加します。

オフセットの分部分の生成

final offsetMinutes = (offset.inMinutes.abs() % 60).toString().padLeft(2, '0');

タイムゾーンオフセットを分単位で取得します(絶対値にして、60 で割った余り)。時間と同じく、 2 桁の文字列に変換します。分が 1 桁の場合は左側にゼロを追加します。

オフセット形式の生成

final offsetFormat = '$offsetSign$offsetHours:$offsetMinutes';

符号、時間、分を結合してタイムゾーンオフセットを表現します。

最終的な文字列の生成

return '${toIso8601String()}$offsetFormat';

DateTime オブジェクトを ISO 8601 形式の文字列に変換し、その後ろにタイムゾーンオフセットを付加して返します。

おわりに

今回は、Dart 言語で 2023-07-01T12:34:56+09:00 という ISO 8601 形式の文字列を生成をする方法について書きました。

ありがとうございました。

参考にしたページ



37歳、良いスタートを切りました!…