@@ -3,29 +3,141 @@ import { assertEquals, assertThrows } from "@std/assert";
33import { FakeTime } from "@std/testing/time" ;
44import { DateTimeFormatter } from "./_date_time_formatter.ts" ;
55
6- Deno . test ( "dateTimeFormatter.format()" , ( ) => {
7- const cases = [
8- [ "yyyy-MM-dd HH:mm:ss a" , new Date ( 2020 , 0 , 1 ) , "2020-01-01 00:00:00 AM" ] ,
9- [
10- "yyyy-MM-dd HH:mm:ss a" ,
11- new Date ( 2020 , 0 , 1 , 23 , 59 , 59 ) ,
12- "2020-01-01 23:59:59 PM" ,
13- ] ,
14- [
15- "yyyy-MM-dd hh:mm:ss a" ,
16- new Date ( 2020 , 0 , 1 , 23 , 59 , 59 ) ,
17- "2020-01-01 11:59:59 PM" ,
18- ] ,
19- [ "yyyy-MM-dd a" , new Date ( 2020 , 0 , 1 ) , "2020-01-01 AM" ] ,
20- [ "yyyy-MM-dd HH:mm:ss a" , new Date ( 2020 , 0 , 1 ) , "2020-01-01 00:00:00 AM" ] ,
21- [ "yyyy-MM-dd hh:mm:ss a" , new Date ( 2020 , 0 , 1 ) , "2020-01-01 12:00:00 AM" ] ,
22- [ "yyyy" , new Date ( 2020 , 0 , 1 ) , "2020" ] ,
23- [ "MM" , new Date ( 2020 , 0 , 1 ) , "01" ] ,
24- ] as const ;
25- for ( const [ format , date , expected ] of cases ) {
26- const formatter = new DateTimeFormatter ( format ) ;
27- assertEquals ( formatter . format ( date ) , expected ) ;
28- }
6+ Deno . test ( "dateTimeFormatter.format()" , async ( t ) => {
7+ await t . step ( "handles basic cases" , ( ) => {
8+ const cases : [ string , Date , string ] [ ] = [
9+ [ "yyyy-MM-dd HH:mm:ss a" , new Date ( 2020 , 0 , 1 ) , "2020-01-01 00:00:00 AM" ] ,
10+ [
11+ "yyyy-MM-dd HH:mm:ss a" ,
12+ new Date ( 2020 , 0 , 1 , 23 , 59 , 59 ) ,
13+ "2020-01-01 23:59:59 PM" ,
14+ ] ,
15+ [
16+ "yyyy-MM-dd hh:mm:ss a" ,
17+ new Date ( 2020 , 0 , 1 , 23 , 59 , 59 ) ,
18+ "2020-01-01 11:59:59 PM" ,
19+ ] ,
20+ [ "yyyy-MM-dd a" , new Date ( 2020 , 0 , 1 ) , "2020-01-01 AM" ] ,
21+ [ "yyyy-MM-dd HH:mm:ss a" , new Date ( 2020 , 0 , 1 ) , "2020-01-01 00:00:00 AM" ] ,
22+ [ "yyyy-MM-dd hh:mm:ss a" , new Date ( 2020 , 0 , 1 ) , "2020-01-01 12:00:00 AM" ] ,
23+ ] ;
24+ for ( const [ format , date , expected ] of cases ) {
25+ const formatter = new DateTimeFormatter ( format ) ;
26+ assertEquals ( formatter . format ( date ) , expected ) ;
27+ }
28+ } ) ;
29+
30+ await t . step ( "handles yyyy" , ( ) => {
31+ const formatter = new DateTimeFormatter ( "yyyy" ) ;
32+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 ) ) , "2020" ) ;
33+ assertEquals ( formatter . format ( new Date ( 20202 , 0 , 1 ) ) , "20202" ) ;
34+ } ) ;
35+ await t . step ( "handles yy" , ( ) => {
36+ const formatter = new DateTimeFormatter ( "yy" ) ;
37+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 ) ) , "20" ) ;
38+ assertEquals ( formatter . format ( new Date ( 20202 , 0 , 1 ) ) , "02" ) ;
39+ } ) ;
40+
41+ await t . step ( "handles MM" , ( ) => {
42+ const formatter = new DateTimeFormatter ( "MM" ) ;
43+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 ) ) , "01" ) ;
44+ assertEquals ( formatter . format ( new Date ( 2020 , 11 , 1 ) ) , "12" ) ;
45+ } ) ;
46+ await t . step ( "handles M" , ( ) => {
47+ const formatter = new DateTimeFormatter ( "M" ) ;
48+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 ) ) , "1" ) ;
49+ assertEquals ( formatter . format ( new Date ( 2020 , 11 , 1 ) ) , "12" ) ;
50+ } ) ;
51+
52+ await t . step ( "handles dd" , ( ) => {
53+ const formatter = new DateTimeFormatter ( "dd" ) ;
54+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 ) ) , "01" ) ;
55+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 22 ) ) , "22" ) ;
56+ } ) ;
57+ await t . step ( "handles d" , ( ) => {
58+ const formatter = new DateTimeFormatter ( "d" ) ;
59+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 ) ) , "1" ) ;
60+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 22 ) ) , "22" ) ;
61+ } ) ;
62+
63+ await t . step ( "handles HH" , ( ) => {
64+ const formatter = new DateTimeFormatter ( "HH" ) ;
65+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 ) ) , "00" ) ;
66+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 22 , 0 , 0 ) ) , "22" ) ;
67+ } ) ;
68+ await t . step ( "handles H" , ( ) => {
69+ const formatter = new DateTimeFormatter ( "H" ) ;
70+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 ) ) , "0" ) ;
71+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 22 , 0 , 0 ) ) , "22" ) ;
72+ } ) ;
73+ await t . step ( "handles hh" , ( ) => {
74+ const formatter = new DateTimeFormatter ( "hh" ) ;
75+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 ) ) , "12" ) ;
76+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 1 , 0 , 0 ) ) , "01" ) ;
77+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 22 , 0 , 0 ) ) , "10" ) ;
78+ } ) ;
79+ await t . step ( "handles h" , ( ) => {
80+ const formatter = new DateTimeFormatter ( "h" ) ;
81+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 ) ) , "12" ) ;
82+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 1 , 0 , 0 ) ) , "1" ) ;
83+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 22 , 0 , 0 ) ) , "10" ) ;
84+ } ) ;
85+
86+ await t . step ( "handles mm" , ( ) => {
87+ const formatter = new DateTimeFormatter ( "mm" ) ;
88+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 ) ) , "00" ) ;
89+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 1 , 0 ) ) , "01" ) ;
90+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 22 , 0 ) ) , "22" ) ;
91+ } ) ;
92+ await t . step ( "handles m" , ( ) => {
93+ const formatter = new DateTimeFormatter ( "m" ) ;
94+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 ) ) , "0" ) ;
95+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 1 , 0 ) ) , "1" ) ;
96+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 22 , 0 ) ) , "22" ) ;
97+ } ) ;
98+
99+ await t . step ( "handles ss" , ( ) => {
100+ const formatter = new DateTimeFormatter ( "ss" ) ;
101+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 ) ) , "00" ) ;
102+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 1 ) ) , "01" ) ;
103+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 22 ) ) , "22" ) ;
104+ } ) ;
105+ await t . step ( "handles s" , ( ) => {
106+ const formatter = new DateTimeFormatter ( "s" ) ;
107+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 ) ) , "0" ) ;
108+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 1 ) ) , "1" ) ;
109+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 22 ) ) , "22" ) ;
110+ } ) ;
111+
112+ await t . step ( "handles SSS" , ( ) => {
113+ const formatter = new DateTimeFormatter ( "SSS" ) ;
114+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 , 105 ) ) , "105" ) ;
115+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 , 10 ) ) , "010" ) ;
116+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 , 0 ) ) , "000" ) ;
117+ } ) ;
118+ await t . step ( "handles SS" , ( ) => {
119+ const formatter = new DateTimeFormatter ( "SS" ) ;
120+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 , 105 ) ) , "10" ) ;
121+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 , 10 ) ) , "01" ) ;
122+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 , 0 ) ) , "00" ) ;
123+ } ) ;
124+ await t . step ( "handles S" , ( ) => {
125+ const formatter = new DateTimeFormatter ( "S" ) ;
126+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 , 105 ) ) , "1" ) ;
127+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 , 10 ) ) , "0" ) ;
128+ assertEquals ( formatter . format ( new Date ( 2020 , 0 , 1 , 0 , 0 , 0 , 0 ) ) , "0" ) ;
129+ } ) ;
130+
131+ await t . step ( "handles utc" , ( ) => {
132+ const formatter = new DateTimeFormatter ( "HH:mm" ) ;
133+ assertEquals (
134+ formatter . format (
135+ new Date ( "2020-01-01T06:30:00.000-01:30" ) ,
136+ { timeZone : "UTC" } ,
137+ ) ,
138+ "08:00" ,
139+ ) ;
140+ } ) ;
29141} ) ;
30142
31143Deno . test ( "dateTimeFormatter.format() with empty format string returns empty string" , ( ) => {
@@ -55,20 +167,66 @@ Deno.test("dateTimeFormatter.formatToParts()", async (t) => {
55167 { type : "day" , value : "01" } ,
56168 ] ) ;
57169 } ) ;
170+ await t . step ( "handles case without separators" , ( ) => {
171+ const format = "yyyyMMdd" ;
172+ const formatter = new DateTimeFormatter ( format ) ;
173+ assertEquals ( formatter . formatToParts ( "20200101" ) , [
174+ { type : "year" , value : "2020" } ,
175+ { type : "month" , value : "01" } ,
176+ { type : "day" , value : "01" } ,
177+ ] ) ;
178+ } ) ;
179+
180+ await t . step ( "throws on an empty string" , ( ) => {
181+ const format = "yyyy-MM-dd" ;
182+ const formatter = new DateTimeFormatter ( format ) ;
183+ assertThrows (
184+ ( ) => formatter . formatToParts ( "" ) ,
185+ Error ,
186+ "Cannot format value: The value is not valid for part { year undefined } " ,
187+ ) ;
188+ } ) ;
189+ await t . step ( "throws on a string which exceeds the format" , ( ) => {
190+ const format = "yyyy-MM-dd" ;
191+ const formatter = new DateTimeFormatter ( format ) ;
192+ assertThrows (
193+ ( ) => formatter . formatToParts ( "2020-01-01T00:00:00.000Z" ) ,
194+ Error ,
195+ "datetime string was not fully parsed!" ,
196+ ) ;
197+ } ) ;
198+ await t . step ( "throws on malformatted year" , ( ) => {
199+ const format = "yyyy-MM-dd" ;
200+ const formatter = new DateTimeFormatter ( format ) ;
201+ assertThrows (
202+ ( ) => formatter . formatToParts ( "20-01-01" ) ,
203+ Error ,
204+ "Cannot format value: The value is not valid for part { year undefined } 20" ,
205+ ) ;
206+ } ) ;
58207
59208 await t . step ( "handles yy" , ( ) => {
60209 const format = "yy" ;
61210 const formatter = new DateTimeFormatter ( format ) ;
62211 assertEquals ( formatter . formatToParts ( "20" ) , [
63212 { type : "year" , value : "20" } ,
64213 ] ) ;
214+ assertEquals ( formatter . formatToParts ( "00" ) , [
215+ { type : "year" , value : "00" } ,
216+ ] ) ;
217+ assertThrows ( ( ) => formatter . formatToParts ( "2" ) ) ;
218+ assertThrows ( ( ) => formatter . formatToParts ( "202" ) ) ;
219+ assertThrows ( ( ) => formatter . formatToParts ( "2020" ) ) ;
65220 } ) ;
66221 await t . step ( "handles yyyy" , ( ) => {
67222 const format = "yyyy" ;
68223 const formatter = new DateTimeFormatter ( format ) ;
69224 assertEquals ( formatter . formatToParts ( "2020" ) , [
70225 { type : "year" , value : "2020" } ,
71226 ] ) ;
227+ assertThrows ( ( ) => formatter . formatToParts ( "20" ) ) ;
228+ assertThrows ( ( ) => formatter . formatToParts ( "202" ) ) ;
229+ assertThrows ( ( ) => formatter . formatToParts ( "20202" ) ) ;
72230 } ) ;
73231 await t . step ( "handles M" , ( ) => {
74232 const format = "M" ;
@@ -181,64 +339,77 @@ Deno.test("dateTimeFormatter.formatToParts()", async (t) => {
181339 assertEquals ( formatter . formatToParts ( "1" ) , [
182340 { type : "fractionalSecond" , value : "1" } ,
183341 ] ) ;
342+ assertEquals ( formatter . formatToParts ( "0" ) , [
343+ { type : "fractionalSecond" , value : "0" } ,
344+ ] ) ;
345+ assertThrows ( ( ) => formatter . formatToParts ( "00" ) ) ;
184346 } ) ;
185347 await t . step ( "handles SS" , ( ) => {
186348 const format = "SS" ;
187349 const formatter = new DateTimeFormatter ( format ) ;
188350 assertEquals ( formatter . formatToParts ( "10" ) , [
189351 { type : "fractionalSecond" , value : "10" } ,
190352 ] ) ;
353+ assertEquals ( formatter . formatToParts ( "01" ) , [
354+ { type : "fractionalSecond" , value : "01" } ,
355+ ] ) ;
356+ assertEquals ( formatter . formatToParts ( "00" ) , [
357+ { type : "fractionalSecond" , value : "00" } ,
358+ ] ) ;
359+ assertThrows ( ( ) => formatter . formatToParts ( "0" ) ) ;
360+ assertThrows ( ( ) => formatter . formatToParts ( "000" ) ) ;
191361 } ) ;
192362 await t . step ( "handles SSS" , ( ) => {
193363 const format = "SSS" ;
194364 const formatter = new DateTimeFormatter ( format ) ;
195365 assertEquals ( formatter . formatToParts ( "100" ) , [
196366 { type : "fractionalSecond" , value : "100" } ,
197367 ] ) ;
198- } ) ;
199- await t . step ( "handles a" , ( ) => {
200- const format = "a" ;
201- const formatter = new DateTimeFormatter ( format ) ;
202- assertEquals ( formatter . formatToParts ( "AM" ) , [
203- { type : "dayPeriod" , value : "AM" } ,
368+ assertEquals ( formatter . formatToParts ( "010" ) , [
369+ { type : "fractionalSecond" , value : "010" } ,
370+ ] ) ;
371+ assertEquals ( formatter . formatToParts ( "000" ) , [
372+ { type : "fractionalSecond" , value : "000" } ,
204373 ] ) ;
374+ assertThrows ( ( ) => formatter . formatToParts ( "0" ) ) ;
375+ assertThrows ( ( ) => formatter . formatToParts ( "0000" ) ) ;
205376 } ) ;
206- await t . step ( "handles a AM" , ( ) => {
377+ await t . step ( "handles a: AM" , ( ) => {
207378 const format = "a" ;
208379 const formatter = new DateTimeFormatter ( format ) ;
209380 assertEquals ( formatter . formatToParts ( "AM" ) , [
210381 { type : "dayPeriod" , value : "AM" } ,
211382 ] ) ;
212383 } ) ;
213- await t . step ( "handles a AM." , ( ) => {
384+ await t . step ( "handles a: AM." , ( ) => {
214385 const format = "a" ;
215386 const formatter = new DateTimeFormatter ( format ) ;
216387 assertEquals ( formatter . formatToParts ( "AM." ) , [
217388 { type : "dayPeriod" , value : "AM" } ,
218389 ] ) ;
219390 } ) ;
220- await t . step ( "handles a A.M." , ( ) => {
391+ await t . step ( "handles a: A.M." , ( ) => {
221392 const format = "a" ;
222393 const formatter = new DateTimeFormatter ( format ) ;
223394 assertEquals ( formatter . formatToParts ( "A.M." ) , [
224395 { type : "dayPeriod" , value : "AM" } ,
225396 ] ) ;
226397 } ) ;
227- await t . step ( "handles a PM" , ( ) => {
398+ await t . step ( "handles a: PM" , ( ) => {
228399 const format = "a" ;
229400 const formatter = new DateTimeFormatter ( format ) ;
230401 assertEquals ( formatter . formatToParts ( "PM" ) , [
231402 { type : "dayPeriod" , value : "PM" } ,
232403 ] ) ;
233404 } ) ;
234- await t . step ( "handles a PM." , ( ) => {
405+ await t . step ( "handles a: PM." , ( ) => {
235406 const format = "a" ;
236407 const formatter = new DateTimeFormatter ( format ) ;
237408 assertEquals ( formatter . formatToParts ( "PM." ) , [
238409 { type : "dayPeriod" , value : "PM" } ,
239410 ] ) ;
240411 } ) ;
241- await t . step ( "handles a P.M." , ( ) => {
412+ await t . step ( "handles a: P.M." , ( ) => {
242413 const format = "a" ;
243414 const formatter = new DateTimeFormatter ( format ) ;
244415 assertEquals ( formatter . formatToParts ( "P.M." ) , [
@@ -247,26 +418,6 @@ Deno.test("dateTimeFormatter.formatToParts()", async (t) => {
247418 } ) ;
248419} ) ;
249420
250- Deno . test ( "dateTimeFormatter.formatToParts() throws on an empty string" , ( ) => {
251- const format = "yyyy-MM-dd" ;
252- const formatter = new DateTimeFormatter ( format ) ;
253- assertThrows (
254- ( ) => formatter . formatToParts ( "" ) ,
255- Error ,
256- "Cannot format value: The value is not valid for part { year undefined } " ,
257- ) ;
258- } ) ;
259-
260- Deno . test ( "dateTimeFormatter.formatToParts() throws on a string which exceeds the format" , ( ) => {
261- const format = "yyyy-MM-dd" ;
262- const formatter = new DateTimeFormatter ( format ) ;
263- assertThrows (
264- ( ) => formatter . formatToParts ( "2020-01-01T00:00:00.000Z" ) ,
265- Error ,
266- "datetime string was not fully parsed!" ,
267- ) ;
268- } ) ;
269-
270421Deno . test ( "dateTimeFormatter.partsToDate()" , ( ) => {
271422 const date = new Date ( "2020-01-01T00:00:00.000Z" ) ;
272423 using _time = new FakeTime ( date ) ;
@@ -286,6 +437,26 @@ Deno.test("dateTimeFormatter.partsToDate()", () => {
286437 ] ) ,
287438 date ,
288439 ) ;
440+ assertEquals (
441+ formatter . partsToDate ( [
442+ { type : "year" , value : "20" } ,
443+ { type : "month" , value : "1" } ,
444+ { type : "day" , value : "1" } ,
445+ { type : "hour" , value : "0" } ,
446+ { type : "minute" , value : "0" } ,
447+ { type : "second" , value : "0" } ,
448+ { type : "fractionalSecond" , value : "0" } ,
449+ { type : "dayPeriod" , value : "AM" } ,
450+ { type : "timeZoneName" , value : "UTC" } ,
451+ ] ) ,
452+ date ,
453+ ) ;
454+ assertEquals (
455+ formatter . partsToDate ( [
456+ { type : "timeZoneName" , value : "UTC" } ,
457+ ] ) ,
458+ date ,
459+ ) ;
289460} ) ;
290461Deno . test ( "dateTimeFormatter.partsToDate() works with am dayPeriod" , ( ) => {
291462 const date = new Date ( "2020-01-01T00:00:00.000Z" ) ;
0 commit comments