????
Current Path : C:/inetpub/vhost/binhdinhinvest.gdtvietnam.com/api/node_modules/@js-joda/core/src/ |
Current File : C:/inetpub/vhost/binhdinhinvest.gdtvietnam.com/api/node_modules/@js-joda/core/src/ZoneOffset.js |
/** * @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 { requireNonNull } from './assert'; import { DateTimeException } from './errors'; import { MathUtil } from './MathUtil'; import { LocalTime } from './LocalTime'; import { ZoneId } from './ZoneId'; import { ChronoField } from './temporal/ChronoField'; import { TemporalQueries } from './temporal/TemporalQueries'; import { ZoneRules } from './zone/ZoneRules'; const SECONDS_CACHE = {}; const ID_CACHE = {}; /** * * ### Static properties of Class {@link LocalDate} * * ZoneOffset.MAX_SECONDS = 18 * LocalTime.SECONDS_PER_HOUR; * * ZoneOffset.UTC = ZoneOffset.ofTotalSeconds(0); * * ZoneOffset.MIN = ZoneOffset.ofTotalSeconds(-ZoneOffset.MAX_SECONDS); * * ZoneOffset.MAX = ZoneOffset.ofTotalSeconds(ZoneOffset.MAX_SECONDS); * */ export class ZoneOffset extends ZoneId { /** * * @param {number} totalSeconds * @private */ constructor(totalSeconds){ super(); ZoneOffset._validateTotalSeconds(totalSeconds); this._totalSeconds = MathUtil.safeToInt(totalSeconds); this._rules = ZoneRules.of(this); this._id = ZoneOffset._buildId(totalSeconds); } /** * * @returns {number} */ totalSeconds() { return this._totalSeconds; } /** * * @returns {string} */ id() { return this._id; } /** * * @param {number} totalSeconds * @returns {string} */ static _buildId(totalSeconds) { if (totalSeconds === 0) { return 'Z'; } else { const absTotalSeconds = Math.abs(totalSeconds); const absHours = MathUtil.intDiv(absTotalSeconds, LocalTime.SECONDS_PER_HOUR); const absMinutes = MathUtil.intMod(MathUtil.intDiv(absTotalSeconds, LocalTime.SECONDS_PER_MINUTE), LocalTime.MINUTES_PER_HOUR); let buf = `${totalSeconds < 0 ? '-' : '+' }${absHours < 10 ? '0' : ''}${absHours }${absMinutes < 10 ? ':0' : ':'}${absMinutes}`; const absSeconds = MathUtil.intMod(absTotalSeconds, LocalTime.SECONDS_PER_MINUTE); if (absSeconds !== 0) { buf += (absSeconds < 10 ? ':0' : ':') + (absSeconds); } return buf; } } /** * * @param {number} totalSeconds * @private */ static _validateTotalSeconds(totalSeconds){ if (Math.abs(totalSeconds) > ZoneOffset.MAX_SECONDS) { throw new DateTimeException('Zone offset not in valid range: -18:00 to +18:00'); } } /** * * @param {number} hours * @param {number} minutes * @param {number} seconds * @private */ static _validate(hours, minutes, seconds) { if (hours < -18 || hours > 18) { throw new DateTimeException(`Zone offset hours not in valid range: value ${hours } is not in the range -18 to 18`); } if (hours > 0) { if (minutes < 0 || seconds < 0) { throw new DateTimeException('Zone offset minutes and seconds must be positive because hours is positive'); } } else if (hours < 0) { if (minutes > 0 || seconds > 0) { throw new DateTimeException('Zone offset minutes and seconds must be negative because hours is negative'); } } else if ((minutes > 0 && seconds < 0) || (minutes < 0 && seconds > 0)) { throw new DateTimeException('Zone offset minutes and seconds must have the same sign'); } if (Math.abs(minutes) > 59) { throw new DateTimeException(`Zone offset minutes not in valid range: abs(value) ${ Math.abs(minutes)} is not in the range 0 to 59`); } if (Math.abs(seconds) > 59) { throw new DateTimeException(`Zone offset seconds not in valid range: abs(value) ${ Math.abs(seconds)} is not in the range 0 to 59`); } if (Math.abs(hours) === 18 && (Math.abs(minutes) > 0 || Math.abs(seconds) > 0)) { throw new DateTimeException('Zone offset not in valid range: -18:00 to +18:00'); } } //----------------------------------------------------------------------- /** * Obtains an instance of {@link ZoneOffset} using the ID. * * This method parses the string ID of a {@link ZoneOffset} to * return an instance. The parsing accepts all the formats generated by * {@link getId}, plus some additional formats: * * * {@link Z} - for UTC * * `+h` * * `+hh` * * `+hh:mm` * * `-hh:mm` * * `+hhmm` * * `-hhmm` * * `+hh:mm:ss` * * `-hh:mm:ss` * * `+hhmmss` * * `-hhmmss` * * Note that ± means either the plus or minus symbol. * * The ID of the returned offset will be normalized to one of the formats * described by {@link getId}. * * The maximum supported range is from +18:00 to -18:00 inclusive. * * @param {string} offsetId the offset ID, not null * @return {ZoneOffset} the zone-offset, not null * @throws DateTimeException if the offset ID is invalid */ static of(offsetId) { requireNonNull(offsetId, 'offsetId'); // "Z" is always in the cache const offset = ID_CACHE[offsetId]; if (offset != null) { return offset; } // parse - +h, +hh, +hhmm, +hh:mm, +hhmmss, +hh:mm:ss let hours, minutes, seconds; switch (offsetId.length) { case 2: offsetId = `${offsetId[0]}0${offsetId[1]}`; // fallthru // eslint-disable-next-line no-fallthrough case 3: hours = ZoneOffset._parseNumber(offsetId, 1, false); minutes = 0; seconds = 0; break; case 5: hours = ZoneOffset._parseNumber(offsetId, 1, false); minutes = ZoneOffset._parseNumber(offsetId, 3, false); seconds = 0; break; case 6: hours = ZoneOffset._parseNumber(offsetId, 1, false); minutes = ZoneOffset._parseNumber(offsetId, 4, true); seconds = 0; break; case 7: hours = ZoneOffset._parseNumber(offsetId, 1, false); minutes = ZoneOffset._parseNumber(offsetId, 3, false); seconds = ZoneOffset._parseNumber(offsetId, 5, false); break; case 9: hours = ZoneOffset._parseNumber(offsetId, 1, false); minutes = ZoneOffset._parseNumber(offsetId, 4, true); seconds = ZoneOffset._parseNumber(offsetId, 7, true); break; default: throw new DateTimeException(`Invalid ID for ZoneOffset, invalid format: ${offsetId}`); } const first = offsetId[0]; if (first !== '+' && first !== '-') { throw new DateTimeException(`Invalid ID for ZoneOffset, plus/minus not found when expected: ${offsetId}`); } if (first === '-') { return ZoneOffset.ofHoursMinutesSeconds(-hours, -minutes, -seconds); } else { return ZoneOffset.ofHoursMinutesSeconds(hours, minutes, seconds); } } /** * Parse a two digit zero-prefixed number. * * @param {string} offsetId - the offset ID, not null * @param {number} pos - the position to parse, valid * @param {boolean} precededByColon - should this number be prefixed by a precededByColon * @return {number} the parsed number, from 0 to 99 */ static _parseNumber(offsetId, pos, precededByColon) { if (precededByColon && offsetId[pos - 1] !== ':') { throw new DateTimeException(`Invalid ID for ZoneOffset, colon not found when expected: ${offsetId}`); } const ch1 = offsetId[pos]; const ch2 = offsetId[pos + 1]; if (ch1 < '0' || ch1 > '9' || ch2 < '0' || ch2 > '9') { throw new DateTimeException(`Invalid ID for ZoneOffset, non numeric characters found: ${offsetId}`); } return (ch1.charCodeAt(0) - 48) * 10 + (ch2.charCodeAt(0) - 48); } /** * * @param {number} hours * @returns {ZoneOffset} */ static ofHours(hours) { return ZoneOffset.ofHoursMinutesSeconds(hours, 0, 0); } /** * * @param {number} hours * @param {number} minutes * @returns {ZoneOffset} */ static ofHoursMinutes(hours, minutes) { return ZoneOffset.ofHoursMinutesSeconds(hours, minutes, 0); } /** * * @param {number} hours * @param {number} minutes * @param {number} seconds * @returns {ZoneOffset} */ static ofHoursMinutesSeconds(hours, minutes, seconds) { ZoneOffset._validate(hours, minutes, seconds); const totalSeconds = hours * LocalTime.SECONDS_PER_HOUR + minutes * LocalTime.SECONDS_PER_MINUTE + seconds; return ZoneOffset.ofTotalSeconds(totalSeconds); } /** * * @param {number} totalMinutes * @returns {ZoneOffset} */ static ofTotalMinutes(totalMinutes) { const totalSeconds = totalMinutes * LocalTime.SECONDS_PER_MINUTE; return ZoneOffset.ofTotalSeconds(totalSeconds); } /** * * @param {number} totalSeconds * @returns {ZoneOffset} */ static ofTotalSeconds(totalSeconds) { if (totalSeconds % (15 * LocalTime.SECONDS_PER_MINUTE) === 0) { const totalSecs = totalSeconds; let result = SECONDS_CACHE[totalSecs]; if (result == null) { result = new ZoneOffset(totalSeconds); SECONDS_CACHE[totalSecs] = result; ID_CACHE[result.id()] = result; } return result; } else { return new ZoneOffset(totalSeconds); } } /** * Gets the associated time-zone rules. * * The rules will always return this offset when queried. * The implementation class is immutable, thread-safe and serializable. * * @return {ZoneRules} the rules, not null */ rules() { return this._rules; } /** * Gets the value of the specified field from this offset as an `int`. * * This queries this offset for the value for the specified field. * The returned value will always be within the valid range of values for the field. * If it is not possible to return the value, because the field is not supported * or for some other reason, an exception is thrown. * * If the field is a {@link ChronoField} then the query is implemented here. * The {@link OFFSET_SECONDS} field returns the value of the offset. * All other {@link ChronoField} instances will throw a {@link DateTimeException}. * * If the field is not a {@link ChronoField}, then the result of this method * is obtained by invoking {@link TemporalField.getFrom} * passing `this` as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * * @param {TemporalField} field - the field to get, not null * @return {number} the value for the field * @throws DateTimeException if a value for the field cannot be obtained * @throws ArithmeticException if numeric overflow occurs */ get(field) { return this.getLong(field); } /** * Gets the value of the specified field from this offset as a `long`. * * This queries this offset for the value for the specified field. * If it is not possible to return the value, because the field is not supported * or for some other reason, an exception is thrown. * * If the field is a {@link ChronoField} then the query is implemented here. * The {@link OFFSET_SECONDS} field returns the value of the offset. * All other {@link ChronoField} instances will throw a {@link DateTimeException}. * * If the field is not a {@link ChronoField}, then the result of this method * is obtained by invoking {@link TemporalField.getFrom} * passing `this` as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * * @param {TemporalField} field - the field to get, not null * @return {number} the value for the field * @throws DateTimeException if a value for the field cannot be obtained * @throws ArithmeticException if numeric overflow occurs */ getLong(field) { if (field === ChronoField.OFFSET_SECONDS) { return this._totalSeconds; } else if (field instanceof ChronoField) { throw new DateTimeException(`Unsupported field: ${field}`); } return field.getFrom(this); } //----------------------------------------------------------------------- /** * Queries this offset using the specified query. * * This queries this offset using the specified query strategy object. * The {@link TemporalQuery} object defines the logic to be used to * obtain the result. Read the documentation of the query to understand * what the result of this method will be. * * The result of this method is obtained by invoking the * {@link TemporalQuery#queryFrom} method on the * specified query passing `this` as the argument. * * @param {TemporalQuery} query - the query to invoke, not null * @return {*} the query result, null may be returned (defined by the query) * @throws DateTimeException if unable to query (defined by the query) * @throws ArithmeticException if numeric overflow occurs (defined by the query) */ query(query) { requireNonNull(query, 'query'); if (query === TemporalQueries.offset() || query === TemporalQueries.zone()) { return this; } else if (query === TemporalQueries.localDate() || query === TemporalQueries.localTime() || query === TemporalQueries.precision() || query === TemporalQueries.chronology() || query === TemporalQueries.zoneId()) { return null; } return query.queryFrom(this); } /** * Adjusts the specified temporal object to have the same offset as this object. * * This returns a temporal object of the same observable type as the input * with the offset changed to be the same as this. * * The adjustment is equivalent to using {@link Temporal#with} * passing {@link ChronoField#OFFSET_SECONDS} as the field. * * In most cases, it is clearer to reverse the calling pattern by using * {@link Temporal#with}: * <pre> * // these two lines are equivalent, but the second approach is recommended * temporal = thisOffset.adjustInto(temporal); * temporal = temporal.with(thisOffset); * </pre> * * This instance is immutable and unaffected by this method call. * * @param {Temporal} temporal - the target object to be adjusted, not null * @return {Temporal} the adjusted object, not null * @throws DateTimeException if unable to make the adjustment * @throws ArithmeticException if numeric overflow occurs */ adjustInto(temporal) { return temporal.with(ChronoField.OFFSET_SECONDS, this._totalSeconds); } /** * Compares this offset to another offset in descending order. * * The offsets are compared in the order that they occur for the same time * of day around the world. Thus, an offset of `+10:00` comes before an * offset of `+09:00` and so on down to `-18:00`. * * The comparison is "consistent with equals", as defined by {@link Comparable}. * * @param {!ZoneOffset} other - the other date to compare to, not null * @return {number} the comparator value, negative if less, positive if greater * @throws NullPointerException if {@link other} is null */ compareTo(other) { requireNonNull(other, 'other'); return other._totalSeconds - this._totalSeconds; } /** * Checks if this offset is equal to another offset. * * The comparison is based on the amount of the offset in seconds. * This is equivalent to a comparison by ID. * * @param {*} obj - the object to check, null returns false * @return {boolean} true if this is equal to the other offset */ equals(obj) { if (this === obj) { return true; } if (obj instanceof ZoneOffset) { return this._totalSeconds === obj._totalSeconds; } return false; } /** * @return {number} */ hashCode(){ return this._totalSeconds; } /** * * @returns {string} */ toString(){ return this._id; } } export function _init() { ZoneOffset.MAX_SECONDS = 18 * LocalTime.SECONDS_PER_HOUR; ZoneOffset.UTC = ZoneOffset.ofTotalSeconds(0); ZoneOffset.MIN = ZoneOffset.ofTotalSeconds(-ZoneOffset.MAX_SECONDS); ZoneOffset.MAX = ZoneOffset.ofTotalSeconds(ZoneOffset.MAX_SECONDS); }