456 lines
11 KiB
JavaScript
456 lines
11 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.default = toDate;
|
|
|
|
var _index = _interopRequireDefault(require("date-fns/_lib/toInteger/index.js"));
|
|
|
|
var _index2 = _interopRequireDefault(require("date-fns/_lib/getTimezoneOffsetInMilliseconds/index.js"));
|
|
|
|
var _index3 = _interopRequireDefault(require("../_lib/tzParseTimezone/index.js"));
|
|
|
|
var _index4 = _interopRequireDefault(require("../_lib/tzPattern/index.js"));
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
var MILLISECONDS_IN_HOUR = 3600000;
|
|
var MILLISECONDS_IN_MINUTE = 60000;
|
|
var DEFAULT_ADDITIONAL_DIGITS = 2;
|
|
var patterns = {
|
|
dateTimePattern: /^([0-9W+-]+)(T| )(.*)/,
|
|
datePattern: /^([0-9W+-]+)(.*)/,
|
|
plainTime: /:/,
|
|
// year tokens
|
|
YY: /^(\d{2})$/,
|
|
YYY: [/^([+-]\d{2})$/, // 0 additional digits
|
|
/^([+-]\d{3})$/, // 1 additional digit
|
|
/^([+-]\d{4})$/ // 2 additional digits
|
|
],
|
|
YYYY: /^(\d{4})/,
|
|
YYYYY: [/^([+-]\d{4})/, // 0 additional digits
|
|
/^([+-]\d{5})/, // 1 additional digit
|
|
/^([+-]\d{6})/ // 2 additional digits
|
|
],
|
|
// date tokens
|
|
MM: /^-(\d{2})$/,
|
|
DDD: /^-?(\d{3})$/,
|
|
MMDD: /^-?(\d{2})-?(\d{2})$/,
|
|
Www: /^-?W(\d{2})$/,
|
|
WwwD: /^-?W(\d{2})-?(\d{1})$/,
|
|
HH: /^(\d{2}([.,]\d*)?)$/,
|
|
HHMM: /^(\d{2}):?(\d{2}([.,]\d*)?)$/,
|
|
HHMMSS: /^(\d{2}):?(\d{2}):?(\d{2}([.,]\d*)?)$/,
|
|
// time zone tokens (to identify the presence of a tz)
|
|
timeZone: _index4.default
|
|
};
|
|
/**
|
|
* @name toDate
|
|
* @category Common Helpers
|
|
* @summary Convert the given argument to an instance of Date.
|
|
*
|
|
* @description
|
|
* Convert the given argument to an instance of Date.
|
|
*
|
|
* If the argument is an instance of Date, the function returns its clone.
|
|
*
|
|
* If the argument is a number, it is treated as a timestamp.
|
|
*
|
|
* If an argument is a string, the function tries to parse it.
|
|
* Function accepts complete ISO 8601 formats as well as partial implementations.
|
|
* ISO 8601: http://en.wikipedia.org/wiki/ISO_8601
|
|
* If the function cannot parse the string or the values are invalid, it returns Invalid Date.
|
|
*
|
|
* If the argument is none of the above, the function returns Invalid Date.
|
|
*
|
|
* **Note**: *all* Date arguments passed to any *date-fns* function is processed by `toDate`.
|
|
* All *date-fns* functions will throw `RangeError` if `options.additionalDigits` is not 0, 1, 2 or undefined.
|
|
*
|
|
* @param {Date|String|Number} argument - the value to convert
|
|
* @param {OptionsWithTZ} [options] - the object with options. See [Options]{@link https://date-fns.org/docs/Options}
|
|
* @param {0|1|2} [options.additionalDigits=2] - the additional number of digits in the extended year format
|
|
* @param {String} [options.timeZone=''] - used to specify the IANA time zone offset of a date String.
|
|
* @returns {Date} the parsed date in the local time zone
|
|
* @throws {TypeError} 1 argument required
|
|
* @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
|
|
*
|
|
* @example
|
|
* // Convert string '2014-02-11T11:30:30' to date:
|
|
* var result = toDate('2014-02-11T11:30:30')
|
|
* //=> Tue Feb 11 2014 11:30:30
|
|
*
|
|
* @example
|
|
* // Convert string '+02014101' to date,
|
|
* // if the additional number of digits in the extended year format is 1:
|
|
* var result = toDate('+02014101', {additionalDigits: 1})
|
|
* //=> Fri Apr 11 2014 00:00:00
|
|
*/
|
|
|
|
function toDate(argument, dirtyOptions) {
|
|
if (arguments.length < 1) {
|
|
throw new TypeError('1 argument required, but only ' + arguments.length + ' present');
|
|
}
|
|
|
|
if (argument === null) {
|
|
return new Date(NaN);
|
|
}
|
|
|
|
var options = dirtyOptions || {};
|
|
var additionalDigits = options.additionalDigits == null ? DEFAULT_ADDITIONAL_DIGITS : (0, _index.default)(options.additionalDigits);
|
|
|
|
if (additionalDigits !== 2 && additionalDigits !== 1 && additionalDigits !== 0) {
|
|
throw new RangeError('additionalDigits must be 0, 1 or 2');
|
|
} // Clone the date
|
|
|
|
|
|
if (argument instanceof Date || typeof argument === 'object' && Object.prototype.toString.call(argument) === '[object Date]') {
|
|
// Prevent the date to lose the milliseconds when passed to new Date() in IE10
|
|
return new Date(argument.getTime());
|
|
} else if (typeof argument === 'number' || Object.prototype.toString.call(argument) === '[object Number]') {
|
|
return new Date(argument);
|
|
} else if (!(typeof argument === 'string' || Object.prototype.toString.call(argument) === '[object String]')) {
|
|
return new Date(NaN);
|
|
}
|
|
|
|
var dateStrings = splitDateString(argument);
|
|
var parseYearResult = parseYear(dateStrings.date, additionalDigits);
|
|
var year = parseYearResult.year;
|
|
var restDateString = parseYearResult.restDateString;
|
|
var date = parseDate(restDateString, year);
|
|
|
|
if (isNaN(date)) {
|
|
return new Date(NaN);
|
|
}
|
|
|
|
if (date) {
|
|
var timestamp = date.getTime();
|
|
var time = 0;
|
|
var offset;
|
|
|
|
if (dateStrings.time) {
|
|
time = parseTime(dateStrings.time);
|
|
|
|
if (isNaN(time)) {
|
|
return new Date(NaN);
|
|
}
|
|
}
|
|
|
|
if (dateStrings.timeZone || options.timeZone) {
|
|
offset = (0, _index3.default)(dateStrings.timeZone || options.timeZone, new Date(timestamp + time));
|
|
|
|
if (isNaN(offset)) {
|
|
return new Date(NaN);
|
|
}
|
|
} else {
|
|
// get offset accurate to hour in time zones that change offset
|
|
offset = (0, _index2.default)(new Date(timestamp + time));
|
|
offset = (0, _index2.default)(new Date(timestamp + time + offset));
|
|
}
|
|
|
|
return new Date(timestamp + time + offset);
|
|
} else {
|
|
return new Date(NaN);
|
|
}
|
|
}
|
|
|
|
function splitDateString(dateString) {
|
|
var dateStrings = {};
|
|
var parts = patterns.dateTimePattern.exec(dateString);
|
|
var timeString;
|
|
|
|
if (!parts) {
|
|
parts = patterns.datePattern.exec(dateString);
|
|
|
|
if (parts) {
|
|
dateStrings.date = parts[1];
|
|
timeString = parts[2];
|
|
} else {
|
|
dateStrings.date = null;
|
|
timeString = dateString;
|
|
}
|
|
} else {
|
|
dateStrings.date = parts[1];
|
|
timeString = parts[3];
|
|
}
|
|
|
|
if (timeString) {
|
|
var token = patterns.timeZone.exec(timeString);
|
|
|
|
if (token) {
|
|
dateStrings.time = timeString.replace(token[1], '');
|
|
dateStrings.timeZone = token[1].trim();
|
|
} else {
|
|
dateStrings.time = timeString;
|
|
}
|
|
}
|
|
|
|
return dateStrings;
|
|
}
|
|
|
|
function parseYear(dateString, additionalDigits) {
|
|
var patternYYY = patterns.YYY[additionalDigits];
|
|
var patternYYYYY = patterns.YYYYY[additionalDigits];
|
|
var token; // YYYY or ±YYYYY
|
|
|
|
token = patterns.YYYY.exec(dateString) || patternYYYYY.exec(dateString);
|
|
|
|
if (token) {
|
|
var yearString = token[1];
|
|
return {
|
|
year: parseInt(yearString, 10),
|
|
restDateString: dateString.slice(yearString.length)
|
|
};
|
|
} // YY or ±YYY
|
|
|
|
|
|
token = patterns.YY.exec(dateString) || patternYYY.exec(dateString);
|
|
|
|
if (token) {
|
|
var centuryString = token[1];
|
|
return {
|
|
year: parseInt(centuryString, 10) * 100,
|
|
restDateString: dateString.slice(centuryString.length)
|
|
};
|
|
} // Invalid ISO-formatted year
|
|
|
|
|
|
return {
|
|
year: null
|
|
};
|
|
}
|
|
|
|
function parseDate(dateString, year) {
|
|
// Invalid ISO-formatted year
|
|
if (year === null) {
|
|
return null;
|
|
}
|
|
|
|
var token;
|
|
var date;
|
|
var month;
|
|
var week; // YYYY
|
|
|
|
if (dateString.length === 0) {
|
|
date = new Date(0);
|
|
date.setUTCFullYear(year);
|
|
return date;
|
|
} // YYYY-MM
|
|
|
|
|
|
token = patterns.MM.exec(dateString);
|
|
|
|
if (token) {
|
|
date = new Date(0);
|
|
month = parseInt(token[1], 10) - 1;
|
|
|
|
if (!validateDate(year, month)) {
|
|
return new Date(NaN);
|
|
}
|
|
|
|
date.setUTCFullYear(year, month);
|
|
return date;
|
|
} // YYYY-DDD or YYYYDDD
|
|
|
|
|
|
token = patterns.DDD.exec(dateString);
|
|
|
|
if (token) {
|
|
date = new Date(0);
|
|
var dayOfYear = parseInt(token[1], 10);
|
|
|
|
if (!validateDayOfYearDate(year, dayOfYear)) {
|
|
return new Date(NaN);
|
|
}
|
|
|
|
date.setUTCFullYear(year, 0, dayOfYear);
|
|
return date;
|
|
} // yyyy-MM-dd or YYYYMMDD
|
|
|
|
|
|
token = patterns.MMDD.exec(dateString);
|
|
|
|
if (token) {
|
|
date = new Date(0);
|
|
month = parseInt(token[1], 10) - 1;
|
|
var day = parseInt(token[2], 10);
|
|
|
|
if (!validateDate(year, month, day)) {
|
|
return new Date(NaN);
|
|
}
|
|
|
|
date.setUTCFullYear(year, month, day);
|
|
return date;
|
|
} // YYYY-Www or YYYYWww
|
|
|
|
|
|
token = patterns.Www.exec(dateString);
|
|
|
|
if (token) {
|
|
week = parseInt(token[1], 10) - 1;
|
|
|
|
if (!validateWeekDate(year, week)) {
|
|
return new Date(NaN);
|
|
}
|
|
|
|
return dayOfISOWeekYear(year, week);
|
|
} // YYYY-Www-D or YYYYWwwD
|
|
|
|
|
|
token = patterns.WwwD.exec(dateString);
|
|
|
|
if (token) {
|
|
week = parseInt(token[1], 10) - 1;
|
|
var dayOfWeek = parseInt(token[2], 10) - 1;
|
|
|
|
if (!validateWeekDate(year, week, dayOfWeek)) {
|
|
return new Date(NaN);
|
|
}
|
|
|
|
return dayOfISOWeekYear(year, week, dayOfWeek);
|
|
} // Invalid ISO-formatted date
|
|
|
|
|
|
return null;
|
|
}
|
|
|
|
function parseTime(timeString) {
|
|
var token;
|
|
var hours;
|
|
var minutes; // hh
|
|
|
|
token = patterns.HH.exec(timeString);
|
|
|
|
if (token) {
|
|
hours = parseFloat(token[1].replace(',', '.'));
|
|
|
|
if (!validateTime(hours)) {
|
|
return NaN;
|
|
}
|
|
|
|
return hours % 24 * MILLISECONDS_IN_HOUR;
|
|
} // hh:mm or hhmm
|
|
|
|
|
|
token = patterns.HHMM.exec(timeString);
|
|
|
|
if (token) {
|
|
hours = parseInt(token[1], 10);
|
|
minutes = parseFloat(token[2].replace(',', '.'));
|
|
|
|
if (!validateTime(hours, minutes)) {
|
|
return NaN;
|
|
}
|
|
|
|
return hours % 24 * MILLISECONDS_IN_HOUR + minutes * MILLISECONDS_IN_MINUTE;
|
|
} // hh:mm:ss or hhmmss
|
|
|
|
|
|
token = patterns.HHMMSS.exec(timeString);
|
|
|
|
if (token) {
|
|
hours = parseInt(token[1], 10);
|
|
minutes = parseInt(token[2], 10);
|
|
var seconds = parseFloat(token[3].replace(',', '.'));
|
|
|
|
if (!validateTime(hours, minutes, seconds)) {
|
|
return NaN;
|
|
}
|
|
|
|
return hours % 24 * MILLISECONDS_IN_HOUR + minutes * MILLISECONDS_IN_MINUTE + seconds * 1000;
|
|
} // Invalid ISO-formatted time
|
|
|
|
|
|
return null;
|
|
}
|
|
|
|
function dayOfISOWeekYear(isoWeekYear, week, day) {
|
|
week = week || 0;
|
|
day = day || 0;
|
|
var date = new Date(0);
|
|
date.setUTCFullYear(isoWeekYear, 0, 4);
|
|
var fourthOfJanuaryDay = date.getUTCDay() || 7;
|
|
var diff = week * 7 + day + 1 - fourthOfJanuaryDay;
|
|
date.setUTCDate(date.getUTCDate() + diff);
|
|
return date;
|
|
} // Validation functions
|
|
|
|
|
|
var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
var DAYS_IN_MONTH_LEAP_YEAR = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
|
|
function isLeapYearIndex(year) {
|
|
return year % 400 === 0 || year % 4 === 0 && year % 100 !== 0;
|
|
}
|
|
|
|
function validateDate(year, month, date) {
|
|
if (month < 0 || month > 11) {
|
|
return false;
|
|
}
|
|
|
|
if (date != null) {
|
|
if (date < 1) {
|
|
return false;
|
|
}
|
|
|
|
var isLeapYear = isLeapYearIndex(year);
|
|
|
|
if (isLeapYear && date > DAYS_IN_MONTH_LEAP_YEAR[month]) {
|
|
return false;
|
|
}
|
|
|
|
if (!isLeapYear && date > DAYS_IN_MONTH[month]) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function validateDayOfYearDate(year, dayOfYear) {
|
|
if (dayOfYear < 1) {
|
|
return false;
|
|
}
|
|
|
|
var isLeapYear = isLeapYearIndex(year);
|
|
|
|
if (isLeapYear && dayOfYear > 366) {
|
|
return false;
|
|
}
|
|
|
|
if (!isLeapYear && dayOfYear > 365) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function validateWeekDate(year, week, day) {
|
|
if (week < 0 || week > 52) {
|
|
return false;
|
|
}
|
|
|
|
if (day != null && (day < 0 || day > 6)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function validateTime(hours, minutes, seconds) {
|
|
if (hours != null && (hours < 0 || hours >= 25)) {
|
|
return false;
|
|
}
|
|
|
|
if (minutes != null && (minutes < 0 || minutes >= 60)) {
|
|
return false;
|
|
}
|
|
|
|
if (seconds != null && (seconds < 0 || seconds >= 60)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
module.exports = exports.default; |