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
Branded Typesで日時の複雑さと戦う
Search
Saji
November 23, 2025
2
520
Branded Typesで日時の複雑さと戦う
TSKaigiHokuriku2025 LT
-
https://hokuriku.tskaigi.org/talks/41
X
-
https://twitter.com/sajikix
Saji
November 23, 2025
Tweet
Share
More Decks by Saji
See All by Saji
推しProposalと広がる夢~Intl.MessageFormatとDomLocalization~
sajikix
1
270
自作JSエンジンに推しプロポーザルを実装したい!
sajikix
1
260
Lookback TypeScript ESM support and what should we do now.
sajikix
4
720
フロントエンドで日時処理と戦うために 2025 ver
sajikix
6
4.5k
先取り!Temporal
sajikix
0
250
アプリ文言のパースで学ぶ 文字列Literal型パズル入門
sajikix
3
1.1k
The Future of Frontend i18n : Intl.MessageFormat
sajikix
1
4k
Temporalを取り巻く仕様を整理する
sajikix
3
1k
Intlの今までとこれから
sajikix
7
4.2k
Featured
See All Featured
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
1.8k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
340
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
127
54k
Mobile First: as difficult as doing things right
swwweet
225
10k
Side Projects
sachag
455
43k
Docker and Python
trallard
46
3.7k
Building Flexible Design Systems
yeseniaperezcruz
329
39k
Learning to Love Humans: Emotional Interface Design
aarron
274
41k
A Modern Web Designer's Workflow
chriscoyier
697
190k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
11
940
Art, The Web, and Tiny UX
lynnandtonic
303
21k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
1
40
Transcript
3ZVTFJ4BKJLJ!TBKJLJY #SBOEFE5ZQFTͰ࣌ͷෳࡶ͞ͱઓ͏
͍࣌͠Ͱ͢ΑͶʁ
ࣗͷνʔϜͰ՝ͩͬͨ
ҙࣝΛڞ༗͢ΔͨΊʹ ؆୯ʹLJOUPOFͷઆ໌
LJOUPOFʹ͍ͭͯ LJOUPOFɺϓϩάϥϛϯάͷ͕ࣝͳͯ͘ۀʹ߹ΘͤͨγεςϜΛ͢ ͘։ൃͰ͖ΔϊʔίʔυɾϩʔίʔυͰ͢ɻ σʔλΛੵɾҰཡɾݕࡧͰ͖ΔσʔλϕʔεػೳͱɺۀΛԁʹਐΊΔͨ Ίͷίϛϡχέʔγϣϯػೳ͕උΘ͍ͬͯ·͢ɻ
LJOUPOFͷʮΞϓϦʯػೳʹ͍ͭͯ LJOUPOFͷϝΠϯػೳʹʮΞϓϦػೳʯͱݺΕΔͷ͕͋Δ w ̎࣍ݩతʹ༷ʑͳϑΟʔϧυΛஔͯ͠ɺϑΥʔϜΛ࡞ w ϢʔβʔσʔλΛཷΊ͍ͯ͘͜ͱ͕Ͱ͖Δ w ଞʹɺϓϩηεཧίϝϯτଞΞϓϦͷࢀরͳͲ͕Ͱ͖Δ w ݱࡏɺ$MPTVSF-JCSBSZ+4ˠ3FBDU54ʹ৽த
LJOUPOFʮΞϓϦʯͷೖྗը໘
LJOUPOFͷʮΞϓϦʯʹ͋Δ࣌ܥͷϑΟʔϧυ ҎԼͷϑΟʔϧυ͕͋Δ w ϑΟʔϧυΛೖྗͰ͖ΔϑΟʔϧυ w ࣌ࠁϑΟʔϧυ࣌ࠁΛೖྗͰ͖ΔϑΟʔϧυ w ࣌ϑΟʔϧυͱ࣌ࠁΛ߹ΘͤͯೖྗͰ͖ΔϑΟʔϧυ w ࡞࣌
ΈࠐΈϑΟʔϧυ σʔλΛ࡞͕ͨ࣌ࣗ͠ಈͰೖΔ w ߋ৽࣌ ΈࠐΈϑΟʔϧυ σʔλΛߋ৽͕ͨ࣌ࣗ͠ಈͰೖΔ
LJOUPOFͷʮΞϓϦʯʹ͋Δ࣌ܥͷϑΟʔϧυ
࣌ܥͷϑΟʔϧυ࣮ͷ՝ ΞϓϦͷϑΥʔϜͷঢ়ଶΛཧ͢Δ࣌ʹɺશ෦4USJOHܕͰΛཧ͍ͯͨ͠ export type DateFieldValue = { type: typeof FORM_INPUT_FIELD_TYPE.DATE;
value: string; }; export type TimeFieldValue = { type: typeof FORM_INPUT_FIELD_TYPE.TIME; value: string; };
શ෦ಉ͡ܕͩͱ߹͕ѱ͍ʁ
ಉ͡ੑ࣭ͷσʔλ͡Όͳ͍ ؾ͕͢ΔΜͩΑͳ͊
ྨͷ؍͕ͭ͋Δͱߟ͑ͨ
؍ಛఆͷҰॠΛࢦ͢σʔλ͔ʁ ࣌ͷσʔλʹಛఆͷҰॠΛʮࢦ͢ͷʯͱʮࢦ͞ͳ͍ͷʯ͕͋Δ ྫʮੜ݄ʯͱ͍͏ใ࣌ͷσʔλ͕ͩɺಛఆͷҰॠࢦ͞ͳ͍ ͦΕͧΕผͷ֓೦Ͱ͋ΓɺมʹෆՄٯੑ͕͋Δ 2025-11-23 2025-11-23 16:40 16:40 ❌ ❌
؍ϢʔβʔͷೖྗΛ͏͔ʁ ϢʔβʔϩʔΧϧ࣌ؒʹੜ͖͍ͯΔ w Ϣʔβʔ͕ೖྗ͢ΔͷৗʹϩʔΧϧ࣌ؒ w Ͳ͔͜ͰϑΥʔϜͷঢ়ଶˠ65$ͷม͕ඞཁʹͳΔ ٯʹϢʔβʔͷೖྗ มߋ ͕ͳ͍ͷͰ͋Ε w
දࣔલʹϩέʔϧͱλΠϜκʔϯΛՃຯͨ͠ϑΥʔϚοτΛ͢Δ͚ͩ w format(datetime)
݁શવಉ͡ੑ࣭ͷσʔλͰͳ͍ ؍ಛఆͷҰॠΛࢦ͢σʔλ͔ʁ w ಛఆͷҰॠΛࢦ࣌͢ߋ৽࣌࡞࣌ w ಛఆͷҰॠΛࢦ͞ͳ͍࣌ࠁ ؍ɿϢʔβʔೖྗΛ͏σʔλ͔ʁ w ೖྗΛ͏࣌࣌ࠁ w
ೖྗΛΘͳ͍ߋ৽࣌࡞࣌
݁ಉ͡ੑ࣭ͷσʔλͰͳ͍ ಛఆͷҰॠΛࢦ͢ ಛఆͷҰॠΛࢦ͞ͳ͍ ϢʔβʔೖྗΛ͏ ࣌ϑΟʔϧυ ࣌ࠁϑΟʔϧυϑΟʔϧυ ϢʔβʔೖྗΛΘͳ͍ ߋ৽࣌࡞࣌ϑΟʔϧυ
͡Ό͚͋Α͏
ϧʔϧ࣌ͱͯ͠ѻ͏σʔλΛྨ͠ݶఆ͢Δ ࣌ͱͯ͠ѻ͏ อ࣋͢Δ σʔλΛҎԼͷͭʹݶఆͨ͠ 65$*404USJOH"2025-11-23T07:40:00.000Z" %BUF4USJOH"2025-11-23" 5JNF4USJOH"16:40"
-PDBM%BUF5JNF0CKFDU{date: "2025-11-23", time: "16:40"} w %BUF4USJOHͱ5JNF4USJOHΛ߹Θͤͨͷ
ϧʔϧ࣌ͱͯ͠ѻ͍͍ͬͯσʔλ ಛఆͷҰॠΛࢦ͢ ಛఆͷҰॠΛࢦ͞ͳ͍ ϢʔβʔೖྗΛ͏ -PDBM%BUF5JNF0CKFDU ˣ 65$*404USJOH %BUF4USJOH5JNF4USJOH ϢʔβʔೖྗΛΘͳ͍ 65$*404USJOH
ؒ %BUFμϝͳͷ %BUFͷ··σʔλͷอ࣋ΓऔΓ͢Δ͜ͱඇਪʹͯ͠Δ ཧ༝ w ͦͦγεςϜλΠϜκʔϯ ↔︎ 65$͔͠αϙʔτ͍ͯ͠ͳ͍ w ೖग़ྗΛ65$γεςϜͷͲͬͪͰѻ͏͔͕҉త
w จࣈྻͷύʔε͕͔ͳΓτϦοΩʔ w ͜͜ʹօ͞Μͷࢥ͏ҙͷ%BUFͷෆຬΛೖΕΔ
ܕͰ͚͍ͨʂ
#SBOEFE5ZQFTͩʂ #SBOEFE5ZQFTͱ w ʮߏ͕ಉ͡ͳΒಉ͡ܕͱ͢Δʯͱ͍͏54ͷݪଇΛճආ͠ɺ w ߏ͕ಉ͡ܕͰޓ͍ʹ۠ผ͕ͭ͘Α͏ʹ͢Δख๏ ࣗͳΜͰ͔ΜͰಋೖ͢Δͷʹ৻ॏɻͰ࣌ʹؔͯ͠ w ಘΒΕΔԸܙ ࣌ͷ͜͠͞
#SBOEFE5ZQFTʹΑΔσϝϦοτ ͱࢥͬͯΔ
࣮ࡍͷίʔυ #SBOEFE5ZQFͷఆٛ ྫUTCISOStringܕ const utcisoStringBrand = Symbol('for UTCISOStringBrand'); export
type UTCISOString = string & { [utcisoStringBrand]: unknown; };
࣮ࡍͷίʔυ "TTFSUJPOؔηοτͰ࡞Δͱศར export function createUTCISOString( rawString: string, strict: boolean =
true ): UTCISOString { if (strict && !UTC_ISO_DATE_TIME_REGEX.test(rawString)) { throw new Error(`Invalid UTC ISO String : ${rawString}`); } return rawString as UTCISOString; }
'&Ͱ#SBOEFE5ZQFTʹҠߦ͢Δ࣌ͷίπ ֎෦͔ΒͷσʔλɾϢʔβʔೖྗɾ4UBUFͷ̏ํ͔ΒݫີԽ͢Δͱྑ͍ ίʔυ ϕʔε ֎෦σʔλ "1* 4UBUF Ϣʔβʔೖྗύʔπ ;PE4DIFNB "TTFSUJPO7BMJEBUJPO
ܕఆٛݫີԽ
#SBOEFE5ZQFTΛ࣌σʔλʹಋೖͯ͠Έͯ ܕΛݟΔ͚ͩͰɺԿΛͯ͘͠ΕΔͷ͔Ұྎવ w ྫҾ͕-PDBM%BUF5JNF0CKFDUฦΓ͕65$*404UJOH w ˠ*40ܗࣜͳΜͩͳʂฦΓ65$ͳͷͰ࣌ࠩมͯ͠Δʂ ܕΤϥʔ͕ग़ΔͷͰؒҧ͍ͬͯͦ͏ͳͱ͜ΖΛൃݟɾ༧Ͱ͖Δ w ࣌ͷυϝΠϯʹৄ͘͠ͳ͍δϡχΞϝϯόʔͰ҆৺ νʔϜͰͷڞ௨ݴޠʹͳΔ
Α͏ʹؤுͬͯΔͱ͜Ζ
͜͜·ͰͰेศར͚ͩͲ
কདྷΛݟਾ͑Δ
࣌Yকདྷ
࣌Yকདྷ5FNQPSBM
5FNQPSBMΛҙࣝͯ͠Δ ࣮͜ͷྨ5FNQPSBMΛࢀߟʹ͍ͯ͠Δ ͱ͍͏͔͓ͷͣͱͦ͏ͳΔ 5FNQPSBMͱͷରԠؔ w 65$*404USJOHTemporal.Instant w %BUF4USJOHTeporal.PlainDate w
5JNF4USJOHTeporal.PlainTime w -PDBM%BUF5JNF0CKFDUTeporal.PlainDateTime
5FNQPSBMΛҙࣝͯ͠Δ UTCISOString LocalDateTimeObj DateStiring TimeString
5FNQPSBMͷੴ ݁ہ5FNQPSBM͕ղܾ͔ͨͬͨ͜͠ͱͱಉࠜͷͩͬͨ w ͦΕΛ#SBOEFE5ZQFͰղܾͯ͠Δ w ·ͩ5FNQPSBM͔͔࣌ؒΓͦ͏ͳͷͰ ٯʹݴ͑ɺ5FNQPSBMҠߦ؆୯ʹͳΔͣͰ͢Ͷʂ w ରରԠͯ͠ΔͷͰมͯ͠Δ͚ͩͰ͍͍
·ͱΊ ࣌ͷσʔλΛѻ͏ͷ͍͠ w ಛʹಠཱͨ࣌͠ࠁΛѻ͏߹%BUFͷ͍উख͕ LJOUPOFͷΞϓϦը໘৽Ͱ#SBOEFE5ZQFTͰ࣌σʔλΛྨɾ੍ݶͯ͠Δ w ϝϦοτڗडͰ͖ͯΔ ͱࢥ͏ ࣌σʔλͷྨ5FNQPSBMΛࢀߟʹ
ݟӽͯ͠ ࡞͍ͬͯΔ w ૣ͘5FNQPSBM͕͘Εղܾ͢Δͷʹͳ͊ ࣌σʔλͷཧͰࠔͬͨͱ͖#SBOEFE5ZQFT͕ॿ͚ʹͳΔ͔͠Εͳ͍
4BKJ3ZVTFJ4BKJLJ 'SPOUFOE%FWFMPQFSBU$ZCP[V JOD 𝕏 !TBKJLJY
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠