quasar-framework
Version:
Build responsive SPA, SSR, PWA, Hybrid Mobile Apps and Electron apps, all simultaneously using the same codebase
575 lines (478 loc) • 12.4 kB
JavaScript
/* eslint no-fallthrough: 0 */
import { isDate, isString } from './is.js'
import { pad, capitalize } from './format.js'
import i18n from '../i18n.js'
const
MILLISECONDS_IN_DAY = 86400000,
MILLISECONDS_IN_HOUR = 3600000,
MILLISECONDS_IN_MINUTE = 60000,
token = /\[((?:[^\]\\]|\\]|\\)*)\]|d{1,4}|M{1,4}|m{1,2}|w{1,2}|Qo|Do|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,
reMySQLDateTimeStr = /^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]{6})?$/
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 setMonth (date, newMonth /* 1-based */) {
const
test = new Date(date.getFullYear(), newMonth, 0, 0, 0, 0, 0),
days = test.getDate()
date.setMonth(newMonth - 1, Math.min(days, date.getDate()))
}
function buildDateVal (d) {
return new Date(isString(d) && reMySQLDateTimeStr.exec(d) !== null ? d.substring(0, 23).replace(' ', 'T') : d)
}
function getChange (date, mod, add) {
const
t = buildDateVal(date),
sign = (add ? 1 : -1)
Object.keys(mod).forEach(key => {
if (key === 'month') {
setMonth(t, t.getMonth() + 1 + sign * mod.month)
return
}
const op = key === 'year'
? 'FullYear'
: capitalize(key === 'days' ? 'date' : key)
t[`set${op}`](t[`get${op}`]() + sign * mod[key])
})
return t
}
export function isValid (date) {
if (typeof date === 'number') {
return true
}
const t = Date.parse(date)
return isNaN(t) === false
}
export function buildDate (mod, utc) {
return adjustDate(new Date(), mod, utc)
}
export function getDayOfWeek (date) {
const dow = buildDateVal(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)
}
export function isBetweenDates (date, from, to, opts = {}) {
let
d1 = buildDateVal(from).getTime(),
d2 = buildDateVal(to).getTime(),
cur = buildDateVal(date).getTime()
opts.inclusiveFrom && d1--
opts.inclusiveTo && d2++
return cur > d1 && cur < d2
}
export function addToDate (date, mod) {
return getChange(date, mod, true)
}
export function subtractFromDate (date, mod) {
return getChange(date, mod, false)
}
export function adjustDate (date, mod, utc) {
const
t = buildDateVal(date),
prefix = `set${utc ? 'UTC' : ''}`
Object.keys(mod).forEach(key => {
if (key === 'month') {
setMonth(t, mod.month)
return
}
const op = key === 'year'
? 'FullYear'
: key.charAt(0).toUpperCase() + key.slice(1)
t[`${prefix}${op}`](mod[key])
})
return t
}
export function startOfDate (date, unit) {
const t = buildDateVal(date)
switch (unit) {
case 'year':
t.setMonth(0)
case 'month':
t.setDate(1)
case 'day':
t.setHours(0)
case 'hour':
t.setMinutes(0)
case 'minute':
t.setSeconds(0)
case 'second':
t.setMilliseconds(0)
}
return t
}
export function endOfDate (date, unit) {
const t = buildDateVal(date)
switch (unit) {
case 'year':
t.setMonth(11)
case 'month':
t.setDate(daysInMonth(date))
case 'day':
t.setHours(23)
case 'hour':
t.setMinutes(59)
case 'minute':
t.setSeconds(59)
case 'second':
t.setMilliseconds(59)
}
return t
}
export function getMaxDate (date, ...args) {
let t = buildDateVal(date)
args.forEach(d => {
t = Math.max(t, buildDateVal(d))
})
return t
}
export function getMinDate (date, ...args) {
let t = buildDateVal(date)
args.forEach(d => {
t = Math.min(t, buildDateVal(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') {
let
t = buildDateVal(date),
sub = buildDateVal(subtract)
switch (unit) {
case 'years':
return (t.getFullYear() - sub.getFullYear())
case 'months':
return (t.getFullYear() - sub.getFullYear()) * 12 + t.getMonth() - sub.getMonth()
case 'days':
return getDiff(startOfDate(t, 'day'), startOfDate(sub, 'day'), MILLISECONDS_IN_DAY)
case 'hours':
return getDiff(startOfDate(t, 'hour'), startOfDate(sub, 'hour'), MILLISECONDS_IN_HOUR)
case 'minutes':
return getDiff(startOfDate(t, 'minute'), startOfDate(sub, 'minute'), MILLISECONDS_IN_MINUTE)
case 'seconds':
return getDiff(startOfDate(t, 'second'), startOfDate(sub, 'second'), 1000)
}
}
export function getDayOfYear (date) {
return getDateDiff(date, startOfDate(date, 'year'), 'days') + 1
}
export function inferDateFormat (example) {
if (isDate(example)) {
return 'date'
}
if (typeof example === 'number') {
return 'number'
}
return 'string'
}
export function convertDateToFormat (date, type, format) {
if (!date && date !== 0) {
return
}
switch (type) {
case 'date':
return date
case 'number':
return date.getTime()
default:
return formatDate(date, format)
}
}
export function getDateBetween (date, min, max) {
const t = buildDateVal(date)
if (min) {
const low = buildDateVal(min)
if (t < low) {
return low
}
}
if (max) {
const high = buildDateVal(max)
if (t > high) {
return high
}
}
return t
}
export function isSameDate (date, date2, unit) {
const
t = buildDateVal(date),
d = buildDateVal(date2)
if (unit === void 0) {
return t.getTime() === d.getTime()
}
switch (unit) {
case 'second':
if (t.getSeconds() !== d.getSeconds()) {
return false
}
case 'minute': // intentional fall-through
if (t.getMinutes() !== d.getMinutes()) {
return false
}
case 'hour': // intentional fall-through
if (t.getHours() !== d.getHours()) {
return false
}
case 'day': // intentional fall-through
if (t.getDate() !== d.getDate()) {
return false
}
case 'month': // intentional fall-through
if (t.getMonth() !== d.getMonth()) {
return false
}
case 'year': // intentional fall-through
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`
}
export const formatter = {
// Year: 00, 01, ..., 99
YY (date) {
return pad(date.getFullYear(), 4).substr(2)
},
// Year: 1900, 1901, ..., 2099
YYYY (date) {
return pad(date.getFullYear(), 4)
},
// Month: 1, 2, ..., 12
M (date) {
return date.getMonth() + 1
},
// Month: 01, 02, ..., 12
MM (date) {
return pad(date.getMonth() + 1)
},
// Month Short Name: Jan, Feb, ...
MMM (date, opts = {}) {
return (opts.monthNamesShort || i18n.lang.date.monthsShort)[date.getMonth()]
},
// Month Name: January, February, ...
MMMM (date, opts = {}) {
return (opts.monthNames || i18n.lang.date.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: 001, 002, ..., 366
DDDD (date) {
return pad(getDayOfYear(date), 3)
},
// Day of week: 0, 1, ..., 6
d (date) {
return date.getDay()
},
// Day of week: Su, Mo, ...
dd (date) {
return this.dddd(date).slice(0, 2)
},
// Day of week: Sun, Mon, ...
ddd (date, opts = {}) {
return (opts.dayNamesShort || i18n.lang.date.daysShort)[date.getDay()]
},
// Day of week: Sunday, Monday, ...
dddd (date, opts = {}) {
return (opts.dayNames || i18n.lang.date.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: 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()
if (hours === 0) {
return 12
}
if (hours > 12) {
return hours % 12
}
return 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 this.H(date) < 12 ? 'AM' : 'PM'
},
// Meridiem: am, pm
a (date) {
return this.H(date) < 12 ? 'am' : 'pm'
},
// Meridiem: a.m., p.m
aa (date) {
return this.H(date) < 12 ? 'a.m.' : 'p.m.'
},
// Timezone: -01:00, +00:00, ... +12:00
Z (date) {
return formatTimezone(date.getTimezoneOffset(), ':')
},
// Timezone: -0100, +0000, ... +1200
ZZ (date) {
return formatTimezone(date.getTimezoneOffset())
},
// Seconds timestamp: 512969520
X (date) {
return Math.floor(date.getTime() / 1000)
},
// Milliseconds timestamp: 512969520900
x (date) {
return date.getTime()
}
}
export function formatDate (val, mask = 'YYYY-MM-DDTHH:mm:ss.SSSZ', opts) {
if (val !== 0 && !val) {
return
}
let date = buildDateVal(val)
return mask.replace(token, function (match, text) {
if (match in formatter) {
return formatter[match](date, opts)
}
return text === void 0
? match
: text.split('\\]').join(']')
})
}
export function matchFormat (format = '') {
return format.match(token)
}
export function clone (value) {
return isDate(value) ? new Date(value.getTime()) : value
}
export default {
isValid,
buildDate,
getDayOfWeek,
getWeekOfYear,
isBetweenDates,
addToDate,
subtractFromDate,
adjustDate,
startOfDate,
endOfDate,
getMaxDate,
getMinDate,
getDateDiff,
getDayOfYear,
inferDateFormat,
convertDateToFormat,
getDateBetween,
isSameDate,
daysInMonth,
formatter,
formatDate,
matchFormat,
clone
}