Coverage Report

Created: 2018-09-25 14:53

/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 */