/work/obj-fuzz/dist/include/js/Date.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | |
6 | | /* JavaScript date/time computation and creation functions. */ |
7 | | |
8 | | #ifndef js_Date_h |
9 | | #define js_Date_h |
10 | | |
11 | | /* |
12 | | * Dates in JavaScript are defined by IEEE-754 double precision numbers from |
13 | | * the set: |
14 | | * |
15 | | * { t ∈ ℕ : -8.64e15 ≤ t ≤ +8.64e15 } ∪ { NaN } |
16 | | * |
17 | | * The single NaN value represents any invalid-date value. All other values |
18 | | * represent idealized durations in milliseconds since the UTC epoch. (Leap |
19 | | * seconds are ignored; leap days are not.) +0 is the only zero in this set. |
20 | | * The limit represented by 8.64e15 milliseconds is 100 million days either |
21 | | * side of 00:00 January 1, 1970 UTC. |
22 | | * |
23 | | * Dates in the above set are represented by the |ClippedTime| class. The |
24 | | * double type is a superset of the above set, so it *may* (but need not) |
25 | | * represent a date. Use ECMAScript's |TimeClip| method to produce a date from |
26 | | * a double. |
27 | | * |
28 | | * Date *objects* are simply wrappers around |TimeClip|'d numbers, with a bunch |
29 | | * of accessor methods to the various aspects of the represented date. |
30 | | */ |
31 | | |
32 | | #include "mozilla/FloatingPoint.h" |
33 | | #include "mozilla/MathAlgorithms.h" |
34 | | |
35 | | #include "js/Conversions.h" |
36 | | #include "js/Value.h" |
37 | | |
38 | | namespace JS { |
39 | | |
40 | | /** |
41 | | * Re-query the system to determine the current time zone adjustment from UTC, |
42 | | * including any component due to DST. If the time zone has changed, this will |
43 | | * cause all Date object non-UTC methods and formatting functions to produce |
44 | | * appropriately adjusted results. |
45 | | * |
46 | | * Left to its own devices, SpiderMonkey itself may occasionally try to detect |
47 | | * system time changes. However, no particular frequency of checking is |
48 | | * guaranteed. Embedders unable to accept occasional inaccuracies should call |
49 | | * this method in response to system time changes, or immediately before |
50 | | * operations requiring instantaneous correctness, to guarantee correct |
51 | | * behavior. |
52 | | */ |
53 | | extern JS_PUBLIC_API(void) |
54 | | ResetTimeZone(); |
55 | | |
56 | | class ClippedTime; |
57 | | inline ClippedTime TimeClip(double time); |
58 | | |
59 | | /* |
60 | | * |ClippedTime| represents the limited subset of dates/times described above. |
61 | | * |
62 | | * An invalid date/time may be created through the |ClippedTime::invalid| |
63 | | * method. Otherwise, a |ClippedTime| may be created using the |TimeClip| |
64 | | * method. |
65 | | * |
66 | | * In typical use, the user might wish to manipulate a timestamp. The user |
67 | | * performs a series of operations on it, but the final value might not be a |
68 | | * date as defined above -- it could have overflowed, acquired a fractional |
69 | | * component, &c. So as a *final* step, the user passes that value through |
70 | | * |TimeClip| to produce a number restricted to JavaScript's date range. |
71 | | * |
72 | | * APIs that accept a JavaScript date value thus accept a |ClippedTime|, not a |
73 | | * double. This ensures that date/time APIs will only ever receive acceptable |
74 | | * JavaScript dates. This also forces users to perform any desired clipping, |
75 | | * as only the user knows what behavior is desired when clipping occurs. |
76 | | */ |
77 | | class ClippedTime |
78 | | { |
79 | | double t; |
80 | | |
81 | 0 | explicit ClippedTime(double time) : t(time) {} |
82 | | friend ClippedTime TimeClip(double time); |
83 | | |
84 | | public: |
85 | | // Create an invalid date. |
86 | 0 | ClippedTime() : t(mozilla::UnspecifiedNaN<double>()) {} |
87 | | |
88 | | // Create an invalid date/time, more explicitly; prefer this to the default |
89 | | // constructor. |
90 | 0 | static ClippedTime invalid() { return ClippedTime(); } |
91 | | |
92 | 0 | double toDouble() const { return t; } |
93 | | |
94 | 0 | bool isValid() const { return !mozilla::IsNaN(t); } |
95 | | }; |
96 | | |
97 | | // ES6 20.3.1.15. |
98 | | // |
99 | | // Clip a double to JavaScript's date range (or to an invalid date) using the |
100 | | // ECMAScript TimeClip algorithm. |
101 | | inline ClippedTime |
102 | | TimeClip(double time) |
103 | 0 | { |
104 | 0 | // Steps 1-2. |
105 | 0 | const double MaxTimeMagnitude = 8.64e15; |
106 | 0 | if (!mozilla::IsFinite(time) || mozilla::Abs(time) > MaxTimeMagnitude) { |
107 | 0 | return ClippedTime(mozilla::UnspecifiedNaN<double>()); |
108 | 0 | } |
109 | 0 | |
110 | 0 | // Step 3. |
111 | 0 | return ClippedTime(ToInteger(time) + (+0.0)); |
112 | 0 | } |
113 | | |
114 | | // Produce a double Value from the given time. Because times may be NaN, |
115 | | // prefer using this to manual canonicalization. |
116 | | inline Value |
117 | | TimeValue(ClippedTime time) |
118 | 0 | { |
119 | 0 | return DoubleValue(JS::CanonicalizeNaN(time.toDouble())); |
120 | 0 | } |
121 | | |
122 | | // Create a new Date object whose [[DateValue]] internal slot contains the |
123 | | // clipped |time|. (Users who must represent times outside that range must use |
124 | | // another representation.) |
125 | | extern JS_PUBLIC_API(JSObject*) |
126 | | NewDateObject(JSContext* cx, ClippedTime time); |
127 | | |
128 | | // Year is a year, month is 0-11, day is 1-based. The return value is a number |
129 | | // of milliseconds since the epoch. |
130 | | // |
131 | | // Consistent with the MakeDate algorithm defined in ECMAScript, this value is |
132 | | // *not* clipped! Use JS::TimeClip if you need a clipped date. |
133 | | JS_PUBLIC_API(double) |
134 | | MakeDate(double year, unsigned month, unsigned day); |
135 | | |
136 | | // Year is a year, month is 0-11, day is 1-based, and time is in milliseconds. |
137 | | // The return value is a number of milliseconds since the epoch. |
138 | | // |
139 | | // Consistent with the MakeDate algorithm defined in ECMAScript, this value is |
140 | | // *not* clipped! Use JS::TimeClip if you need a clipped date. |
141 | | JS_PUBLIC_API(double) |
142 | | MakeDate(double year, unsigned month, unsigned day, double time); |
143 | | |
144 | | // Takes an integer number of milliseconds since the epoch and returns the |
145 | | // year. Can return NaN, and will do so if NaN is passed in. |
146 | | JS_PUBLIC_API(double) |
147 | | YearFromTime(double time); |
148 | | |
149 | | // Takes an integer number of milliseconds since the epoch and returns the |
150 | | // month (0-11). Can return NaN, and will do so if NaN is passed in. |
151 | | JS_PUBLIC_API(double) |
152 | | MonthFromTime(double time); |
153 | | |
154 | | // Takes an integer number of milliseconds since the epoch and returns the |
155 | | // day (1-based). Can return NaN, and will do so if NaN is passed in. |
156 | | JS_PUBLIC_API(double) |
157 | | DayFromTime(double time); |
158 | | |
159 | | // Takes an integer year and returns the number of days from epoch to the given |
160 | | // year. |
161 | | // NOTE: The calculation performed by this function is literally that given in |
162 | | // the ECMAScript specification. Nonfinite years, years containing fractional |
163 | | // components, and years outside ECMAScript's date range are not handled with |
164 | | // any particular intelligence. Garbage in, garbage out. |
165 | | JS_PUBLIC_API(double) |
166 | | DayFromYear(double year); |
167 | | |
168 | | // Takes an integer number of milliseconds since the epoch and an integer year, |
169 | | // returns the number of days in that year. If |time| is nonfinite, returns NaN. |
170 | | // Otherwise |time| *must* correspond to a time within the valid year |year|. |
171 | | // This should usually be ensured by computing |year| as |JS::DayFromYear(time)|. |
172 | | JS_PUBLIC_API(double) |
173 | | DayWithinYear(double time, double year); |
174 | | |
175 | | // The callback will be a wrapper function that accepts a single double (the time |
176 | | // to clamp and jitter.) Inside the JS Engine, other parameters that may be needed |
177 | | // are all constant, so they are handled inside the wrapper function |
178 | | using ReduceMicrosecondTimePrecisionCallback = double(*)(double); |
179 | | |
180 | | // Set a callback into the toolkit/components/resistfingerprinting function that |
181 | | // will centralize time resolution and jitter into one place. |
182 | | JS_PUBLIC_API(void) |
183 | | SetReduceMicrosecondTimePrecisionCallback(ReduceMicrosecondTimePrecisionCallback callback); |
184 | | |
185 | | // Sets the time resolution for fingerprinting protection, and whether jitter |
186 | | // should occur. If resolution is set to zero, then no rounding or jitter will |
187 | | // occur. This is used if the callback above is not specified. |
188 | | JS_PUBLIC_API(void) |
189 | | SetTimeResolutionUsec(uint32_t resolution, bool jitter); |
190 | | |
191 | | } // namespace JS |
192 | | |
193 | | #endif /* js_Date_h */ |