"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;