Share
Embed
フロントエンドで日時処理と戦うために 2025 ver
JSConf.jp おかわり Node学園46時限目
- https://nodejs.connpass.com/event/344588/
X
- https://twitter.com/sajikix
Saji
February 28, 2025
Transcript
67 slides
-
͓ॻ͖ ࣌ͷجຊʹ͍͓ͭͯ͞Β͍ ίϯϐϡʔλ8FCͰ࣌Λѻ͏ͨΊͷ༷ +4ͷ%BUFͱͦͷ՝ɾϥΠϒϥϦͷར༻ *OUMʹΑΔॻࣜԽͷվળ
ࠓޙ5FNQPSBMͰͲ͏มΘΔͷ͔ ݁ہࠓҙࣝͨ͠ํ͕͍͍͜ͱ -
αϚʔλΠϜ %45EBZMJHIUTBWJOHUJNF தͷ͕࣌ؒ͘ͳΔՆͷؒɺ࣌ܭΛਐΊΔ͜ͱͰ͕ΕΔ࣌ࠁΛΒͤΔ w य़ࠒ࣌ؒΛ̍࣌ؒਐΊΔ w ͕̍࣌ؒ͘ͳΔ w ࣮ࢪͷதͷͲ͔͜ͷ͕̍࣌ؒແ͘ͳΔ w
ळࠒ࣌ؒΛ̍࣌ؒ͢ w ͕̍࣌ؒ͘ͳΔ w ࣮ࢪͷதͷͲ͔͜Ͱಉ࣌͡ࠁ͕̎ճདྷΔ -
࣌ͷදه3'$ 3'$ ͜͏͍͏ͭ ిࢠϝʔϧͷ༷3'$Ͱ࣌ͷදهͱܾͯ͠ΊΒΕͨ w ͜ͷܗࣜ)551Ͱܧঝ͞Εɺਪ͞ΕΔ࣌ͷදهͱͯ͠ఆٛ w )551 ͭྺ࢙తܦҢͱޙํޓੑ͔Βαϙʔτ͢Δܗ͕ࣜ͋Δ͕ʜ
+4ʹ͓͍ͯɺ%BUFQSPUPUZQFUP65$4USJOH ͰੜͰ͖Δ Sun, 06 Nov 1994 08:49:37 GMT -
࣌ͷදه+4Ͱͷඪ४ϑΥʔϚοτ &$."4DSJQUʮ*40֦ுܗࣜΛ୯७Խͨ͠ͷʯΛඪ४ͱͯ͠Δ > ECMAScript de fi nes a string interchange
format for date-times based upon a simpli fi cation of the ISO 8601 calendar date extended format. The format is as follows: YYYY-MM-DDTHH:mm:ss.sssZ ͭ·Γ*40֦ுܗࣜ㲈3'$㲈+4ͷඪ४ϑΥʔϚοτ w ຊશ෦Ϗϛϣʔʹҧ͏͚ͲجຊϋϚΔ͜ͱͳ͍ͣ %BUFQSPUPUZQFUP65$4USJOH ͰੜͰ͖Δ -
ʲ༨ஊʳλΠϜκʔϯͷਖ਼نԽ λΠϜκʔϯɾλΠϜκʔϯ໊มΘΔ͜ͱ͕͋Δ w κʔϯͷ߹ซ"UMBOUJD3FZLKBWJL"GSJDB"CJEKBO w ໊ͷมߋ"TJB$BMDVUUB"TJB,PMLBUB ݱঢ়ϒϥβʹΑͬͯਖ਼نԽͷڍಈ͕ඍົʹҧ͏ w ʮจࣈྻԽͯ͠ൺֱʯͱ͔ͪ͠Ό͏ͱఆ֎ͷڍಈʹͳͬͨΓ͢Δʜ w
)BOEMJOH5JNF;POF$BOPOJDBMJ[BUJPO$IBOHFTͱͯ͠5FNQPSBMͱಉ࣌ʹ ڍಈͷվળ͕ਐΊΒΕ͍ͯΔɻ -
ΧϨϯμʔJ$BMFOEBS3'$ εέδϡʔϧͷඪ४ϑΥʔϚοτ w ΧϨϯμʔΞϓϦిࢠϝʔϧͰ༧ఆใΛΓऔΓͰ͖Δ αϚʔλΠϜͷڥք࣌ࠁղܾํ๏ʹ͍ͭͯᐆດʹͳΒͳ͍Α͏ఆٛ͞ΕͯΔ w λΠϜκʔϯ͕ਖ਼ͷํมԽ ։࢝࣌ ͍ํΛબ w
λΠϜκʔϯ͕ෛͷํมԽ ऴྃ࣌ ૣ͍ํΛબ w ͜Ε%BUFଟ͘ͷϥΠϒϥϦͷڍಈͱҰக͢Δ -
ʲ༨ஊʳݴޠλάͷ֦ுαϒλά ֦ுαϒλάͬͯԿʁ w <ݴޠ><จࣈମܥ><Ҭ><ҟମ><֦ு><ࢲ༻> w ݴޠλάΛ֦ுͰ͖Δߏจ w <จࣈ><dจࣈ>ͱ͍͏ܗࣜ ྫKB+1VDBKBQBOFTF
w *&5'͔ΒͷϨϏϡʔΛड͚ͯ*"/"͔ΒׂΓͯΒΕͨͷ AYAҎ֎ 6֦ு u-Ͱ࢝·Δͭ 6OJDPEF͕ཧ͍ͯ͠Δˠ-%.-Λࢀরͷ͜ͱ -
ॻࣜԽͷͨΊͷ༷-%.- 654 -%.- -PDBMF%BUB.BSLVQ-BOHVBHF ͱ w 6OJDPEF͕ఆΊ͍ͯΔϩέʔϧࠃࡍԽʹؔ͢Δ͋ΒΏΔσʔλΛه͢Δ ͨΊͷ౷Ұతͳ9.-ʹΑΔϑΥʔϚοτ w ϩέʔϧࣝผࢠ࣌ͷϑΥʔϚοτෳܗংʜ
࣌ʹؔͯ͠ॻࣜԽͷύλʔϯྐྵͷใͳͲͷܗࣜΛఆΊͯΔ w Α͘͏1BUUFSOจࣈྻ ZZZZ..EE ͷҙຯͳͲఆٛͯ͠Δ w ༨ஊ ͜Εʹैͬͯͳ͍ϥΠϒϥϦͪΒ΄Βʜ -
·ͱΊ %BUF5JNF *"/" 5JNF[POF 6OJDPEF -%.- $-%3 *&5' 3'$
#$1 *OUM &$." #$1 3'$ -
+4ͷ%BUFͷԿ͕ਏ͍͔ γεςϜͱ65$ͷλΠϜκʔϯ͔͠αϙʔτ͠ͳ͍ άϨΰϦεྐྵҎ֎͑ͳ͍ ࣌จࣈྻͷύʔεڍಈ͕Θ͔Γʹ͍͘ 4FUܥͷϝιου͕ഁյมߋͳͷ͕͍ʹ͍͘
ܭࢉܥͷϢʔςΟϦςΟϝιου͕ͳ͍ *OUMҎલ ॻࣜԽػೳෆ͍ͯͨ͠ -
࣌จࣈྻͷύʔεڍಈ͕Θ͔Γʹ͍͘ ༗໊·Ͱͩͱ65$͚ͩͲ࣌ࠁؚΊΔͱγεςϜͷλΠϜκʔϯʹͳΔ • 2025-02-27 → "Thu Feb 27 2025 09:00:00
GMT+0900" • 2025-02-27T00:00:00 → "Thu Feb 27 2025 00:00:00 GMT+0900" ্༷໌ه͞Εͯͳ͍͚ͲύʔεͰ͖ͪΌ͏ͭ͋Δ • RFC 2822ܗࣜ : "Thu Feb 27 2025" • εϥογϡ(/) ۠Γ : "2025/02/27" -
*OUM%BUF5JNF'PSNBUͰେମͷχʔζຬͨͤΔ *OUM%BUF5JNF'PSNBUͷॻࣜԽΦϓγϣϯ͕͔ͳΓਐา͍ͯ͠Δ w EBUF4UZMFUJNF4UZMFͰ·ͱΊͯελΠϧࢦఆ w ֤ߏཁૉ ZFBSNPOUIEBZ ͝ͱʹࡉ͔͘ελΠϧ͕ௐͰ͖Δ const formatter
= new Intl.DateTimeFormat('en-US', { year: 'numeric', // Ͱදࣔ month: 'long', // ͍ܗͰදࣔ day: '2-digit', // 2 ܻͷͰදࣔ weekday: 'long', // ͍ܗͰදࣔ era: 'short' // ͍ܗͰදࣔ }); -
*OUMʹGPSNBU5P1BSUT ϝιου͋Δ ߏཁૉ͝ͱͷྻͱͯ͠ग़ྗͯ͘͠ΕΔ Ͳ͏ͯ͠GPSNBUϝιουͰతͷจࣈྻ͕ग़ͳ͍߹ w GSPNBU5P1BSUTϝιουˠҰ෦ॻ͖͑ˠWBMVFΛKPJOˠతͷจࣈྻ new Intl.DateTimeFormat("ja-JP").formatToParts(new Date(2024, 11,
7)); // [ // { "type": "year", "value": "2024" }, // { "type": "literal", "value": "/" }, // { "type": "month", "value": "12" }, // { "type": "literal", "value": "/" }, // { "type": "day", "value": "7" } // ] -
ʲ༨ஊʳ1BUUFSOʹΑΔॻࣜԽͷޭࡑ ΈΜͳ1BUUFSOจࣈྻ ZZZZ..EE ͰॻࣜԽ͕ͨ͠Δ͚Ͳʜ w 1BUUFSOจࣈྻΛࣗͰཧࠃࡍॻࣜԽػೳΛશ෦ࣗલͰΔ֮ޛ w ͦͷ1BUUFSOਖ਼֬ʁଞϩέʔϧߟྀͰ͖ͯΔʁϩέʔϧؒͰ౷Ұੑ͋Δ w
*OUM-PDBMFͱ%BUF͔ΒͳΔ͘దͰ౷Ұײ͋ΔΑ͏ʹจࣈྻΛબ͢Δ ͦΕ͋ͬͯ*OUMଆجຊ1BUUFSOॻࣜԽΛରԠ͠ͳ͍ํΛ؏͍͍ͯΔ ͰͬͺΓࠜڧ͍ʮཉ͍͠ʯͷ w 5FNQPSBMWͰೖΔʜ͔Ͷ -
ύʔεͷݫ֨Խͱ*9%5' 5FNQPSBMݫີʹ3'$ͱͦΕΛ֦ுͨ͠3'$ͷΈαϙʔτ RFC 3339 : ISO8601ͱ΄΅Ұॹ / toISOString() ͷ݁Ռ •
"2025-02-27T00:00:00.000Z" 3'$*OUFSOFU&YUFOEFE%BUF5JNF'PSNBU *9%5' w 3'$ͷλΠϜκʔϯΧϨϯμʔใΛՃͰ͖ΔΑ͏֦ு • "2025-02-27T00:00:00.000Z[Asia/Tokyo][u-ca-japanese]" -
ඇഁյϝιουͰܭࢉϝιου͋Δ 5FNQPSBMͷ࣌ૢ࡞ܥͷ"1*جຊඇഁյϝιου ܭࢉϝιου ܭࢉܥͷϝιου͋Δ w Ճࢉݮࢉظؒͷܭࢉൺֱ • zonedDateTime.add(duration) •
ظؒΛද͢ Temporal.Duration ΫϥεΛར༻Ͱ͖Δ • Temporal.Duration.from({ days: 1, hours: 12 }); -
5FNQPSBMͱ*OUM ֤$MBTTͷUP-PDBM4USJOH w *OUM%BUF5JNF'PSNBU w *OUM%VSBUJPO'PSNBU 🆕࠷ۙ4UBHFʹͳͬͨΑʂ ͱΦϓγϣϯϩέʔϧͷѻ͍͕Ұॹ΄΅ϥούʔͷΑ͏ʹ͑Δ
·ͨɺରԠ͢ΔΧϨϯμʔ*OUM%BUF5JNF'PSNBUͱҰॹ w 5FNQPSBM͔ΒͰΧϨϯμʔΛ౿·͑ͨॻࣜԽ͕ߦ͑Δ -
5FNQPSBMͷΞϓϩʔν ֤ΦϒδΣΫτͰ໌֬ʹʮઈର࣌ؒPSϩʔΧϧ࣌ʯΛ۠ผ • ઈର࣌ؒ : Temporal.Instant • ϩʔΧϧͳ࣌ : Temporal.Plainʓʓ
• ϩʔΧϧͳ࣌ʹΧϨϯμʔΛࢦఆͰ͖Δ มʹλΠϜκʔϯใ͕ඞཁˠڮ͠ͷͨΊͷΫϥε • Temporal.ZonedDateTime Ͱ૬ޓͷมΛߦ͏ -
5FNQPSBMʹ͍ͭͯͬͱৄ͘͠ ࠷ۙ.%/͕Ճ͞Εͨ ͳΜͱͦͷྔϖʔδʂ w IUUQTEFWFMPQFSNP[JMMBPSHFO64EPDT8FC+BWB4DSJQU3FGFSFODF (MPCBM@0CKFDUT5FNQPSBM HJIZPKQͷॴଐνʔϜ࿈ࡌͰॻ͔͍͖ͤͯͨͩ·ͨ͠ એ
w 5FNQPSBMͰมΘΔ+BWB4DSJQUͷ࣌ૢ࡞ w ΑΓ۩ମతͳϢʔεέʔεͱ͔ॻ͍ͯΔ -
΄΅ɺλΠϜκʔϯͱΧϨϯμʔͱॻࣜԽͷ͍ͤ ࣌ͷΊΜͲ͘͞͞Λղ͢Δͱ w λΠϜκʔϯ ࣌ࠩ ͷܭࢉ͕໘ w ΧϨϯμʔ ྐྵ ͷॲཧ͕͍͠
w ࠃࡍԽͰͷॻࣜԽύλʔϯ͕ແ ΈΜͳ͕6OJY5JNF 1PTJY5JNF ͰಡΈॻ͖Ͱ͖ͯΕ͘͜͠ͳ͍ w ͚Ͳਓؒͦ͏Ͱ͖͍ͯͳ͍ ࠓͷ5BML͔ΒͩΑʂʂ -
λΠϜκʔϯ͕͍͜͠ ϩʔΧϧͳ࣌ͱઈରతͳ࣌ͷڥքΛҙࣝ͢Δઃܭ w λΠϜκʔϯʹΑΔมΛͪΌΜͱ࡞Δ ઈରత࣌ 4FSWFS Formated String User Input
4FSWFS ϩʔΧϧͳ࣌ ઈରత࣌ ϩʔΧϧͳ࣌ ม ม -
ͦͦάϨΰϦεྐྵҎ֎ͷΧϨϯμʔΛαϙʔτ͢ΔϥΠϒϥϦগͳ͍ ΧϨϯμʔ͕ؔ͋Δͷ͋͘·ͰʮϩʔΧϧͳ࣌ʯଆͳ͜ͱΛҙࣝ͢Δ ΧϨϯμʔ͕͍͠ ઈରత࣌ 4FSWFS Formated String User Input 4FSWFS
ϩʔΧϧͳ࣌ ઈରత࣌ ϩʔΧϧͳ࣌ ม ม ར༻͢ΔΧϨϯμʔ -
ʲະདྷʳ࣌ͷ໘ࣄˠ5FNQPSBM *OUMͰղܾ ࣌ͷෳࡶͩͬͨ෦Λ5FNQPSBMͱ*OUMͰΧόʔͰ͖Δະདྷ w λΠϜκʔϯ ࣌ࠩ ͷܭࢉ͕໘ˠ5FNQPSBMͷ୲ w ΧϨϯμʔ ྐྵ
ͷॲཧ͕͍͠ˠ5FNQPSBMͷ୲ w ࠃࡍԽͰͷॻࣜԽύλʔϯ͕ແˠ*OUMͷ୲ ͋Δ͍ˢΛ͍͍ײ͡ʹϥοϓͨ͠ϥΠϒϥϦ͕ྲྀߦΔՄೳੑ ˠ͜ͷະདྷΛ৴͡Δ߹ɺٯࢉͯ͠Ͳ͏͓͖ͯͩ͘͠Ζ͏ʁ -
ݱঢ়Ͱͷબࢶ ݱঢ়͜Μͳײ͡ʹ͓ͯ͘͠ͷ͕ྑͦ͞͏ w λΠϜκʔϯ ࣌ࠩ ͷܭࢉ͕໘ w ˠϥΠϒϥϦͰؤுΓͭͭɺ5FNQPSBMΛͭ w ΧϨϯμʔ
ྐྵ ͷॲཧ͕͍͠ w ˠϥΠϒϥϦ࣮ͰؤுΓͭͭɺ5FNQPSBMΛͭPSະαϙʔτ w ࠃࡍԽͰͷॻࣜԽύλʔϯ͕ແˠ*OUM͏͋ΔͷͰͳΔ͘͏ -
ʲ࠶ܝʳλΠϜκʔϯ͕͍͜͠ ϩʔΧϧͳ࣌ͱઈରతͳ࣌ͷڥքΛҙࣝ͢Δઃܭ w λΠϜκʔϯʹΑΔมΛͪΌΜͱ࡞Δ ઈରత࣌ 4FSWFS Formated String User Input
4FSWFS ϩʔΧϧͳ࣌ ઈରత࣌ ϩʔΧϧͳ࣌ ม ม -
5FNQPSBMͷҠߦָ͕ʹ ϩʔΧϧ࣌ͱઈର࣌ͷڥքΛ໌֬ʹ͢Δͱ5FNQPSBMʹҠߦ͍͢͠ ;POFE%BUF5JNF *OTUBOU ;POFE%BUF5JNF 1MBJO%BUF5JNF *OTUBOU 4FSWFS FormatedString Input
Component 4FSWFS ར༻͢Δ5JN[F;POF toLocaleString() ܭࢉ BEEVOUJMʜ DBMFOEBS -
*OUMͰॻࣜԽΛؤுΔ࣌ ҎԼͷॱͰߟ͍͑ͯ͘ͱྑ͍ ͦ͜·Ͱڧ͘ϑΥʔϚοτʹͩ͜ΘΒͳ͍ w ·ͣ*OUMͷEBUF4UZMFUJNFTUZMFͰҰׅࢦఆͯ͠ΈΔ ͋Δఔίϯτϩʔϧ͍ͨ͠ w *OUMͰࡉ͔͍୯Ґ
݄ʜ ͝ͱͷTUZMFΛࢦఆͯ͠ΈΔ Ͱຬ͍͔ͳ͍߹ w GPSNBU5P1BSUTͰΧελϚΠζ 1BUUFOจࣈྻʹΑΔॻࣜԽߟྀʹʁ -
࣌ͷอଘܗࣜ جຊతʹ6OJY5JNFPS3'$65$จࣈྻͰอଘ͓ͯ͘͠ͱྑͦ͞͏ w ͋Δ͍ՃͰλΠϜκʔϯΛ࣋ͭ w λΠϜκʔϯ࣋ͭ߹ུ͞ͳ͍ํ͕ྑ͍ ❌+45✅<"TJB5PLZP> কདྷతʹ*9%5'ʹҠߦ͍ͯ͘͠ͷ͋Γ w
*9%5'͋͘·Ͱ3'$ͷ֦ு w 3'$ͦͷ··αϙʔτ͞ΕΔͷͰ -
·ͱΊ ࣌ͷجຊʹ͍ͭͯ໘ͳ෦ͳͲΛৼΓฦͬͨ ίϯϐϡʔλ8FCͰ࣌Λѻ͏ͨΊͷ༷ʹ͍ͭͯ֓؍ͨ͠ +4ͷ%BUFͷ՝ͱϥΠϒϥϦ*OUM͕Ͳ͏վળ͖͔ͯͨ͠ ࠓޙ͍͠ͱ͜ΖΛ5FNQPSBM *OUMͰΧόʔͰ͖ΔͷͰ
̐ͷະདྷʹ͚ͯ࣌Λѻ͏্ͰؾΛ͚͍ͭͨ͜ͱΛԿݸ͔հͨ͠