Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
本当はややこしい日時のFormatPattern
Search
Saji
July 08, 2026
380
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
本当はややこしい日時のFormatPattern
Saji
July 08, 2026
More Decks by Saji
See All by Saji
tpac_study (2026)
sajikix
0
320
業務に残された「良くない型」で考える「TypeScriptの難しさ」
sajikix
4
8k
It’s “Time” to use Temporal
sajikix
3
670
ユーザーが作成したコードをブラウザ上で安全に実行できる Plugin システムへのアプローチ
sajikix
1
850
Branded Typesで日時の複雑さと戦う
sajikix
4
1.2k
推しProposalと広がる夢~Intl.MessageFormatとDomLocalization~
sajikix
2
810
自作JSエンジンに推しプロポーザルを実装したい!
sajikix
1
370
Lookback TypeScript ESM support and what should we do now.
sajikix
5
830
フロントエンドで日時処理と戦うために 2025 ver
sajikix
6
4.7k
Featured
See All Featured
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
630
Chasing Engaging Ingredients in Design
codingconduct
0
280
Being A Developer After 40
akosma
91
590k
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
220
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
4
490
GraphQLとの向き合い方2022年版
quramy
50
15k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
180
XXLCSS - How to scale CSS and keep your sanity
sugarenia
249
1.3M
GitHub's CSS Performance
jonrohan
1033
470k
Game over? The fight for quality and originality in the time of robots
wayneb77
1
250
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
580
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.3k
Transcript
本当はややこしい 日時のFormatPattern Nihonbashi.js #11 Saji (Ryusei Sajiki) / @sajikix
(主に国際化の文脈で ) 日時のフォーマットは 結構面倒くさい
⚠ 今回しない話 • タイムゾーンの話 ◦ 時差の変換とかサマータイムとか • 暦にまつわる話 ◦
非グレゴリウス暦の面倒なところなど • 人間の可読性特に考えなくて良い or 厳密なもの ◦ ISO8601 / RFC3339 とかの話
先に結論とその上で話すこと Intl.DateTimeFormatでいいならそれに越したことない • 今回のトークの結論としては実質これが全て • このあと話す「めんどくささ」を極力踏まないようにできる Intl.DateTimeFormatを使わないで頑張ろうとした時... • パンドラの箱は開かれます この辺りについて何が面倒なんだ?という話をします
みんながよくやりがち 大体以下の2択になると思ってる • FormatPattern文字列を使ってフォーマット • 一から全部自分で組み立てる 一から全部組み立てるのは国際化とかまで考えると大変 • 使い回しがしづらい /
ロケールデータをどこから持ってくる? …etc → なのでFormatPattern文字列を使いがち(今回はこの話)
FormatPattern文字列 「YYYY年MM月DD日」みたいなPatternを渡してフォーマットする方法 • 対応するSymbolのまとまり (YYYYなど) に実際の日時を入れてくれる • 大抵の日時系ライブラリでサポートされている方式 • (言語・ライブラリによっては実際の値を渡すものもある)
自由度が高いため、webフロントエンドでも各所で使われているが...
問題1: ライブラリ間互換性 ライブラリごとにFormatPatternのルールが微妙に違う JSのライブラリでは大きく2系統ある • Moment.js / Day.js 系 :
YYYY/MM/DD パターン • date-fns / Luxion 系 : yyyy/MM/dd パターン ただ同じ系統でもそれぞれ微妙に受け入れるsymbolやパターンに差がある → 相互運用性に問題がある
どれが正解なのか? (正解はある? ) 一番ちゃんとしていそうな仕様としてUnicodeのLDMLがある • Table: Date Field Symbol Table
• ※ Unicodeは国際化における多くの仕様やデータセット・ライブラリを持つ date-fns はこのLDMLに準拠することを明言している > Format of the string is based on Unicode Technical Standard #35
じゃあ、date-fns 使えば解決?
問題2 : 参照するロケールデータの違い そのライブラリがどんなロケールデータ(月名とか)を参照してるか • 多くのフォーマット機能を持つ日時系ライブラリは独自にデータを持つ • date-fnsの例 const dayValues
= { narrow: ["d", "l", "m", "m", "j", "v", "s"], short: ["do", "lu", "ma", "mi", "ju", "vi", "sá"], abbreviated: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"], //… }
Intl (ICU) の大元はCLDR Unicodeは様々なロケール固有の情報をCLDRという名前で公開・管理してる • 日時のフォーマット以外にも言語名や数値の形式など... • 全世界で最も統一的で網羅的なデータセットと言える OSの国際化機能やJSエンジンもライブラリ(ICU)を経てこのCLDRを利用してる →
CLDRのデータを利用するのが一番確実と言えそう (ちなみにdate-fnsのデータは結構CLDRとズレてたりする。多分他も...)
LDML準拠 + CLDRがデータソース なら解決?
問題3 : CLDRにもバージョンがある CLDRは常にupdateされている • 近年だと4月頃と10月頃にメジャーアップデートがある データ更新がある = フォーマット結果は変わりうる •
(メジャーなロケールではそこまで多くないけど) すごく厳密なことを言い出すと... • 「OSやBEと参照しているCLDRを揃えたい」みたいなことになる
つまり理想的には ... 以下があれば良い • pattern symbolはLDML準拠 • ロケールデータのデータソースはCLDR • ソースのCLDRバージョンは選べる
• (とはいえサイズが大きすぎるのは勘弁....) そんなライブラリあるのか .....? (パッと調べた感じなかなかなさそう )
じゃあ、作るっきゃない
作ってみた https://github.com/sajikix/datetime-pattern-formatter
作ったライブラリの特徴 • formatPatternはLDMLに完全に準拠 (一部未サポートSymbolあり) • 参照するのはCLDRそのままのデータ • ロケールを明示的に指定するのでそこまでバンドルサイズは肥大しない • 参照するCLDRのバージョンも明示的に指定できる
import { en } from "@sajikix/datetime-pattern-formatter/cldr/48_2/en"; format(new Date(), "yyyy-MM-dd", en, { inUTC: true}); // → 2026-07-08
これで全て解決?
突然ですがクイズです
以下の指定は正しい? 例: 「September」のような省略しない表記で月選択のDropDownUIを作った • 月だから使うシンボルはMで wide形式だから MMMM だな! • const
label = format(date,”MMMM”) • 英語ではちゃんと 「September」になった!ヨシ 👈
A. 月名が格変化する言語がある 日付の一部として表記する時と単体で表記する時で変化する 例 : チェコ語で 1月と1月5日をそれぞれ表記する場合 • 1月 :
leden • 1月5日 : 5. ledna MMMMの場合は ledna の方になってしまい、好ましくない....
月のformatSymbol : MとL このような月の格変化に対応するため月を表すsymbolには • M : 日付のの中の月名を示す時 • L
: 月名単体を表記する時 (standalone 形式と呼ばれる) の2種類が定義されている。 今回の例の場合 : • より広いロケールに対応することを見越すならLLLLの方が良い
そもそもFormat Pattern自体が難しい そもそも皆さんはFormatPattern文字列をうまく扱えているのか? • LとMを使い分けられていますか? • yとYの違いは説明できますか? • etc… 文法・文化慣習的に不自然なフォーマットを作ることが容易
→ 自由度が高い分、こういった部分は自力で使いこなすしかない
大いなる力には、 大いなる責任が伴う
Intl.DateTimeFormatなら Intl.DateTimeFormat では文法・慣習的に間違ったフォーマットはされづらい • 今回の例でもちゃんと格変化を踏まえてフォーマットされる Intl.DateTimeFormatの挙動 • ロケールごとに文法・慣習的に正しいPattern集みたいなものを持ってる • 渡されたオプションから一番近いものを選択する
• よく使われるformatPatternによる日時フォーマットは難点が多い • 一応公式と言えそうな仕様とメジャーなロケールデータセットはある ◦ LDMLとCLDR • 可能な限りLDMLとCLDRに準拠したフォーマットライブラリを作ってみた • それでも根底にあるformatPattern自体が難しいという問題は残る
• ここら辺を気にしたくないなら、Intl.DateTimeFormat が安全 • formatPatternのご利用は計画的に まとめ
終わり