import { Constants } from './Constants' ; import { LocaleOptions , Locales } from './Locale' ; import { Weekday } from './Weekday' ; export type Unit = 'millis' | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year' ; export type UnitRecord < T > = Record < Unit , T > ; export type Starter = ( x : Date , options ? : LocaleOptions ) => void ; export const startOf = { millis : x => x , second : startOfSecond , minute : startOfMinute , hour : startOfHour , day : startOfDay , week : startOfWeek , month : startOfMonth , quarter : startOfQuarter , year : startOfYear , } ; export type Ender = ( x : Date , options ? : LocaleOptions ) => void ; export const endOf = { millis : x => x , second : endOfSecond , minute : endOfMinute , hour : endOfHour , day : endOfDay , week : endOfWeek , month : endOfMonth , quarter : endOfQuarter , year : endOfYear , } ; export type Adder = ( x : Date , amount : number ) => void ; export const add = { millis : addMilliseconds , second : addSeconds , minute : addMinutes , hour : addHours , day : addDays , week : addWeeks , month : addMonths , quarter : addQuarters , year : addYears , } ; export type Differ = ( a : Date , b : Date ) => number ; export const diff = { millis : diffMilliseconds , second : diffSeconds , minute : diffMinutes , hour : diffHours , day : diffDays , week : diffWeeks , month : diffMonths , quarter : diffQuarters , year : diffYears , } ; /**
 * The number of milliseconds for various duration units. These are worse case
 * scenario and do not include DST changes.
 */ export const durations = { millis : 1 , second : Constants . MILLIS_IN_SECOND , minute : Constants . MILLIS_IN_MINUTE , hour : Constants . MILLIS_IN_HOUR , day : Constants . MILLIS_IN_DAY , week : Constants . MILLIS_IN_WEEK , month : Constants . MILLIS_IN_DAY * Constants . DAY_MAX , quarter : Constants . MILLIS_IN_DAY * Constants . DAY_MAX * Constants . MONTHS_IN_QUARTER , year : Constants . MILLIS_IN_DAY * Constants . DAYS_IN_YEAR } ; export function mutate ( a , mutator , options ? ) { const b = new Date ( a . getTime ( ) ) ; mutator ( b , options ) ; return b ; } export function compare ( a , b , precision = 'millis' , options = Locales . current ) { const starter = startOf [ precision ] ; const x = mutate ( a , starter , options ) ; const y = mutate ( b , starter , options ) ; return x . getTime ( ) - y . getTime ( ) ; } export function getLastDayOfMonth ( x ) { return getDaysInMonth ( x ) - x . getDate ( ) + 1 ; } export function getLastWeekspanOfYear ( x ) { const fromEnd = getDaysInYear ( x ) - getDayOfYear ( x ) ; return Math . floor ( fromEnd / Constants . DAYS_IN_WEEK ) ; } export function getWeekOfYearISO ( x , options = Locales . current ) { return getWeekISO ( mutate ( x , startOfYear ) , getDayOfYear ( x ) , options ) ; } export function getWeekOfYear ( x , options = Locales . current ) { return getWeek ( mutate ( x , startOfYear ) , getDayOfYear ( x ) , options ) ; } export function getWeekspanOfYear ( x ) { return Math . floor ( ( getDayOfYear ( x ) - 1 ) / Constants . DAYS_IN_WEEK ) ; } export function getFullWeekOfYear ( x , options = Locales . current ) { return getFullWeekOf ( mutate ( x , startOfYear ) , getDaysInYear ( x ) , options ) ; } export function getWeeksInYear ( x , options = Locales . current ) { return getWeekOfYearISO ( mutate ( x , endOfYear ) , options ) + 1 ; } export function getLastFullWeekOfYear ( x , options = Locales . current ) { const lastOfYear = mutate ( x , endOfYear ) ; const week = getWeekOfYearISO ( x , options ) ; const weekMax = getWeekOfYearISO ( lastOfYear , options ) ; const lastWeek = weekMax - week ; return getDayOfWeek ( lastOfYear , options ) === Constants . WEEKDAY_MAX ? lastWeek + 1 : lastWeek ; } export function getWeekspanOfMonth ( x ) { return Math . floor ( ( x . getDate ( ) - 1 ) / Constants . DAYS_IN_WEEK ) ; } export function getLastWeekspanOfMonth ( x ) { const fromEnd = getDaysInMonth ( x ) - x . getDate ( ) ; return Math . floor ( fromEnd / Constants . DAYS_IN_WEEK ) ; } export function getFullWeekOfMonth ( x , options = Locales . current ) { return getFullWeekOf ( mutate ( x , startOfMonth ) , x . getDate ( ) , options ) ; } export function getLastFullWeekOfMonth ( x , options = Locales . current ) { const fromEnd = getDaysInMonth ( x ) - x . getDate ( ) ; const invertedDayOfWeek = Constants . WEEKDAY_MAX - getDayOfWeek ( x , options ) ; return Math . floor ( ( fromEnd - invertedDayOfWeek + Constants . DAYS_IN_WEEK ) / Constants . DAYS_IN_WEEK ) ; } export function getWeekOfMonthISO ( x , options = Locales . current ) { return getWeekISO ( mutate ( x , startOfMonth ) , x . getDate ( ) , options ) ; } export function getWeekOfMonth ( x , options = Locales . current ) { return getWeek ( mutate ( x , startOfMonth ) , x . getDate ( ) , options ) ; } export function getWeekISO ( start , dayOfStart , options = Locales . current ) { const { firstWeekContainsDate } = options ; const dayOfWeekFirst = getDayOfWeek ( start , options ) ; const hasWeekZero = Constants . DAYS_IN_WEEK - dayOfWeekFirst < firstWeekContainsDate ; const offset = hasWeekZero ? dayOfWeekFirst - 1 : dayOfWeekFirst - 1 + Constants . DAYS_IN_WEEK ; return Math . floor ( ( dayOfStart + offset ) / Constants . DAYS_IN_WEEK ) ; } export function getWeek ( start , dayOfStart , options ) { const dayOfWeekFirst = getDayOfWeek ( start , options ) ; const offset = dayOfWeekFirst - 1 + Constants . DAYS_IN_WEEK ; return Math . floor ( ( dayOfStart + offset ) / Constants . DAYS_IN_WEEK ) ; } export function getFullWeekOf ( start , dayOfStart , options = Locales . current ) { const dayOfWeekFirst = getDayOfWeek ( start , options ) ; const hasWeekZero = dayOfWeekFirst !== Weekday . SUNDAY ; const offset = hasWeekZero ? dayOfWeekFirst - 1 : dayOfWeekFirst - 1 + Constants . DAYS_IN_WEEK ; return Math . floor ( ( dayOfStart + offset ) / Constants . DAYS_IN_WEEK ) ; } export function getDayOfWeek ( x , options = Locales . current ) { const { weekStartsOn } = options ; const day = x . getDay ( ) ; return day < weekStartsOn ? day - weekStartsOn + Constants . DAYS_IN_WEEK : day - weekStartsOn ; } export function getDayOfYear ( a ) { return Math . round ( diffDays ( a , mutate ( a , startOfYear ) ) ) + 1 ; } export function getDateOffset ( x ) { return - Math . round ( x . getTimezoneOffset ( ) / 15 ) * 15 ; } export function isDaylightSavingTime ( x ) { const offset = getDateOffset ( x ) ; return ( offset > getDateOffset ( mutate ( x , d => d . setMonth ( 0 ) ) ) || offset > getDateOffset ( mutate ( x , d => d . setMonth ( 5 ) ) ) ) ; } export function isLeapYear ( x ) { const year = x . getFullYear ( ) ; return year % 400 === 0 || ( year % 4 === 0 && year % 100 !== 0 ) ; } export function getDaysInYear ( x ) { return isLeapYear ( x ) ? 366 : 365 ; } const daysInMonth = [ [ 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 ] , [ 31 , 29 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 ] ] ; export function getDaysInMonth ( x ) { return daysInMonth [ isLeapYear ( x ) ? 1 : 0 ] [ x . getMonth ( ) ] ; } export function getAbsoluteTimestamp ( a ) { return a . getTime ( ) - getTimezoneOffsetInMilliseconds ( a ) ; } export function getTimezoneOffsetInMilliseconds ( a ) { const b = new Date ( a . getTime ( ) ) ; const offsetMinutes = b . getTimezoneOffset ( ) ; b . setSeconds ( 0 , 0 ) ; const offsetMilliseconds = b . getTime ( ) % Constants . MILLIS_IN_MINUTE ; return offsetMinutes * Constants . MILLIS_IN_MINUTE + offsetMilliseconds ; } export function getQuarter ( x ) { return Math . floor ( x . getMonth ( ) / Constants . MONTHS_IN_QUARTER ) ; } export function startOfSecond ( x ) { x . setMilliseconds ( 0 ) ; } export function startOfMinute ( x ) { x . setSeconds ( 0 , 0 ) ; } export function startOfHour ( x ) { x . setMinutes ( 0 , 0 , 0 ) ; } export function startOfDay ( x ) { x . setHours ( 0 , 0 , 0 , 0 ) ; } export function startOfWeek ( x , options = Locales . current ) { const dayOfWeek = getDayOfWeek ( x , options ) ; x . setDate ( x . getDate ( ) - dayOfWeek ) ; x . setHours ( 0 , 0 , 0 , 0 ) ; } export function startOfMonth ( x ) { x . setDate ( Constants . DAY_MIN ) ; x . setHours ( 0 , 0 , 0 , 0 ) ; } export function startOfQuarter ( x ) { const month = x . getMonth ( ) ; x . setMonth ( month - ( month % Constants . MONTHS_IN_QUARTER ) , Constants . DAY_MIN ) ; x . setHours ( 0 , 0 , 0 , 0 ) ; } export function startOfYear ( x ) { const year = x . getFullYear ( ) ; x . setTime ( 0 ) ; x . setFullYear ( year , 0 , 1 ) ; x . setHours ( 0 , 0 , 0 , 0 ) ; } export function endOfSecond ( x ) { x . setMilliseconds ( Constants . MILLIS_MAX ) ; } export function endOfMinute ( x ) { x . setSeconds ( Constants . SECOND_MAX , Constants . MILLIS_MAX ) ; } export function endOfHour ( x ) { x . setMinutes ( Constants . MINUTE_MAX , Constants . SECOND_MAX , Constants . MILLIS_MAX ) ; } export function endOfDay ( x ) { x . setHours ( Constants . HOUR_MAX , Constants . MINUTE_MAX , Constants . SECOND_MAX , Constants . MILLIS_MAX ) ; } export function endOfWeek ( x , options = Locales . current ) { const dayOfWeek = getDayOfWeek ( x , options ) ; x . setDate ( x . getDate ( ) + ( Constants . WEEKDAY_MAX - dayOfWeek ) ) ; endOfDay ( x ) ; } export function endOfMonth ( x ) { x . setFullYear ( x . getFullYear ( ) , x . getMonth ( ) + 1 , 0 ) ; endOfDay ( x ) ; } export function endOfQuarter ( x ) { const month = x . getMonth ( ) ; x . setMonth ( month - ( month % Constants . MONTHS_IN_QUARTER ) + Constants . MONTHS_IN_QUARTER , Constants . DAY_MIN ) ; endOfDay ( x ) ; } export function endOfYear ( x ) { x . setFullYear ( x . getFullYear ( ) + 1 , 0 , 0 ) ; endOfDay ( x ) ; } export function addMilliseconds ( x , amount ) { x . setTime ( x . getTime ( ) + amount ) ; } export function addSeconds ( x , amount ) { addMilliseconds ( x , amount * Constants . MILLIS_IN_SECOND ) ; } export function addMinutes ( x , amount ) { addMilliseconds ( x , amount * Constants . MILLIS_IN_MINUTE ) ; } export function addHours ( x , amount ) { addMilliseconds ( x , amount * Constants . MILLIS_IN_HOUR ) ; } export function addDays ( x , amount ) { x . setDate ( x . getDate ( ) + amount ) ; } export function addWeeks ( x , amount ) { addDays ( x , amount * Constants . DAYS_IN_WEEK ) ; } export function addMonths ( x , amount ) { const month = x . getMonth ( ) + amount ; const y = new Date ( 0 ) ; y . setFullYear ( y . getFullYear ( ) , month , 1 ) ; y . setHours ( 0 , 0 , 0 , 0 ) ; const dayMax = getDaysInMonth ( y ) ; x . setMonth ( month , Math . min ( dayMax , x . getDate ( ) ) ) ; } export function addQuarters ( x , amount ) { addMonths ( x , amount * Constants . MONTHS_IN_QUARTER ) ; } export function addYears ( x , amount ) { addMonths ( x , amount * Constants . MONTHS_IN_YEAR ) ; } export function diffMilliseconds ( a , b ) { return a . getTime ( ) - b . getTime ( ) ; } export function diffSeconds ( a , b ) { return diffMilliseconds ( a , b ) / Constants . MILLIS_IN_SECOND ; } export function diffMinutes ( a , b ) { return diffMilliseconds ( a , b ) / Constants . MILLIS_IN_MINUTE ; } export function diffHours ( a , b ) { return diffMilliseconds ( a , b ) / Constants . MILLIS_IN_HOUR ; } export function diffDays ( a , b ) { const leftTimestamp = getAbsoluteTimestamp ( a ) ; const rightTimestamp = getAbsoluteTimestamp ( b ) ; return ( leftTimestamp - rightTimestamp ) / Constants . MILLIS_IN_DAY ; } export function diffWeeks ( a , b ) { return diffDays ( a , b ) / Constants . DAYS_IN_WEEK ; } export function diffMonths ( a , b ) { const years = a . getFullYear ( ) - b . getFullYear ( ) ; const months = a . getMonth ( ) - b . getMonth ( ) ; const date = ( a . getDate ( ) - b . getDate ( ) ) / Constants . DAY_MAX ; return years * Constants . MONTHS_IN_YEAR + months + date ; } export function diffQuarters ( a , b ) { return diffMonths ( a , b ) / Constants . MONTHS_IN_QUARTER ; } export function diffYears ( a , b ) { return diffMonths ( a , b ) / Constants . MONTHS_IN_YEAR ; }