wangzhibo
2026-05-09 53418655c061ac26f66058253f39200aced1ab1d
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
/**
 * @copyright (c) 2016, Philipp Thürwächter & Pattrick Hüper
 * @copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos
 * @license BSD-3-Clause (see LICENSE in the root directory of this source tree)
 */
 
import { assert } from '../assert';
import { DateTimeException, IllegalArgumentException } from '../errors';
import { MathUtil } from '../MathUtil';
 
/**
 * The range of valid values for a date-time field.
 *
 * All TemporalField instances have a valid range of values.
 * For example, the ISO day-of-month runs from 1 to somewhere between 28 and 31.
 * This class captures that valid range.
 *
 * It is important to be aware of the limitations of this class.
 * Only the minimum and maximum values are provided.
 * It is possible for there to be invalid values within the outer range.
 * For example, a weird field may have valid values of 1, 2, 4, 6, 7, thus
 * have a range of '1 - 7', despite that fact that values 3 and 5 are invalid.
 *
 * Instances of this class are not tied to a specific field.
 */
export class ValueRange {
 
    /**
     *
     * @param {!number} minSmallest
     * @param {!number} minLargest
     * @param {!number} maxSmallest
     * @param {!number} maxLargest
     * @private
     */
    constructor(minSmallest, minLargest, maxSmallest, maxLargest) {
        assert(!(minSmallest > minLargest), `Smallest minimum value '${minSmallest 
        }' must be less than largest minimum value '${minLargest}'`, IllegalArgumentException);
        assert(!(maxSmallest > maxLargest), `Smallest maximum value '${maxSmallest 
        }' must be less than largest maximum value '${maxLargest}'`, IllegalArgumentException);
        assert(!(minLargest > maxLargest), `Minimum value '${minLargest 
        }' must be less than maximum value '${maxLargest}'`, IllegalArgumentException);
 
        this._minSmallest = minSmallest;
        this._minLargest = minLargest;
        this._maxLargest = maxLargest;
        this._maxSmallest = maxSmallest;
    }
 
    /**
     * Is the value range fixed and fully known.
     *
     * For example, the ISO day-of-month runs from 1 to between 28 and 31.
     * Since there is uncertainty about the maximum value, the range is not fixed.
     * However, for the month of January, the range is always 1 to 31, thus it is fixed.
     *
     * @return {boolean} true if the set of values is fixed
     */
    isFixed() {
        return this._minSmallest === this._minLargest && this._maxSmallest === this._maxLargest;
    }
 
    /**
     *
     * @returns {number}
     */
    minimum(){
        return this._minSmallest;
    }
 
    /**
     *
     * @returns {number}
     */
    largestMinimum(){
        return this._minLargest;
    }
 
    /**
     *
     * @returns {number}
     */
    maximum(){
        return this._maxLargest;
    }
 
    /**
     *
     * @returns {number}
     */
    smallestMaximum(){
        return this._maxSmallest;
    }
 
    /**
     *
     * @returns {boolean}
     */
    isValidValue(value) {
        return (this.minimum() <= value && value <= this.maximum());
    }
 
    /**
     *
     * @param {number} value
     * @param {TemporalField} field
     */
    checkValidValue(value, field) {
        let msg;
        if (!this.isValidValue(value)) {
            if (field != null) {
                msg = `Invalid value for ${field} (valid values ${this.toString()}): ${value}`;
            } else {
                msg = `Invalid value (valid values ${this.toString()}): ${value}`;
            }
            return assert(false, msg, DateTimeException);
        }
        return value;
    }
 
    /**
     * Checks that the specified value is valid and fits in an `int`.
     *
     * This validates that the value is within the valid range of values and that
     * all valid values are within the bounds of an `int`.
     * The field is only used to improve the error message.
     *
     * @param {number} value - the value to check
     * @param {TemporalField} field - the field being checked, may be null
     * @return {number} the value that was passed in
     * @see #isValidIntValue(long)
     */
    checkValidIntValue(value, field) {
        if (this.isValidIntValue(value) === false) {
            throw new DateTimeException(`Invalid int value for ${field}: ${value}`);
        }
        return value;
    }
 
    /**
     * Checks if the value is within the valid range and that all values
     * in the range fit in an `int`.
     *
     * This method combines {@link isIntValue} and {@link isValidValue}.
     *
     * @param {number} value - the value to check
     * @return true if the value is valid and fits in an `int`
     */
    isValidIntValue(value) {
        return this.isIntValue() && this.isValidValue(value);
    }
 
    /**
     * Checks if all values in the range fit in an `int`.
     *
     * This checks that all valid values are within the bounds of an `int`.
     *
     * For example, the ISO month-of-year has values from 1 to 12, which fits in an `int`.
     * By comparison, ISO nano-of-day runs from 1 to 86,400,000,000,000 which does not fit in an `int`.
     *
     * This implementation uses {@link getMinimum} and {@link getMaximum}.
     *
     * @return boolean if a valid value always fits in an `int`
     */
    isIntValue() { // should be isSafeIntegerValue
        return this.minimum() >= MathUtil.MIN_SAFE_INTEGER && this.maximum() <= MathUtil.MAX_SAFE_INTEGER;
    }
 
    /**
     * Checks if this range is equal to another range.
     *
     * The comparison is based on the four values, minimum, largest minimum,
     * smallest maximum and maximum.
     * Only objects of type {@link ValueRange} are compared, other types return false.
     *
     * @param {*} other - the object to check, null returns false
     * @return {boolean} true if this is equal to the other range
     */
    equals(other) {
        if (other === this) {
            return true;
        }
        if (other instanceof ValueRange) {
            return this._minSmallest === other._minSmallest && this._minLargest === other._minLargest &&
                this._maxSmallest === other._maxSmallest && this._maxLargest === other._maxLargest;
        }
        return false;
    }
 
    /**
     * A hash code for this range.
     *
     * @return {number} a suitable hash code
     */
    hashCode() {
        return MathUtil.hashCode(this._minSmallest, this._minLargest, this._maxSmallest, this._maxLargest);
    }
 
    /*
     * Outputs this range as a String.
     *
     * The format will be '{min}/{largestMin} - {smallestMax}/{max}',
     * where the largestMin or smallestMax sections may be omitted, together
     * with associated slash, if they are the same as the min or max.
     *
     * @return {string} a string representation of this range, not null
     */
    toString() {
        let str = this.minimum() + (this.minimum() !== this.largestMinimum() ? `/${this.largestMinimum()}` : '');
        str += ' - ';
        str += this.smallestMaximum() + (this.smallestMaximum() !== this.maximum() ? `/${this.maximum()}` : '');
        return str;
    }
 
    /*
     * called with 2 params: Obtains a fixed value range.
     *
     * This factory obtains a range where the minimum and maximum values are fixed.
     * For example, the ISO month-of-year always runs from 1 to 12.
     *
     * @param min  the minimum value
     * @param max  the maximum value
     * @return the ValueRange for min, max, not null
 
     * called with 3 params: Obtains a variable value range.
     *
     * This factory obtains a range where the minimum value is fixed and the maximum value may vary.
     * For example, the ISO day-of-month always starts at 1, but ends between 28 and 31.
     *
     * @param min  the minimum value
     * @param maxSmallest  the smallest maximum value
     * @param maxLargest  the largest maximum value
     * @return the ValueRange for min, smallest max, largest max, not null
 
     * called with 4 params: Obtains a fully variable value range.
     *
     * This factory obtains a range where both the minimum and maximum value may vary.
     *
     * @param minSmallest  the smallest minimum value
     * @param minLargest  the largest minimum value
     * @param maxSmallest  the smallest maximum value
     * @param maxLargest  the largest maximum value
     *
     * @return {ValueRange} the ValueRange for smallest min, largest min, smallest max, largest max, not null
     */
    static of() {
        if (arguments.length === 2) {
            return new ValueRange(arguments[0], arguments[0], arguments[1], arguments[1]);
        } else if (arguments.length === 3) {
            return new ValueRange(arguments[0], arguments[0], arguments[1], arguments[2]);
        } else if (arguments.length === 4) {
            return new ValueRange(arguments[0], arguments[1], arguments[2], arguments[3]);
        } else {
            return assert(false, `Invalid number of arguments ${arguments.length}`, IllegalArgumentException);
        }
    }
}