import toInteger from '../_lib/toInteger/index.ts'import requiredArgs from '../_lib/requiredArgs/index.ts'
var MILLISECONDS_IN_HOUR = 3600000var MILLISECONDS_IN_MINUTE = 60000var DEFAULT_ADDITIONAL_DIGITS = 2
var patterns = { dateTimeDelimiter: /[T ]/, timeZoneDelimiter: /[Z ]/i, timezone: /([Z+-].*)$/,}
var dateRegex = /^-?(?:(\d{3})|(\d{2})(?:-?(\d{2}))?|W(\d{2})(?:-?(\d{1}))?|)$/var timeRegex = /^(\d{2}(?:[.,]\d*)?)(?::?(\d{2}(?:[.,]\d*)?))?(?::?(\d{2}(?:[.,]\d*)?))?$/var timezoneRegex = /^([+-])(\d{2})(?::?(\d{2}))?$/
export default function parseISO(argument, dirtyOptions) { requiredArgs(1, arguments)
var options = dirtyOptions || {}
var additionalDigits = options.additionalDigits == null ? DEFAULT_ADDITIONAL_DIGITS : toInteger(options.additionalDigits) if ( additionalDigits !== 2 && additionalDigits !== 1 && additionalDigits !== 0 ) { throw new RangeError('additionalDigits must be 0, 1 or 2') }
if ( !( typeof argument === 'string' || Object.prototype.toString.call(argument) === '[object String]' ) ) { return new Date(NaN) }
var dateStrings = splitDateString(argument)
var date if (dateStrings.date) { var parseYearResult = parseYear(dateStrings.date, additionalDigits) date = parseDate(parseYearResult.restDateString, parseYearResult.year) }
if (isNaN(date) || !date) { return new Date(NaN) }
var timestamp = date.getTime() var time = 0 var offset
if (dateStrings.time) { time = parseTime(dateStrings.time) if (isNaN(time) || time === null) { return new Date(NaN) } }
if (dateStrings.timezone) { offset = parseTimezone(dateStrings.timezone) if (isNaN(offset)) { return new Date(NaN) } } else { var dirtyDate = new Date(timestamp + time) var result = new Date(0) result.setFullYear( dirtyDate.getUTCFullYear(), dirtyDate.getUTCMonth(), dirtyDate.getUTCDate() ) result.setHours( dirtyDate.getUTCHours(), dirtyDate.getUTCMinutes(), dirtyDate.getUTCSeconds(), dirtyDate.getUTCMilliseconds() ) return result }
return new Date(timestamp + time + offset)}
function splitDateString(dateString) { var dateStrings = {} var array = dateString.split(patterns.dateTimeDelimiter) var timeString
if (array.length > 2) { return dateStrings }
if (/:/.test(array[0])) { dateStrings.date = null timeString = array[0] } else { dateStrings.date = array[0] timeString = array[1] if (patterns.timeZoneDelimiter.test(dateStrings.date)) { dateStrings.date = dateString.split(patterns.timeZoneDelimiter)[0] timeString = dateString.substr(dateStrings.date.length, dateString.length) } }
if (timeString) { var token = patterns.timezone.exec(timeString) if (token) { dateStrings.time = timeString.replace(token[1], '') dateStrings.timezone = token[1] } else { dateStrings.time = timeString } }
return dateStrings}
function parseYear(dateString, additionalDigits) { var regex = new RegExp( '^(?:(\\d{4}|[+-]\\d{' + (4 + additionalDigits) + '})|(\\d{2}|[+-]\\d{' + (2 + additionalDigits) + '})$)' )
var captures = dateString.match(regex) if (!captures) return { year: null }
var year = captures[1] && parseInt(captures[1]) var century = captures[2] && parseInt(captures[2])
return { year: century == null ? year : century * 100, restDateString: dateString.slice((captures[1] || captures[2]).length), }}
function parseDate(dateString, year) { if (year === null) return null
var captures = dateString.match(dateRegex) if (!captures) return null
var isWeekDate = !!captures[4] var dayOfYear = parseDateUnit(captures[1]) var month = parseDateUnit(captures[2]) - 1 var day = parseDateUnit(captures[3]) var week = parseDateUnit(captures[4]) var dayOfWeek = parseDateUnit(captures[5]) - 1
if (isWeekDate) { if (!validateWeekDate(year, week, dayOfWeek)) { return new Date(NaN) } return dayOfISOWeekYear(year, week, dayOfWeek) } else { var date = new Date(0) if ( !validateDate(year, month, day) || !validateDayOfYearDate(year, dayOfYear) ) { return new Date(NaN) } date.setUTCFullYear(year, month, Math.max(dayOfYear, day)) return date }}
function parseDateUnit(value) { return value ? parseInt(value) : 1}
function parseTime(timeString) { var captures = timeString.match(timeRegex) if (!captures) return null
var hours = parseTimeUnit(captures[1]) var minutes = parseTimeUnit(captures[2]) var seconds = parseTimeUnit(captures[3])
if (!validateTime(hours, minutes, seconds)) { return NaN }
return ( hours * MILLISECONDS_IN_HOUR + minutes * MILLISECONDS_IN_MINUTE + seconds * 1000 )}
function parseTimeUnit(value) { return (value && parseFloat(value.replace(',', '.'))) || 0}
function parseTimezone(timezoneString) { if (timezoneString === 'Z') return 0
var captures = timezoneString.match(timezoneRegex) if (!captures) return 0
var sign = captures[1] === '+' ? -1 : 1 var hours = parseInt(captures[2]) var minutes = (captures[3] && parseInt(captures[3])) || 0
if (!validateTimezone(hours, minutes)) { return NaN }
return ( sign * (hours * MILLISECONDS_IN_HOUR + minutes * MILLISECONDS_IN_MINUTE) )}
function dayOfISOWeekYear(isoWeekYear, week, day) { var date = new Date(0) date.setUTCFullYear(isoWeekYear, 0, 4) var fourthOfJanuaryDay = date.getUTCDay() || 7 var diff = (week - 1) * 7 + day + 1 - fourthOfJanuaryDay date.setUTCDate(date.getUTCDate() + diff) return date}
var daysInMonths = [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
function isLeapYearIndex(year) { return year % 400 === 0 || (year % 4 === 0 && year % 100)}
function validateDate(year, month, date) { return ( month >= 0 && month <= 11 && date >= 1 && date <= (daysInMonths[month] || (isLeapYearIndex(year) ? 29 : 28)) )}
function validateDayOfYearDate(year, dayOfYear) { return dayOfYear >= 1 && dayOfYear <= (isLeapYearIndex(year) ? 366 : 365)}
function validateWeekDate(_year, week, day) { return week >= 1 && week <= 53 && day >= 0 && day <= 6}
function validateTime(hours, minutes, seconds) { if (hours === 24) { return minutes === 0 && seconds === 0 }
return ( seconds >= 0 && seconds < 60 && minutes >= 0 && minutes < 60 && hours >= 0 && hours < 25 )}
function validateTimezone(_hours, minutes) { return minutes >= 0 && minutes <= 59}