Delete WebMetal implementation in favor of WebGPU
[WebKit-https.git] / Source / WebCore / platform / DateComponents.cpp
1 /*
2  * Copyright (C) 2009 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "DateComponents.h"
33
34 #include <limits.h>
35 #include <wtf/ASCIICType.h>
36 #include <wtf/DateMath.h>
37 #include <wtf/MathExtras.h>
38 #include <wtf/text/StringConcatenateNumbers.h>
39
40 namespace WebCore {
41
42 // HTML5 specification defines minimum week of year is one.
43 const int DateComponents::minimumWeekNumber = 1;
44
45 // HTML5 specification defines maximum week of year is 53.
46 const int DateComponents::maximumWeekNumber = 53;
47
48 static const int maximumMonthInMaximumYear = 8; // This is September, since months are 0 based.
49 static const int maximumDayInMaximumMonth = 13;
50 static const int maximumWeekInMaximumYear = 37; // The week of 275760-09-13
51
52 static const int daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
53
54 static bool isLeapYear(int year)
55 {
56     if (year % 4)
57         return false;
58     if (!(year % 400))
59         return true;
60     if (!(year % 100))
61         return false;
62     return true;
63 }
64
65 // 'month' is 0-based.
66 static int maxDayOfMonth(int year, int month)
67 {
68     if (month != 1) // February?
69         return daysInMonth[month];
70     return isLeapYear(year) ? 29 : 28;
71 }
72
73 // 'month' is 0-based.
74 static int dayOfWeek(int year, int month, int day)
75 {
76     int shiftedMonth = month + 2;
77     // 2:January, 3:Feburuary, 4:March, ...
78
79     // Zeller's congruence
80     if (shiftedMonth <= 3) {
81         shiftedMonth += 12;
82         year--;
83     }
84     // 4:March, ..., 14:January, 15:February
85
86     int highYear = year / 100;
87     int lowYear = year % 100;
88     // We add 6 to make the result Sunday-origin.
89     int result = (day + 13 * shiftedMonth / 5 + lowYear + lowYear / 4 + highYear / 4 + 5 * highYear + 6) % 7;
90     return result;
91 }
92
93 int DateComponents::maxWeekNumberInYear() const
94 {
95     int day = dayOfWeek(m_year, 0, 1); // January 1.
96     return day == Thursday || (day == Wednesday && isLeapYear(m_year)) ? maximumWeekNumber : maximumWeekNumber - 1;
97 }
98
99 static unsigned countDigits(const UChar* src, unsigned length, unsigned start)
100 {
101     unsigned index = start;
102     for (; index < length; ++index) {
103         if (!isASCIIDigit(src[index]))
104             break;
105     }
106     return index - start;
107 }
108
109 // Very strict integer parser. Do not allow leading or trailing whitespace unlike charactersToIntStrict().
110 static bool toInt(const UChar* src, unsigned length, unsigned parseStart, unsigned parseLength, int& out)
111 {
112     if (parseStart + parseLength > length || parseLength <= 0)
113         return false;
114     int value = 0;
115     const UChar* current = src + parseStart;
116     const UChar* end = current + parseLength;
117
118     // We don't need to handle negative numbers for ISO 8601.
119     for (; current < end; ++current) {
120         if (!isASCIIDigit(*current))
121             return false;
122         int digit = *current - '0';
123         if (value > (INT_MAX - digit) / 10) // Check for overflow.
124             return false;
125         value = value * 10 + digit;
126     }
127     out = value;
128     return true;
129 }
130
131 bool DateComponents::parseYear(const UChar* src, unsigned length, unsigned start, unsigned& end)
132 {
133     unsigned digitsLength = countDigits(src, length, start);
134     // Needs at least 4 digits according to the standard.
135     if (digitsLength < 4)
136         return false;
137     int year;
138     if (!toInt(src, length, start, digitsLength, year))
139         return false;
140     if (year < minimumYear() || year > maximumYear())
141         return false;
142     m_year = year;
143     end = start + digitsLength;
144     return true;
145 }
146
147 static bool withinHTMLDateLimits(int year, int month)
148 {
149     if (year < DateComponents::minimumYear())
150         return false;
151     if (year < DateComponents::maximumYear())
152         return true;
153     return month <= maximumMonthInMaximumYear;
154 }
155
156 static bool withinHTMLDateLimits(int year, int month, int monthDay)
157 {
158     if (year < DateComponents::minimumYear())
159         return false;
160     if (year < DateComponents::maximumYear())
161         return true;
162     if (month < maximumMonthInMaximumYear)
163         return true;
164     return monthDay <= maximumDayInMaximumMonth;
165 }
166
167 static bool withinHTMLDateLimits(int year, int month, int monthDay, int hour, int minute, int second, int millisecond)
168 {
169     if (year < DateComponents::minimumYear())
170         return false;
171     if (year < DateComponents::maximumYear())
172         return true;
173     if (month < maximumMonthInMaximumYear)
174         return true;
175     if (monthDay < maximumDayInMaximumMonth)
176         return true;
177     if (monthDay > maximumDayInMaximumMonth)
178         return false;
179     // (year, month, monthDay) = (maximumYear, maximumMonthInMaximumYear, maximumDayInMaximumMonth)
180     return !hour && !minute && !second && !millisecond;
181 }
182
183 bool DateComponents::addDay(int dayDiff)
184 {
185     ASSERT(m_monthDay);
186
187     int day = m_monthDay + dayDiff;
188     if (day > maxDayOfMonth(m_year, m_month)) {
189         day = m_monthDay;
190         int year = m_year;
191         int month = m_month;
192         int maxDay = maxDayOfMonth(year, month);
193         for (; dayDiff > 0; --dayDiff) {
194             ++day;
195             if (day > maxDay) {
196                 day = 1;
197                 ++month;
198                 if (month >= 12) { // month is 0-origin.
199                     month = 0;
200                     ++year;
201                 }
202                 maxDay = maxDayOfMonth(year, month);
203             }
204         }
205         if (!withinHTMLDateLimits(year, month, day))
206             return false;
207         m_year = year;
208         m_month = month;
209     } else if (day < 1) {
210         int month = m_month;
211         int year = m_year;
212         day = m_monthDay;
213         for (; dayDiff < 0; ++dayDiff) {
214             --day;
215             if (day < 1) {
216                 --month;
217                 if (month < 0) {
218                     month = 11;
219                     --year;
220                 }
221                 day = maxDayOfMonth(year, month);
222             }
223         }
224         if (!withinHTMLDateLimits(year, month, day))
225             return false;
226         m_year = year;
227         m_month = month;
228     } else {
229         if (!withinHTMLDateLimits(m_year, m_month, day))
230             return false;
231     }
232     m_monthDay = day;
233     return true;
234 }
235
236 bool DateComponents::addMinute(int minute)
237 {
238     // This function is used to adjust timezone offset. So m_year, m_month,
239     // m_monthDay have values between the lower and higher limits.
240     ASSERT(withinHTMLDateLimits(m_year, m_month, m_monthDay));
241
242     int carry;
243     // minute can be negative or greater than 59.
244     minute += m_minute;
245     if (minute > 59) {
246         carry = minute / 60;
247         minute = minute % 60;
248     } else if (minute < 0) {
249         carry = (59 - minute) / 60;
250         minute += carry * 60;
251         carry = -carry;
252         ASSERT(minute >= 0 && minute <= 59);
253     } else {
254         if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, minute, m_second, m_millisecond))
255             return false;
256         m_minute = minute;
257         return true;
258     }
259
260     int hour = m_hour + carry;
261     if (hour > 23) {
262         carry = hour / 24;
263         hour = hour % 24;
264     } else if (hour < 0) {
265         carry = (23 - hour) / 24;
266         hour += carry * 24;
267         carry = -carry;
268         ASSERT(hour >= 0 && hour <= 23);
269     } else {
270         if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, hour, minute, m_second, m_millisecond))
271             return false;
272         m_minute = minute;
273         m_hour = hour;
274         return true;
275     }
276     if (!addDay(carry))
277         return false;
278     if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, hour, minute, m_second, m_millisecond))
279         return false;
280     m_minute = minute;
281     m_hour = hour;
282     return true;
283 }
284
285 // Parses a timezone part, and adjust year, month, monthDay, hour, minute, second, millisecond.
286 bool DateComponents::parseTimeZone(const UChar* src, unsigned length, unsigned start, unsigned& end)
287 {
288     if (start >= length)
289         return false;
290     unsigned index = start;
291     if (src[index] == 'Z') {
292         end = index + 1;
293         return true;
294     }
295
296     bool minus;
297     if (src[index] == '+')
298         minus = false;
299     else if (src[index] == '-')
300         minus = true;
301     else
302         return false;
303     ++index;
304
305     int hour;
306     int minute;
307     if (!toInt(src, length, index, 2, hour) || hour < 0 || hour > 23)
308         return false;
309     index += 2;
310
311     if (index >= length || src[index] != ':')
312         return false;
313     ++index;
314
315     if (!toInt(src, length, index, 2, minute) || minute < 0 || minute > 59)
316         return false;
317     index += 2;
318
319     if (minus) {
320         hour = -hour;
321         minute = -minute;
322     }
323
324     // Subtract the timezone offset.
325     if (!addMinute(-(hour * 60 + minute)))
326         return false;
327     end = index;
328     return true;
329 }
330
331 bool DateComponents::parseMonth(const UChar* src, unsigned length, unsigned start, unsigned& end)
332 {
333     ASSERT(src);
334     unsigned index;
335     if (!parseYear(src, length, start, index))
336         return false;
337     if (index >= length || src[index] != '-')
338         return false;
339     ++index;
340
341     int month;
342     if (!toInt(src, length, index, 2, month) || month < 1 || month > 12)
343         return false;
344     --month;
345     if (!withinHTMLDateLimits(m_year, month))
346         return false;
347     m_month = month;
348     end = index + 2;
349     m_type = Month;
350     return true;
351 }
352
353 bool DateComponents::parseDate(const UChar* src, unsigned length, unsigned start, unsigned& end)
354 {
355     ASSERT(src);
356     unsigned index;
357     if (!parseMonth(src, length, start, index))
358         return false;
359     // '-' and 2-digits are needed.
360     if (index + 2 >= length)
361         return false;
362     if (src[index] != '-')
363         return false;
364     ++index;
365
366     int day;
367     if (!toInt(src, length, index, 2, day) || day < 1 || day > maxDayOfMonth(m_year, m_month))
368         return false;
369     if (!withinHTMLDateLimits(m_year, m_month, day))
370         return false;
371     m_monthDay = day;
372     end = index + 2;
373     m_type = Date;
374     return true;
375 }
376
377 bool DateComponents::parseWeek(const UChar* src, unsigned length, unsigned start, unsigned& end)
378 {
379     ASSERT(src);
380     unsigned index;
381     if (!parseYear(src, length, start, index))
382         return false;
383
384     // 4 characters ('-' 'W' digit digit) are needed.
385     if (index + 3 >= length)
386         return false;
387     if (src[index] != '-')
388         return false;
389     ++index;
390     if (src[index] != 'W')
391         return false;
392     ++index;
393
394     int week;
395     if (!toInt(src, length, index, 2, week) || week < minimumWeekNumber || week > maxWeekNumberInYear())
396         return false;
397     if (m_year == maximumYear() && week > maximumWeekInMaximumYear)
398         return false;
399     m_week = week;
400     end = index + 2;
401     m_type = Week;
402     return true;
403 }
404
405 bool DateComponents::parseTime(const UChar* src, unsigned length, unsigned start, unsigned& end)
406 {
407     ASSERT(src);
408     int hour;
409     if (!toInt(src, length, start, 2, hour) || hour < 0 || hour > 23)
410         return false;
411     unsigned index = start + 2;
412     if (index >= length)
413         return false;
414     if (src[index] != ':')
415         return false;
416     ++index;
417
418     int minute;
419     if (!toInt(src, length, index, 2, minute) || minute < 0 || minute > 59)
420         return false;
421     index += 2;
422
423     int second = 0;
424     int millisecond = 0;
425     // Optional second part.
426     // Do not return with false because the part is optional.
427     if (index + 2 < length && src[index] == ':') {
428         if (toInt(src, length, index + 1, 2, second) && second >= 0 && second <= 59) {
429             index += 3;
430
431             // Optional fractional second part.
432             if (index < length && src[index] == '.') {
433                 unsigned digitsLength = countDigits(src, length, index + 1);
434                 if (digitsLength >  0) {
435                     ++index;
436                     bool ok;
437                     if (digitsLength == 1) {
438                         ok = toInt(src, length, index, 1, millisecond);
439                         millisecond *= 100;
440                     } else if (digitsLength == 2) {
441                         ok = toInt(src, length, index, 2, millisecond);
442                         millisecond *= 10;
443                     } else // digitsLength >= 3
444                         ok = toInt(src, length, index, 3, millisecond);
445                     ASSERT_UNUSED(ok, ok);
446                     index += digitsLength;
447                 }
448             }
449         }
450     }
451     m_hour = hour;
452     m_minute = minute;
453     m_second = second;
454     m_millisecond = millisecond;
455     end = index;
456     m_type = Time;
457     return true;
458 }
459
460 bool DateComponents::parseDateTimeLocal(const UChar* src, unsigned length, unsigned start, unsigned& end)
461 {
462     ASSERT(src);
463     unsigned index;
464     if (!parseDate(src, length, start, index))
465         return false;
466     if (index >= length)
467         return false;
468     if (src[index] != 'T')
469         return false;
470     ++index;
471     if (!parseTime(src, length, index, end))
472         return false;
473     if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_second, m_millisecond))
474         return false;
475     m_type = DateTimeLocal;
476     return true;
477 }
478
479 bool DateComponents::parseDateTime(const UChar* src, unsigned length, unsigned start, unsigned& end)
480 {
481     ASSERT(src);
482     unsigned index;
483     if (!parseDate(src, length, start, index))
484         return false;
485     if (index >= length)
486         return false;
487     if (src[index] != 'T')
488         return false;
489     ++index;
490     if (!parseTime(src, length, index, index))
491         return false;
492     if (!parseTimeZone(src, length, index, end))
493         return false;
494     if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_second, m_millisecond))
495         return false;
496     m_type = DateTime;
497     return true;
498 }
499
500 static inline double positiveFmod(double value, double divider)
501 {
502     double remainder = fmod(value, divider);
503     return remainder < 0 ? remainder + divider : remainder;
504 }
505
506 void DateComponents::setMillisecondsSinceMidnightInternal(double msInDay)
507 {
508     ASSERT(msInDay >= 0 && msInDay < msPerDay);
509     m_millisecond = static_cast<int>(fmod(msInDay, msPerSecond));
510     double value = floor(msInDay / msPerSecond);
511     m_second = static_cast<int>(fmod(value, secondsPerMinute));
512     value = floor(value / secondsPerMinute);
513     m_minute = static_cast<int>(fmod(value, minutesPerHour));
514     m_hour = static_cast<int>(value / minutesPerHour);
515 }
516
517 bool DateComponents::setMillisecondsSinceEpochForDateInternal(double ms)
518 {
519     m_year = msToYear(ms);
520     int yearDay = dayInYear(ms, m_year);
521     m_month = monthFromDayInYear(yearDay, isLeapYear(m_year));
522     m_monthDay = dayInMonthFromDayInYear(yearDay, isLeapYear(m_year));
523     return true;
524 }
525
526 bool DateComponents::setMillisecondsSinceEpochForDate(double ms)
527 {
528     m_type = Invalid;
529     if (!std::isfinite(ms))
530         return false;
531     if (!setMillisecondsSinceEpochForDateInternal(round(ms)))
532         return false;
533     if (!withinHTMLDateLimits(m_year, m_month, m_monthDay))
534         return false;
535     m_type = Date;
536     return true;
537 }
538
539 bool DateComponents::setMillisecondsSinceEpochForDateTime(double ms)
540 {
541     m_type = Invalid;
542     if (!std::isfinite(ms))
543         return false;
544     ms = round(ms);
545     setMillisecondsSinceMidnightInternal(positiveFmod(ms, msPerDay));
546     if (!setMillisecondsSinceEpochForDateInternal(ms))
547         return false;
548     if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_second, m_millisecond))
549         return false;
550     m_type = DateTime;
551     return true;
552 }
553
554 bool DateComponents::setMillisecondsSinceEpochForDateTimeLocal(double ms)
555 {
556     // Internal representation of DateTimeLocal is the same as DateTime except m_type.
557     if (!setMillisecondsSinceEpochForDateTime(ms))
558         return false;
559     m_type = DateTimeLocal;
560     return true;
561 }
562
563 bool DateComponents::setMillisecondsSinceEpochForMonth(double ms)
564 {
565     m_type = Invalid;
566     if (!std::isfinite(ms))
567         return false;
568     if (!setMillisecondsSinceEpochForDateInternal(round(ms)))
569         return false;
570     if (!withinHTMLDateLimits(m_year, m_month))
571         return false;
572     m_type = Month;
573     return true;
574 }
575
576 bool DateComponents::setMillisecondsSinceMidnight(double ms)
577 {
578     m_type = Invalid;
579     if (!std::isfinite(ms))
580         return false;
581     setMillisecondsSinceMidnightInternal(positiveFmod(round(ms), msPerDay));
582     m_type = Time;
583     return true;
584 }
585
586 bool DateComponents::setMonthsSinceEpoch(double months)
587 {
588     if (!std::isfinite(months))
589         return false;
590     months = round(months);
591     double doubleMonth = positiveFmod(months, 12);
592     double doubleYear = 1970 + (months - doubleMonth) / 12;
593     if (doubleYear < minimumYear() || maximumYear() < doubleYear)
594         return false;
595     int year = static_cast<int>(doubleYear);
596     int month = static_cast<int>(doubleMonth);
597     if (!withinHTMLDateLimits(year, month))
598         return false;
599     m_year = year;
600     m_month = month;
601     m_type = Month;
602     return true;
603 }
604
605 // Offset from January 1st to Monday of the ISO 8601's first week.
606 //   ex. If January 1st is Friday, such Monday is 3 days later. Returns 3.
607 static int offsetTo1stWeekStart(int year)
608 {
609     int offsetTo1stWeekStart = 1 - dayOfWeek(year, 0, 1);
610     if (offsetTo1stWeekStart <= -4)
611         offsetTo1stWeekStart += 7;
612     return offsetTo1stWeekStart;
613 }
614
615 bool DateComponents::setMillisecondsSinceEpochForWeek(double ms)
616 {
617     m_type = Invalid;
618     if (!std::isfinite(ms))
619         return false;
620     ms = round(ms);
621
622     m_year = msToYear(ms);
623     if (m_year < minimumYear() || m_year > maximumYear())
624         return false;
625
626     int yearDay = dayInYear(ms, m_year);
627     int offset = offsetTo1stWeekStart(m_year);
628     if (yearDay < offset) {
629         // The day belongs to the last week of the previous year.
630         m_year--;
631         if (m_year <= minimumYear())
632             return false;
633         m_week = maxWeekNumberInYear();
634     } else {
635         m_week = ((yearDay - offset) / 7) + 1;
636         if (m_week > maxWeekNumberInYear()) {
637             m_year++;
638             m_week = 1;
639         }
640         if (m_year > maximumYear() || (m_year == maximumYear() && m_week > maximumWeekInMaximumYear))
641             return false;
642     }
643     m_type = Week;
644     return true;
645 }
646
647 double DateComponents::millisecondsSinceEpochForTime() const
648 {
649     ASSERT(m_type == Time || m_type == DateTime || m_type == DateTimeLocal);
650     return ((m_hour * minutesPerHour + m_minute) * secondsPerMinute + m_second) * msPerSecond + m_millisecond;
651 }
652
653 double DateComponents::millisecondsSinceEpoch() const
654 {
655     switch (m_type) {
656     case Date:
657         return dateToDaysFrom1970(m_year, m_month, m_monthDay) * msPerDay;
658     case DateTime:
659     case DateTimeLocal:
660         return dateToDaysFrom1970(m_year, m_month, m_monthDay) * msPerDay + millisecondsSinceEpochForTime();
661     case Month:
662         return dateToDaysFrom1970(m_year, m_month, 1) * msPerDay;
663     case Time:
664         return millisecondsSinceEpochForTime();
665     case Week:
666         return (dateToDaysFrom1970(m_year, 0, 1) + offsetTo1stWeekStart(m_year) + (m_week - 1) * 7) * msPerDay;
667     case Invalid:
668         break;
669     }
670     ASSERT_NOT_REACHED();
671     return invalidMilliseconds();
672 }
673
674 double DateComponents::monthsSinceEpoch() const
675 {
676     ASSERT(m_type == Month);
677     return (m_year - 1970) * 12 + m_month;
678 }
679
680 String DateComponents::toStringForTime(SecondFormat format) const
681 {
682     ASSERT(m_type == DateTime || m_type == DateTimeLocal || m_type == Time);
683     SecondFormat effectiveFormat = format;
684     if (m_millisecond)
685         effectiveFormat = Millisecond;
686     else if (format == None && m_second)
687         effectiveFormat = Second;
688
689     switch (effectiveFormat) {
690     default:
691         ASSERT_NOT_REACHED();
692 #if ASSERT_DISABLED
693         FALLTHROUGH; // To None.
694 #endif
695     case None:
696         return makeString(pad('0', 2, m_hour), ':', pad('0', 2, m_minute));
697     case Second:
698         return makeString(pad('0', 2, m_hour), ':', pad('0', 2, m_minute), ':', pad('0', 2, m_second));
699     case Millisecond:
700         return makeString(pad('0', 2, m_hour), ':', pad('0', 2, m_minute), ':', pad('0', 2, m_second), '.', pad('0', 3, m_millisecond));
701     }
702 }
703
704 String DateComponents::toString(SecondFormat format) const
705 {
706     switch (m_type) {
707     case Date:
708         return makeString(pad('0', 4, m_year), '-', pad('0', 2, m_month + 1), '-', pad('0', 2, m_monthDay));
709     case DateTime:
710         return makeString(pad('0', 4, m_year), '-', pad('0', 2, m_month + 1), '-', pad('0', 2, m_monthDay), 'T', toStringForTime(format), 'Z');
711     case DateTimeLocal:
712         return makeString(pad('0', 4, m_year), '-', pad('0', 2, m_month + 1), '-', pad('0', 2, m_monthDay), 'T', toStringForTime(format));
713     case Month:
714         return makeString(pad('0', 4, m_year), '-', pad('0', 2, m_month + 1));
715     case Time:
716         return toStringForTime(format);
717     case Week:
718         return makeString(pad('0', 4, m_year), "-W", pad('0', 2, m_week));
719     case Invalid:
720         break;
721     }
722     ASSERT_NOT_REACHED();
723     return "(Invalid DateComponents)"_str;
724 }
725
726 } // namespace WebCore