UNPKG

quasar

Version:

Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time

1,037 lines (871 loc) 23.8 kB
/* eslint no-fallthrough: 0 */ import { isDate } from '../is/is.js' import { pad, capitalize } from '../format/format.js' import { jalaaliMonthLength } from './private.persian.js' import Lang, { defaultLang } from '../../plugins/lang/Lang.js' const MILLISECONDS_IN_DAY = 86400000, MILLISECONDS_IN_HOUR = 3600000, MILLISECONDS_IN_MINUTE = 60000, defaultMask = 'YYYY-MM-DDTHH:mm:ss.SSSZ', token = /\[((?:[^\]\\]|\\]|\\)*)\]|do|d{1,4}|Mo|M{1,4}|m{1,2}|wo|w{1,2}|Qo|Do|DDDo|D{1,4}|YY(?:YY)?|H{1,2}|h{1,2}|s{1,2}|S{1,3}|Z{1,2}|a{1,2}|[AQExX]/g, reverseToken = /(\[[^\]]*\])|do|d{1,4}|Mo|M{1,4}|m{1,2}|wo|w{1,2}|Qo|Do|DDDo|D{1,4}|YY(?:YY)?|H{1,2}|h{1,2}|s{1,2}|S{1,3}|Z{1,2}|a{1,2}|[AQExX]|([.*+:?^,\s${}()|\\]+)/g, regexStore = {} function getRegexData (mask, dateLocale) { const days = '(' + dateLocale.days.join('|') + ')', key = mask + days if (regexStore[ key ] !== void 0) { return regexStore[ key ] } const daysShort = '(' + dateLocale.daysShort.join('|') + ')', months = '(' + dateLocale.months.join('|') + ')', monthsShort = '(' + dateLocale.monthsShort.join('|') + ')' const map = {} let index = 0 const regexText = mask.replace(reverseToken, match => { index++ switch (match) { case 'YY': map.YY = index return '(-?\\d{1,2})' case 'YYYY': map.YYYY = index return '(-?\\d{1,4})' case 'M': map.M = index return '(\\d{1,2})' case 'Mo': map.M = index++ // bumping to M return '(\\d{1,2}(st|nd|rd|th))' case 'MM': map.M = index // bumping to M return '(\\d{2})' case 'MMM': map.MMM = index return monthsShort case 'MMMM': map.MMMM = index return months case 'D': map.D = index return '(\\d{1,2})' case 'Do': map.D = index++ // bumping to D return '(\\d{1,2}(st|nd|rd|th))' case 'DD': map.D = index // bumping to D return '(\\d{2})' case 'H': map.H = index return '(\\d{1,2})' case 'HH': map.H = index // bumping to H return '(\\d{2})' case 'h': map.h = index return '(\\d{1,2})' case 'hh': map.h = index // bumping to h return '(\\d{2})' case 'm': map.m = index return '(\\d{1,2})' case 'mm': map.m = index // bumping to m return '(\\d{2})' case 's': map.s = index return '(\\d{1,2})' case 'ss': map.s = index // bumping to s return '(\\d{2})' case 'S': map.S = index return '(\\d{1})' case 'SS': map.S = index // bump to S return '(\\d{2})' case 'SSS': map.S = index // bump to S return '(\\d{3})' case 'A': map.A = index return '(AM|PM)' case 'a': map.a = index return '(am|pm)' case 'aa': map.aa = index return '(a\\.m\\.|p\\.m\\.)' case 'ddd': return daysShort case 'dddd': return days case 'Q': case 'd': case 'E': return '(\\d{1})' case 'do': index++ return '(\\d{1}(st|nd|rd|th))' case 'Qo': return '(1st|2nd|3rd|4th)' case 'DDD': case 'DDDD': return '(\\d{1,3})' case 'DDDo': index++ return '(\\d{1,3}(st|nd|rd|th))' case 'w': return '(\\d{1,2})' case 'wo': index++ return '(\\d{1,2}(st|nd|rd|th))' case 'ww': return '(\\d{2})' case 'Z': // to split: (?:(Z)()()|([+-])?(\\d{2}):?(\\d{2})) map.Z = index return '(Z|[+-]\\d{2}:\\d{2})' case 'ZZ': map.ZZ = index return '(Z|[+-]\\d{2}\\d{2})' case 'X': map.X = index return '(-?\\d+)' case 'x': map.x = index return '(-?\\d{4,})' default: index-- if (match[ 0 ] === '[') { match = match.substring(1, match.length - 1) } return match.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') } }) const res = { map, regex: new RegExp('^' + regexText) } regexStore[ key ] = res return res } function getDateLocale (paramDateLocale, langProps) { return paramDateLocale !== void 0 ? paramDateLocale : ( langProps !== void 0 ? langProps.date : defaultLang.date ) } function formatTimezone (offset, delimeter = '') { const sign = offset > 0 ? '-' : '+', absOffset = Math.abs(offset), hours = Math.floor(absOffset / 60), minutes = absOffset % 60 return sign + pad(hours) + delimeter + pad(minutes) } function applyYearMonthDayChange (date, mod, sign) { let year = date.getFullYear(), month = date.getMonth() const day = date.getDate() if (mod.year !== void 0) { year += sign * mod.year delete mod.year } if (mod.month !== void 0) { month += sign * mod.month delete mod.month } date.setDate(1) date.setMonth(2) date.setFullYear(year) date.setMonth(month) date.setDate(Math.min(day, daysInMonth(date))) if (mod.date !== void 0) { date.setDate(date.getDate() + sign * mod.date) delete mod.date } return date } function applyYearMonthDay (date, mod, middle) { const year = mod.year !== void 0 ? mod.year : date[ `get${ middle }FullYear` ](), month = mod.month !== void 0 ? mod.month - 1 : date[ `get${ middle }Month` ](), maxDay = (new Date(year, month + 1, 0)).getDate(), day = Math.min(maxDay, mod.date !== void 0 ? mod.date : date[ `get${ middle }Date` ]()) date[ `set${ middle }Date` ](1) date[ `set${ middle }Month` ](2) date[ `set${ middle }FullYear` ](year) date[ `set${ middle }Month` ](month) date[ `set${ middle }Date` ](day) delete mod.year delete mod.month delete mod.date return date } function getChange (date, rawMod, sign) { const mod = normalizeMod(rawMod), d = new Date(date), t = mod.year !== void 0 || mod.month !== void 0 || mod.date !== void 0 ? applyYearMonthDayChange(d, mod, sign) // removes year/month/day : d for (const key in mod) { const op = capitalize(key) t[ `set${ op }` ](t[ `get${ op }` ]() + sign * mod[ key ]) } return t } function normalizeMod (mod) { const acc = { ...mod } if (mod.years !== void 0) { acc.year = mod.years delete acc.years } if (mod.months !== void 0) { acc.month = mod.months delete acc.months } if (mod.days !== void 0) { acc.date = mod.days delete acc.days } if (mod.day !== void 0) { acc.date = mod.day delete acc.day } if (mod.hour !== void 0) { acc.hours = mod.hour delete acc.hour } if (mod.minute !== void 0) { acc.minutes = mod.minute delete acc.minute } if (mod.second !== void 0) { acc.seconds = mod.second delete acc.second } if (mod.millisecond !== void 0) { acc.milliseconds = mod.millisecond delete acc.millisecond } return acc } export function adjustDate (date, rawMod, utc) { const mod = normalizeMod(rawMod), middle = utc === true ? 'UTC' : '', d = new Date(date), t = mod.year !== void 0 || mod.month !== void 0 || mod.date !== void 0 ? applyYearMonthDay(d, mod, middle) // removes year/month/day : d for (const key in mod) { const op = key.charAt(0).toUpperCase() + key.slice(1) t[ `set${ middle }${ op }` ](mod[ key ]) } return t } export function extractDate (str, mask, dateLocale) { const d = __splitDate(str, mask, dateLocale) const date = new Date( d.year, d.month === null ? null : d.month - 1, d.day === null ? 1 : d.day, d.hour, d.minute, d.second, d.millisecond ) const tzOffset = date.getTimezoneOffset() return d.timezoneOffset === null || d.timezoneOffset === tzOffset ? date : getChange(date, { minutes: d.timezoneOffset - tzOffset }, 1) } export function __splitDate (str, mask, dateLocale, calendar, defaultModel) { const date = { year: null, month: null, day: null, hour: null, minute: null, second: null, millisecond: null, timezoneOffset: null, dateHash: null, timeHash: null } defaultModel !== void 0 && Object.assign(date, defaultModel) if ( str === void 0 || str === null || str === '' || typeof str !== 'string' ) { return date } if (mask === void 0) { mask = defaultMask } const langOpts = getDateLocale(dateLocale, Lang.props), months = langOpts.months, monthsShort = langOpts.monthsShort const { regex, map } = getRegexData(mask, langOpts) const match = str.match(regex) if (match === null) { return date } let tzString = '' if (map.X !== void 0 || map.x !== void 0) { const stamp = parseInt(match[ map.X !== void 0 ? map.X : map.x ], 10) if (isNaN(stamp) === true || stamp < 0) { return date } const d = new Date(stamp * (map.X !== void 0 ? 1000 : 1)) date.year = d.getFullYear() date.month = d.getMonth() + 1 date.day = d.getDate() date.hour = d.getHours() date.minute = d.getMinutes() date.second = d.getSeconds() date.millisecond = d.getMilliseconds() } else { if (map.YYYY !== void 0) { date.year = parseInt(match[ map.YYYY ], 10) } else if (map.YY !== void 0) { const y = parseInt(match[ map.YY ], 10) date.year = y < 0 ? y : 2000 + y } if (map.M !== void 0) { date.month = parseInt(match[ map.M ], 10) if (date.month < 1 || date.month > 12) { return date } } else if (map.MMM !== void 0) { date.month = monthsShort.indexOf(match[ map.MMM ]) + 1 } else if (map.MMMM !== void 0) { date.month = months.indexOf(match[ map.MMMM ]) + 1 } if (map.D !== void 0) { date.day = parseInt(match[ map.D ], 10) if (date.year === null || date.month === null || date.day < 1) { return date } const maxDay = calendar !== 'persian' ? (new Date(date.year, date.month, 0)).getDate() : jalaaliMonthLength(date.year, date.month) if (date.day > maxDay) { return date } } if (map.H !== void 0) { date.hour = parseInt(match[ map.H ], 10) % 24 } else if (map.h !== void 0) { date.hour = parseInt(match[ map.h ], 10) % 12 if ( (map.A && match[ map.A ] === 'PM') || (map.a && match[ map.a ] === 'pm') || (map.aa && match[ map.aa ] === 'p.m.') ) { date.hour += 12 } date.hour = date.hour % 24 } if (map.m !== void 0) { date.minute = parseInt(match[ map.m ], 10) % 60 } if (map.s !== void 0) { date.second = parseInt(match[ map.s ], 10) % 60 } if (map.S !== void 0) { date.millisecond = parseInt(match[ map.S ], 10) * 10 ** (3 - match[ map.S ].length) } if (map.Z !== void 0 || map.ZZ !== void 0) { tzString = (map.Z !== void 0 ? match[ map.Z ].replace(':', '') : match[ map.ZZ ]) date.timezoneOffset = (tzString[ 0 ] === '+' ? -1 : 1) * (60 * tzString.slice(1, 3) + 1 * tzString.slice(3, 5)) } } date.dateHash = pad(date.year, 6) + '/' + pad(date.month) + '/' + pad(date.day) date.timeHash = pad(date.hour) + ':' + pad(date.minute) + ':' + pad(date.second) + tzString return date } export function isValid (date) { return typeof date === 'number' ? true : isNaN(Date.parse(date)) === false } export function buildDate (mod, utc) { return adjustDate(new Date(), mod, utc) } export function getDayOfWeek (date) { const dow = new Date(date).getDay() return dow === 0 ? 7 : dow } export function getWeekOfYear (date) { // Remove time components of date const thursday = new Date(date.getFullYear(), date.getMonth(), date.getDate()) // Change date to Thursday same week thursday.setDate(thursday.getDate() - ((thursday.getDay() + 6) % 7) + 3) // Take January 4th as it is always in week 1 (see ISO 8601) const firstThursday = new Date(thursday.getFullYear(), 0, 4) // Change date to Thursday same week firstThursday.setDate(firstThursday.getDate() - ((firstThursday.getDay() + 6) % 7) + 3) // Check if daylight-saving-time-switch occurred and correct for it const ds = thursday.getTimezoneOffset() - firstThursday.getTimezoneOffset() thursday.setHours(thursday.getHours() - ds) // Number of weeks between target Thursday and first Thursday const weekDiff = (thursday - firstThursday) / (MILLISECONDS_IN_DAY * 7) return 1 + Math.floor(weekDiff) } function getDayIdentifier (date) { return date.getFullYear() * 10000 + date.getMonth() * 100 + date.getDate() } function getDateIdentifier (date, onlyDate /* = false */) { const d = new Date(date) return onlyDate === true ? getDayIdentifier(d) : d.getTime() } export function isBetweenDates (date, from, to, opts = {}) { const d1 = getDateIdentifier(from, opts.onlyDate), d2 = getDateIdentifier(to, opts.onlyDate), cur = getDateIdentifier(date, opts.onlyDate) return (cur > d1 || (opts.inclusiveFrom === true && cur === d1)) && (cur < d2 || (opts.inclusiveTo === true && cur === d2)) } export function addToDate (date, mod) { return getChange(date, mod, 1) } export function subtractFromDate (date, mod) { return getChange(date, mod, -1) } export function startOfDate (date, unit, utc) { const t = new Date(date), prefix = `set${ utc === true ? 'UTC' : '' }` switch (unit) { case 'year': case 'years': t[ `${ prefix }Month` ](0) case 'month': case 'months': t[ `${ prefix }Date` ](1) case 'day': case 'days': case 'date': t[ `${ prefix }Hours` ](0) case 'hour': case 'hours': t[ `${ prefix }Minutes` ](0) case 'minute': case 'minutes': t[ `${ prefix }Seconds` ](0) case 'second': case 'seconds': t[ `${ prefix }Milliseconds` ](0) } return t } export function endOfDate (date, unit, utc) { const t = new Date(date), prefix = `set${ utc === true ? 'UTC' : '' }` switch (unit) { case 'year': case 'years': t[ `${ prefix }Month` ](11) case 'month': case 'months': t[ `${ prefix }Date` ](daysInMonth(t)) case 'day': case 'days': case 'date': t[ `${ prefix }Hours` ](23) case 'hour': case 'hours': t[ `${ prefix }Minutes` ](59) case 'minute': case 'minutes': t[ `${ prefix }Seconds` ](59) case 'second': case 'seconds': t[ `${ prefix }Milliseconds` ](999) } return t } export function getMaxDate (date /* , ...args */) { let t = new Date(date) Array.prototype.slice.call(arguments, 1).forEach(d => { t = Math.max(t, new Date(d)) }) return t } export function getMinDate (date /*, ...args */) { let t = new Date(date) Array.prototype.slice.call(arguments, 1).forEach(d => { t = Math.min(t, new Date(d)) }) return t } function getDiff (t, sub, interval) { return ( (t.getTime() - t.getTimezoneOffset() * MILLISECONDS_IN_MINUTE) - (sub.getTime() - sub.getTimezoneOffset() * MILLISECONDS_IN_MINUTE) ) / interval } export function getDateDiff (date, subtract, unit = 'days') { const t = new Date(date), sub = new Date(subtract) switch (unit) { case 'years': case 'year': return (t.getFullYear() - sub.getFullYear()) case 'months': case 'month': return (t.getFullYear() - sub.getFullYear()) * 12 + t.getMonth() - sub.getMonth() case 'days': case 'day': case 'date': return getDiff(startOfDate(t, 'day'), startOfDate(sub, 'day'), MILLISECONDS_IN_DAY) case 'hours': case 'hour': return getDiff(startOfDate(t, 'hour'), startOfDate(sub, 'hour'), MILLISECONDS_IN_HOUR) case 'minutes': case 'minute': return getDiff(startOfDate(t, 'minute'), startOfDate(sub, 'minute'), MILLISECONDS_IN_MINUTE) case 'seconds': case 'second': return getDiff(startOfDate(t, 'second'), startOfDate(sub, 'second'), 1000) } } export function getDayOfYear (date) { return getDateDiff(date, startOfDate(date, 'year'), 'days') + 1 } export function inferDateFormat (date) { return isDate(date) === true ? 'date' : (typeof date === 'number' ? 'number' : 'string') } export function getDateBetween (date, min, max) { const t = new Date(date) if (min) { const low = new Date(min) if (t < low) { return low } } if (max) { const high = new Date(max) if (t > high) { return high } } return t } export function isSameDate (date, date2, unit) { const t = new Date(date), d = new Date(date2) if (unit === void 0) { return t.getTime() === d.getTime() } switch (unit) { case 'second': case 'seconds': if (t.getSeconds() !== d.getSeconds()) { return false } case 'minute': // intentional fall-through case 'minutes': if (t.getMinutes() !== d.getMinutes()) { return false } case 'hour': // intentional fall-through case 'hours': if (t.getHours() !== d.getHours()) { return false } case 'day': // intentional fall-through case 'days': case 'date': if (t.getDate() !== d.getDate()) { return false } case 'month': // intentional fall-through case 'months': if (t.getMonth() !== d.getMonth()) { return false } case 'year': // intentional fall-through case 'years': if (t.getFullYear() !== d.getFullYear()) { return false } break default: throw new Error(`date isSameDate unknown unit ${ unit }`) } return true } export function daysInMonth (date) { return (new Date(date.getFullYear(), date.getMonth() + 1, 0)).getDate() } function getOrdinal (n) { if (n >= 11 && n <= 13) { return `${ n }th` } switch (n % 10) { case 1: return `${ n }st` case 2: return `${ n }nd` case 3: return `${ n }rd` } return `${ n }th` } const formatter = { // Year: 00, 01, ..., 99 YY (date, dateLocale, forcedYear) { // workaround for < 1900 with new Date() const y = this.YYYY(date, dateLocale, forcedYear) % 100 return y >= 0 ? pad(y) : '-' + pad(Math.abs(y)) }, // Year: 1900, 1901, ..., 2099 YYYY (date, _dateLocale, forcedYear) { // workaround for < 1900 with new Date() return forcedYear !== void 0 && forcedYear !== null ? forcedYear : date.getFullYear() }, // Month: 1, 2, ..., 12 M (date) { return date.getMonth() + 1 }, // Month: 1st, 2nd, ..., 12th Mo (date) { return getOrdinal(date.getMonth() + 1) }, // Month: 01, 02, ..., 12 MM (date) { return pad(date.getMonth() + 1) }, // Month Short Name: Jan, Feb, ... MMM (date, dateLocale) { return dateLocale.monthsShort[ date.getMonth() ] }, // Month Name: January, February, ... MMMM (date, dateLocale) { return dateLocale.months[ date.getMonth() ] }, // Quarter: 1, 2, 3, 4 Q (date) { return Math.ceil((date.getMonth() + 1) / 3) }, // Quarter: 1st, 2nd, 3rd, 4th Qo (date) { return getOrdinal(this.Q(date)) }, // Day of month: 1, 2, ..., 31 D (date) { return date.getDate() }, // Day of month: 1st, 2nd, ..., 31st Do (date) { return getOrdinal(date.getDate()) }, // Day of month: 01, 02, ..., 31 DD (date) { return pad(date.getDate()) }, // Day of year: 1, 2, ..., 366 DDD (date) { return getDayOfYear(date) }, // Day of year: 1st, 2nd, ..., 366th DDDo (date) { return getOrdinal(getDayOfYear(date)) }, // Day of year: 001, 002, ..., 366 DDDD (date) { return pad(getDayOfYear(date), 3) }, // Day of week: 0, 1, ..., 6 d (date) { return date.getDay() }, // Day of week: 0th, 1st, ..., 6th do (date) { return getOrdinal(date.getDay()) }, // Day of week: Su, Mo, ... dd (date, dateLocale) { return (dateLocale.days[ date.getDay() ]).slice(0, 2) }, // Day of week: Sun, Mon, ... ddd (date, dateLocale) { return dateLocale.daysShort[ date.getDay() ] }, // Day of week: Sunday, Monday, ... dddd (date, dateLocale) { return dateLocale.days[ date.getDay() ] }, // Day of ISO week: 1, 2, ..., 7 E (date) { return date.getDay() || 7 }, // Week of Year: 1 2 ... 52 53 w (date) { return getWeekOfYear(date) }, // Week of Year: 1st 2nd ... 52nd 53rd wo (date) { return getOrdinal(getWeekOfYear(date)) }, // Week of Year: 01 02 ... 52 53 ww (date) { return pad(getWeekOfYear(date)) }, // Hour: 0, 1, ... 23 H (date) { return date.getHours() }, // Hour: 00, 01, ..., 23 HH (date) { return pad(date.getHours()) }, // Hour: 1, 2, ..., 12 h (date) { const hours = date.getHours() return hours === 0 ? 12 : (hours > 12 ? hours % 12 : hours) }, // Hour: 01, 02, ..., 12 hh (date) { return pad(this.h(date)) }, // Minute: 0, 1, ..., 59 m (date) { return date.getMinutes() }, // Minute: 00, 01, ..., 59 mm (date) { return pad(date.getMinutes()) }, // Second: 0, 1, ..., 59 s (date) { return date.getSeconds() }, // Second: 00, 01, ..., 59 ss (date) { return pad(date.getSeconds()) }, // 1/10 of second: 0, 1, ..., 9 S (date) { return Math.floor(date.getMilliseconds() / 100) }, // 1/100 of second: 00, 01, ..., 99 SS (date) { return pad(Math.floor(date.getMilliseconds() / 10)) }, // Millisecond: 000, 001, ..., 999 SSS (date) { return pad(date.getMilliseconds(), 3) }, // Meridiem: AM, PM A (date) { return date.getHours() < 12 ? 'AM' : 'PM' }, // Meridiem: am, pm a (date) { return date.getHours() < 12 ? 'am' : 'pm' }, // Meridiem: a.m., p.m. aa (date) { return date.getHours() < 12 ? 'a.m.' : 'p.m.' }, // Timezone: -01:00, +00:00, ... +12:00 Z (date, _dateLocale, _forcedYear, forcedTimezoneOffset) { const tzOffset = forcedTimezoneOffset === void 0 || forcedTimezoneOffset === null ? date.getTimezoneOffset() : forcedTimezoneOffset return formatTimezone(tzOffset, ':') }, // Timezone: -0100, +0000, ... +1200 ZZ (date, _dateLocale, _forcedYear, forcedTimezoneOffset) { const tzOffset = forcedTimezoneOffset === void 0 || forcedTimezoneOffset === null ? date.getTimezoneOffset() : forcedTimezoneOffset return formatTimezone(tzOffset) }, // Seconds timestamp: 512969520 X (date) { return Math.floor(date.getTime() / 1000) }, // Milliseconds timestamp: 512969520900 x (date) { return date.getTime() } } export function formatDate (val, mask, dateLocale, __forcedYear, __forcedTimezoneOffset) { if ( (val !== 0 && !val) || val === Infinity || val === -Infinity ) { return } const date = new Date(val) if (isNaN(date)) { return } if (mask === void 0) { mask = defaultMask } const locale = getDateLocale(dateLocale, Lang.props) return mask.replace( token, (match, text) => ( match in formatter ? formatter[ match ](date, locale, __forcedYear, __forcedTimezoneOffset) : (text === void 0 ? match : text.split('\\]').join(']')) ) ) } export function clone (date) { return isDate(date) === true ? new Date(date.getTime()) : date } export default { isValid, extractDate, buildDate, getDayOfWeek, getWeekOfYear, isBetweenDates, addToDate, subtractFromDate, adjustDate, startOfDate, endOfDate, getMaxDate, getMinDate, getDateDiff, getDayOfYear, inferDateFormat, getDateBetween, isSameDate, daysInMonth, formatDate, clone }