Date系ライブラリとIE11とタイムゾーン

この記事は個人ブログと同じ内容です

http://ratatatat30.hatenablog.jp/entry/2021/05/14/130211


sekitats です。backcheck で主に送りバントをしています。

さて、これまで backcheck では Date系ライブラリとして moment-timezone.js を使っていました。2020年9月 moment.js はすでにメンテナンスモードに入っており、backcheck ではこの度重い腰を上げて代替ライブラリへの移行をすることになりました。

以下の候補から最適なライブラリを選択するため調査を行いました。

  • date-fns (date-fns-tz)
  • Day.js
  • Luxon
  • js-joda(js-jodaについてはほぼ調査していませんが、念の為候補としてあげています。)

IE11 サポートとタイムゾーンの壁

前提として、Backcheck では IE11のブラウザ使用率が数%あり、IE11のサポートを完全に切ることができません。 選定の課題として IE11上でタイムゾーンの機能が正常に動作するかという点が必須項目となりました。

以下メリデメを表にしました。

ライブラリ名 メリット デメリット
Day.js ・他のライブラリと比べて最もファイルサイズが軽い
・moment に寄せて作られているため移行コストが最も安い
・開発継続性高い
・学習コストがほぼいらない
・IE11や timezone 関連のサポートの信頼性が低い(ライブラリの中では最もモダンブラウザに振り切ってる印象)
・IE11で意図した出力がされなかったため致命的と判断
date-fns(date-fns-tz) ・IE11での動作を確認
・採用しているプロジェクトが多い
・開発継続性高い。
・使用経験者がいる
・関数型設計のため、NuxtプロジェクトやPHPユーザーとは相性が悪い
・学習コストが要る
Luxon ・IE11での動作を確認
・moment.js のコントリビューターをしている人が作っているため後継として信頼性が高い
・Moment の後継であり開発継続性は高い
・IE11サポートに関するドキュメントが充実
・あまり人気がない
・使用経験者がいない
・学習コストが要る
js-joda - 独自実装のためIE9までサポートしている ・人気がない
・使用経験者がいない
java.time, Joda-Tome or Noda Time に慣れた人にはメリットだが、おそらくチーム的に不向き
・学習コストがいる

Luxon に決定 🎉

f:id:sekilberg:20210514111452j:plain
IE11で各種日付ライブラリを検証する

本命の Dayjs は、IE11ではタイムゾーン('Asia/Tokyo’)を指定した日時が意図した結果のになりませんでした。

date-fns (date-fns-tz)とLuxon はdate-fnsが標準時の表記(JST)、Luxon が IANA Time Zone 表記('Asia/Tokyo’)といった違いが出たものの日時は意図した時間が出力されました。 あとは好みや使い勝手といったところになってきますが Nuxt プロジェクトやPHPer との相性(Carbonの使用感との差)といった点で date-fns は脱落。最後に残ったのは Luxon でした。もともと Luxon は Moment.js のコントリビューターが作っているということもあり、IE11サポートのドキュメントも充実していてやはり安心感が違います。

polyfill

さて、IE11は UTC以外の特定のタイムゾーンをサポートしていません。IE11でタイムゾーンをサポートするためには polyfill が必要になります。

Option value ‘Asia/Tokyo’ for 'timeZone' is outside of valid range. Expected: ['UTC’]

https://stackoverflow.com/questions/54364061/ie-11-throwing-timezone-is-outside-of-valid-range-when-setting-timezone-to

IE11でタイムゾーンを扱う際の polyifll として date-time-format-timezone があります。しかし minified でも 2.64MBあり、そのままバンドルに含めると moment-timezone.jsよりもファイルサイズが増えてしまうため注意が必要です。さらにリポジトリアーカイブされており今後更新はされないため最新の polyfill を使うようにします。

最新のはこちら formatjs.io

すべて CDNから取得する場合は以下になります。polyfill.io は userAgent を見て polyfill が必要であるかを判断してファイルを返してくれるため、モダンブラウザで不要なファイルのロードをせずに済みます。

// nuxt.config.js
head: {
  script: [
    {
      src: ‘https://polyfill.io/v3/polyfill.min.js?features=Intl.~locale.ja,Intl.Locale,Intl.getCanonicalLocales,Intl.PluralRules.~locale.ja,Intl.NumberFormat,Intl.NumberFormat.~locale.ja,Intl.DateTimeFormat,Intl.DateTimeFormat.~locale.ja,Intl.NumberFormat.~locale.ja’,
      defer: true
    },
  ],
}

しかし、試してみたところ Intl.DateTimeFormat.~locale.ja のところで正しくロードできませんでした。 import する場合は下記のようになるかと思います。(そのほか必要な polyfill は適宜追加してください。 全てCDNにするか、全てimport にするかにしないと運用がたいへん。。)

// plugins/polyfill-datetimeformat.js
import { shouldPolyfill } from "@formatjs/intl-datetimeformat/should-polyfill";
(async function polyfill() {
  if (shouldPolyfill()) {
    try {
      const dataPolyfills = [
        import("@formatjs/intl-getcanonicallocales/polyfill"),
        import("@formatjs/intl-locale/polyfill"),
        import("@formatjs/intl-numberformat/polyfill"),
        import("@formatjs/intl-numberformat/locale-data/ja"),
        import("@formatjs/intl-pluralrules/polyfill"),
        import("@formatjs/intl-pluralrules/locale-data/ja"),
        import("@formatjs/intl-datetimeformat/polyfill"),
        import("@formatjs/intl-datetimeformat/locale-data/ja"),
        import("@formatjs/intl-datetimeformat/add-all-tz"),
      ];
      await Promise.all(dataPolyfills);
    } catch (e) {
      console.error(e);
    }
  }
})();

まとめ

IE11とタイムゾーンのサポートまでしているところはあまりないのではないでしょうか。タイムゾーンは日本で住んでいるとあまり意識することがありませんが、アプリケーションの世界では必ず必要になる概念であり、非常に学びの多いミッションでした。

代替ライブラリの選定にあたり、date-fns (date-fns-tz), Dayjs, Luxon, (js-joda) について多くの記事を調べましたが、IE11とタイムゾーンに言及した情報というのは見た限りはなかったと思います。この記事が有益な情報となれば幸いです。