summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/Date.js
blob: 6d5d8b7a176355cc5e9688d3fe6328948a1f037f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#if JS_HAS_INTL_API
// This cache, once primed, has these properties:
//
//   runtimeDefaultLocale:
//     Locale information provided by the embedding, guiding SpiderMonkey's
//     selection of a default locale.  See intl_RuntimeDefaultLocale(), whose
//     value controls the value returned by DefaultLocale() that's what's
//     *actually* used.
//   icuDefaultTimeZone:
//     Time zone information provided by ICU. See intl_defaultTimeZone(),
//     whose value controls the value returned by DefaultTimeZone() that's
//     what's *actually* used.
//   formatters:
//     A Record storing formatters consistent with the above
//     runtimeDefaultLocale/localTZA values, for use with the appropriate
//     ES6 toLocale*String Date method when called with its first two
//     arguments having the value |undefined|.
//
// The "formatters" Record has (some subset of) these properties, as determined
// by all values of the first argument passed to |GetCachedFormat|:
//
//   dateTimeFormat: for Date's toLocaleString operation
//   dateFormat: for Date's toLocaleDateString operation
//   timeFormat: for Date's toLocaleTimeString operation
//
// Using this cache, then, requires
// 1) verifying the current runtimeDefaultLocale/icuDefaultTimeZone are
//    consistent with cached values, then
// 2) seeing if the desired formatter is cached and returning it if so, or else
// 3) create the desired formatter and store and return it.
var dateTimeFormatCache = new_Record();

/**
 * Get a cached DateTimeFormat formatter object, created like so:
 *
 *   var opts = ToDateTimeOptions(undefined, required, defaults);
 *   return new Intl.DateTimeFormat(undefined, opts);
 *
 * |format| must be a key from the "formatters" Record described above.
 */
function GetCachedFormat(format, required, defaults) {
  assert(
    format === "dateTimeFormat" ||
      format === "dateFormat" ||
      format === "timeFormat",
    "unexpected format key: please update the comment by dateTimeFormatCache"
  );

  var formatters;
  if (
    !intl_IsRuntimeDefaultLocale(dateTimeFormatCache.runtimeDefaultLocale) ||
    !intl_isDefaultTimeZone(dateTimeFormatCache.icuDefaultTimeZone)
  ) {
    formatters = dateTimeFormatCache.formatters = new_Record();
    dateTimeFormatCache.runtimeDefaultLocale = intl_RuntimeDefaultLocale();
    dateTimeFormatCache.icuDefaultTimeZone = intl_defaultTimeZone();
  } else {
    formatters = dateTimeFormatCache.formatters;
  }

  var fmt = formatters[format];
  if (fmt === undefined) {
    var options = ToDateTimeOptions(undefined, required, defaults);
    fmt = formatters[format] = intl_DateTimeFormat(undefined, options);
  }

  return fmt;
}

/**
 * Format this Date object into a date and time string, using the locale and
 * formatting options provided.
 *
 * Spec: ECMAScript Language Specification, 5.1 edition, 15.9.5.5.
 * Spec: ECMAScript Internationalization API Specification, 13.3.1.
 */
function Date_toLocaleString() {
  // Steps 1-2.
  var x = callFunction(ThisTimeValue, this, DATE_METHOD_LOCALE_STRING);
  if (Number_isNaN(x)) {
    return "Invalid Date";
  }

  // Steps 3-4.
  var locales = ArgumentsLength() ? GetArgument(0) : undefined;
  var options = ArgumentsLength() > 1 ? GetArgument(1) : undefined;

  // Step 5-6.
  var dateTimeFormat;
  if (locales === undefined && options === undefined) {
    // This cache only optimizes for the old ES5 toLocaleString without
    // locales and options.
    dateTimeFormat = GetCachedFormat("dateTimeFormat", "any", "all");
  } else {
    options = ToDateTimeOptions(options, "any", "all");
    dateTimeFormat = intl_DateTimeFormat(locales, options);
  }

  // Step 7.
  return intl_FormatDateTime(dateTimeFormat, x, /* formatToParts = */ false);
}

/**
 * Format this Date object into a date string, using the locale and formatting
 * options provided.
 *
 * Spec: ECMAScript Language Specification, 5.1 edition, 15.9.5.6.
 * Spec: ECMAScript Internationalization API Specification, 13.3.2.
 */
function Date_toLocaleDateString() {
  // Steps 1-2.
  var x = callFunction(ThisTimeValue, this, DATE_METHOD_LOCALE_DATE_STRING);
  if (Number_isNaN(x)) {
    return "Invalid Date";
  }

  // Steps 3-4.
  var locales = ArgumentsLength() ? GetArgument(0) : undefined;
  var options = ArgumentsLength() > 1 ? GetArgument(1) : undefined;

  // Step 5-6.
  var dateTimeFormat;
  if (locales === undefined && options === undefined) {
    // This cache only optimizes for the old ES5 toLocaleDateString without
    // locales and options.
    dateTimeFormat = GetCachedFormat("dateFormat", "date", "date");
  } else {
    options = ToDateTimeOptions(options, "date", "date");
    dateTimeFormat = intl_DateTimeFormat(locales, options);
  }

  // Step 7.
  return intl_FormatDateTime(dateTimeFormat, x, /* formatToParts = */ false);
}

/**
 * Format this Date object into a time string, using the locale and formatting
 * options provided.
 *
 * Spec: ECMAScript Language Specification, 5.1 edition, 15.9.5.7.
 * Spec: ECMAScript Internationalization API Specification, 13.3.3.
 */
function Date_toLocaleTimeString() {
  // Steps 1-2.
  var x = callFunction(ThisTimeValue, this, DATE_METHOD_LOCALE_TIME_STRING);
  if (Number_isNaN(x)) {
    return "Invalid Date";
  }

  // Steps 3-4.
  var locales = ArgumentsLength() ? GetArgument(0) : undefined;
  var options = ArgumentsLength() > 1 ? GetArgument(1) : undefined;

  // Step 5-6.
  var dateTimeFormat;
  if (locales === undefined && options === undefined) {
    // This cache only optimizes for the old ES5 toLocaleTimeString without
    // locales and options.
    dateTimeFormat = GetCachedFormat("timeFormat", "time", "time");
  } else {
    options = ToDateTimeOptions(options, "time", "time");
    dateTimeFormat = intl_DateTimeFormat(locales, options);
  }

  // Step 7.
  return intl_FormatDateTime(dateTimeFormat, x, /* formatToParts = */ false);
}
#endif  // JS_HAS_INTL_API