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
320
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
120
業務に残された「良くない型」で考える「TypeScriptの難しさ」
sajikix
4
7.4k
It’s “Time” to use Temporal
sajikix
3
440
ユーザーが作成したコードをブラウザ上で安全に実行できる Plugin システムへのアプローチ
sajikix
1
770
Branded Typesで日時の複雑さと戦う
sajikix
4
1.2k
推しProposalと広がる夢~Intl.MessageFormatとDomLocalization~
sajikix
1
730
自作JSエンジンに推しプロポーザルを実装したい!
sajikix
1
360
Lookback TypeScript ESM support and what should we do now.
sajikix
5
820
フロントエンドで日時処理と戦うために 2025 ver
sajikix
6
4.7k
Featured
See All Featured
Designing Experiences People Love
moore
143
24k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Making Projects Easy
brettharned
120
6.7k
The browser strikes back
jonoalderson
0
1.4k
The SEO Collaboration Effect
kristinabergwall1
1
500
How to Talk to Developers About Accessibility
jct
2
320
Typedesign – Prime Four
hannesfritz
42
3.1k
A Soul's Torment
seathinner
6
3k
Designing Powerful Visuals for Engaging Learning
tmiket
1
450
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
760
What's in a price? How to price your products and services
michaelherold
247
13k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.4k
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のご利用は計画的に まとめ
終わり