'use strict' ; import type TickPositionsArray from './Axis/TickPositionsArray' ; import type TimeTicksInfoObject from './Axis/TimeTicksInfoObject' ; import H from './Globals.js' ; const { win } = H ; import U from './Utilities.js' ; const { defined , error , extend , isObject , merge , objectEach , pad , pick , splat , timeUnits } = U ; declare module './Options' { interface Options { time ? : Time . TimeOptions ; } } declare module './Axis/TickPositionsArray' { interface TickPositionsArray { info ? : TimeTicksInfoObject ; } } const hasNewSafariBug = H . isSafari && win . Intl && win . Intl . DateTimeFormat . prototype . formatRange ; const hasOldSafariBug = H . isSafari && win . Intl && ! win . Intl . DateTimeFormat . prototype . formatRange ; /**
 * The Time class. Time settings are applied in general for each page using
 * `Highcharts.setOptions`, or individually for each Chart item through the
 * [time](https://api.highcharts.com/highcharts/time) options set.
 *
 * The Time object is available from  Highcharts . Chart ,
 * which refers to  `Highcharts.time` if no individual time settings are
 * applied.
 *
 *  example since class name param { Highcharts . TimeOptions } options class Time { public constructor ( options ) { function param { number } timestamp return { number } this . getTimezoneOffset = this . timezoneOffsetFunction ( ) ; this . update ( options ) ; } public options : Time . TimeOptions = { } ; public timezoneOffset ? : number ; public useUTC : boolean = false ; public variableTimezone : boolean = false ; public Date : typeof Date = win . Date ; public getTimezoneOffset : ReturnType < Time [ 'timezoneOffsetFunction' ] > ; typedef { "Date" | "Day" | "FullYear" | "Hours" | "Milliseconds" | "Minutes" | "Month" | "Seconds" } Highcharts . TimeUnitValue function param { Highcharts . TimeUnitValue } unit param { Date } date return { number } public get ( unit , date ) { if ( this . variableTimezone || this . timezoneOffset ) { const realMs = date . getTime ( ) ; const ms = realMs - this . getTimezoneOffset ( date ) ; date . setTime ( ms ) ; const ret = ( date as any ) [ 'getUTC' + unit ] ( ) ; date . setTime ( realMs ) ; return ret ; } if ( this . useUTC ) { return ( date as any ) [ 'getUTC' + unit ] ( ) ; } return ( date as any ) [ 'get' + unit ] ( ) ; } function param { Highcharts . TimeUnitValue } unit param { Date } date param { number } value return { number } public set ( unit , date , value ) { if ( this . variableTimezone || this . timezoneOffset ) { if ( unit === 'Milliseconds' || unit === 'Seconds' || ( unit === 'Minutes' && this . getTimezoneOffset ( date ) % 3600000 === 0 ) ) { return ( date as any ) [ 'setUTC' + unit ] ( value ) ; } const offset = this . getTimezoneOffset ( date ) ; let ms = date . getTime ( ) - offset ; date . setTime ( ms ) ; ( date as any ) [ 'setUTC' + unit ] ( value ) ; const newOffset = this . getTimezoneOffset ( date ) ; ms = date . getTime ( ) + newOffset ; return date . setTime ( ms ) ; } if ( this . useUTC || ( hasNewSafariBug && unit === 'FullYear' ) ) { return ( date as any ) [ 'setUTC' + unit ] ( value ) ; } return ( date as any ) [ 'set' + unit ] ( value ) ; } private function param { Highcharts . TimeOptions } options public update ( options ) { const useUTC = pick ( options && options . useUTC , true ) as boolean , time = this ; this . options = options = merge ( true , this . options || { } , options ) ; this . Date = options . Date || win . Date || Date ; this . useUTC = useUTC ; this . timezoneOffset = ( useUTC && options . timezoneOffset ) as any ; this . getTimezoneOffset = this . timezoneOffsetFunction ( ) ; this . variableTimezone = useUTC && ! ! ( options . getTimezoneOffset || options . timezone ) ; } function param { number } year param { number } month param { number } date param { number } hours param { number } minutes param { number } seconds return { number } public makeTime ( year , month , date ? , hours ? , minutes ? , seconds ? ) { let d , offset , newOffset ; if ( this . useUTC ) { d = this . Date . UTC . apply ( 0 , arguments ) ; offset = this . getTimezoneOffset ( d ) ; d += offset ; newOffset = this . getTimezoneOffset ( d ) ; if ( offset !== newOffset ) { d += newOffset - offset ; } else if ( offset - 36e5 === this . getTimezoneOffset ( d - 36e5 ) && ! hasOldSafariBug ) { d -= 36e5 ; } } else { d = new this . Date ( year , month , pick ( date , 1 ) , pick ( hours , 0 ) , pick ( minutes , 0 ) , pick ( seconds , 0 ) ) . getTime ( ) ; } return d ; } private function return { Function } public timezoneOffsetFunction ( ) { const time = this , options = this . options , getTimezoneOffset = options . getTimezoneOffset , moment = options . moment || ( win as any ) . moment ; if ( ! this . useUTC ) { return function ( timestamp ) : number { return new Date ( timestamp . toString ( ) ) . getTimezoneOffset ( ) * 60000 ; } ; } if ( options . timezone ) { if ( ! moment ) { error ( 25 ) ; } else { return function ( timestamp ) : number { return - moment . tz ( timestamp , options . timezone ) . utcOffset ( ) * 60000 ; } ; } } if ( this . useUTC && getTimezoneOffset ) { return function ( timestamp ) : number { return getTimezoneOffset ( timestamp . valueOf ( ) ) * 60000 ; } ; } return function ( ) : number { return ( time . timezoneOffset || 0 ) * 60000 ; } ; } /**
     * Formats a JavaScript date timestamp (milliseconds since Jan 1st 1970)
     * into a human readable date string. The available format keys are listed
     * below. Additional formats can be given in the
     *  Highcharts . dateFormats hook.
     *
     * Supported format keys:
     * - `%a`: Short weekday, like 'Mon'
     * - `%A`: Long weekday, like 'Monday'
     * - `%d`: Two digit day of the month, 01 to 31
     * - `%e`: Day of the month, 1 through 31
     * - `%w`: Day of the week, 0 through 6
     * - `%b`: Short month, like 'Jan'
     * - `%B`: Long month, like 'January'
     * - `%m`: Two digit month number, 01 through 12
     * - `%y`: Two digits year, like 09 for 2009
     * - `%Y`: Four digits year, like 2009
     * - `%H`: Two digits hours in 24h format, 00 through 23
     * - `%k`: Hours in 24h format, 0 through 23
     * - `%I`: Two digits hours in 12h format, 00 through 11
     * - `%l`: Hours in 12h format, 1 through 12
     * - `%M`: Two digits minutes, 00 through 59
     * - `%p`: Upper case AM or PM
     * - `%P`: Lower case AM or PM
     * - `%S`: Two digits seconds, 00 through 59
     * - `%L`: Milliseconds (naming from Ruby)
     *
     *  example function param { string } format param { number } timestamp param { boolean } capitalize return { string } public dateFormat ( format , timestamp ? , capitalize ? ) { if ( ! defined ( timestamp ) || isNaN ( timestamp ) ) { return ( H . defaultOptions . lang && H . defaultOptions . lang . invalidDate || '' ) ; } format = pick ( format , '%Y-%m-%d %H:%M:%S' ) ; const time = this , date = new this . Date ( timestamp as any ) , hours = this . get ( 'Hours' , date ) , day = this . get ( 'Day' , date ) , dayOfMonth = this . get ( 'Date' , date ) , month = this . get ( 'Month' , date ) , fullYear = this . get ( 'FullYear' , date ) , lang = H . defaultOptions . lang , langWeekdays = ( lang && lang . weekdays as any ) , shortWeekdays = ( lang && lang . shortWeekdays ) , replacements = extend ( { a : shortWeekdays ? shortWeekdays [ day ] : langWeekdays [ day ] . substr ( 0 , 3 ) , A : langWeekdays [ day ] , d : pad ( dayOfMonth ) , e : pad ( dayOfMonth , 2 , ' ' ) , w : day , b : lang . shortMonths [ month ] , B : lang . months [ month ] , m : pad ( month + 1 ) , o : month + 1 , y : fullYear . toString ( ) . substr ( 2 , 2 ) , Y : fullYear , H : pad ( hours ) , k : hours , I : pad ( ( hours % 12 ) || 12 ) , l : ( hours % 12 ) || 12 , M : pad ( this . get ( 'Minutes' , date ) ) , p : hours < 12 ? 'AM' : 'PM' , P : hours < 12 ? 'am' : 'pm' , S : pad ( date . getSeconds ( ) ) , L : pad ( Math . floor ( ( timestamp as any ) % 1000 ) , 3 ) } , H . dateFormats ) ; objectEach ( replacements , function ( val , key ) : void { while ( format . indexOf ( '%' + key ) !== - 1 ) { format = format . replace ( '%' + key , typeof val === 'function' ? val . call ( time , timestamp ) : val ) ; } } ) ; return capitalize ? ( format . substr ( 0 , 1 ) . toUpperCase ( ) + format . substr ( 1 ) ) : format ; } private param { string | Array < T > | Highcharts . Dictionary < T > } f return { Highcharts . Dictionary < T > } public resolveDTLFormat < T > ( f ) { if ( ! isObject ( f , true ) ) { f = splat ( f ) ; return { main : f [ 0 ] , from : f [ 1 ] , to : f [ 2 ] } ; } return f as any ; } function param { Highcharts . TimeNormalizedObject } normalizedInterval param { number } min param { number } max param { number } startOfWeek return { Highcharts . AxisTickPositionsArray } public getTimeTicks ( normalizedInterval , min ? , max ? , startOfWeek ? ) { const time = this , Date = time . Date , tickPositions = [ ] as TickPositionsArray , higherRanks = { } as Record < string , string > , minDate = new Date ( min as any ) , interval = normalizedInterval . unitRange , count = normalizedInterval . count || 1 ; let i , minYear , variableDayLength , minDay ; startOfWeek = pick ( startOfWeek , 1 ) ; if ( defined ( min ) ) { time . set ( 'Milliseconds' , minDate , interval >= timeUnits . second ? 0 : count * Math . floor ( time . get ( 'Milliseconds' , minDate ) / count ) ) ; if ( interval >= timeUnits . second ) { time . set ( 'Seconds' , minDate , interval >= timeUnits . minute ? 0 : count * Math . floor ( time . get ( 'Seconds' , minDate ) / count ) ) ; } if ( interval >= timeUnits . minute ) { time . set ( 'Minutes' , minDate , interval >= timeUnits . hour ? 0 : count * Math . floor ( time . get ( 'Minutes' , minDate ) / count ) ) ; } if ( interval >= timeUnits . hour ) { time . set ( 'Hours' , minDate , interval >= timeUnits . day ? 0 : count * Math . floor ( time . get ( 'Hours' , minDate ) / count ) ) ; } if ( interval >= timeUnits . day ) { time . set ( 'Date' , minDate , interval >= timeUnits . month ? 1 : Math . max ( 1 , count * Math . floor ( time . get ( 'Date' , minDate ) / count ) ) ) ; } if ( interval >= timeUnits . month ) { time . set ( 'Month' , minDate , interval >= timeUnits . year ? 0 : count * Math . floor ( time . get ( 'Month' , minDate ) / count ) ) ; minYear = time . get ( 'FullYear' , minDate ) ; } if ( interval >= timeUnits . year ) { minYear -= minYear % count ; time . set ( 'FullYear' , minDate , minYear ) ; } if ( interval === timeUnits . week ) { minDay = time . get ( 'Day' , minDate ) ; time . set ( 'Date' , minDate , ( time . get ( 'Date' , minDate ) - minDay + startOfWeek + ( minDay < startOfWeek ? - 7 : 0 ) ) ) ; } minYear = time . get ( 'FullYear' , minDate ) ; const minMonth = time . get ( 'Month' , minDate ) , minDateDate = time . get ( 'Date' , minDate ) , minHours = time . get ( 'Hours' , minDate ) ; min = minDate . getTime ( ) ; if ( ( time . variableTimezone || ! time . useUTC ) && defined ( max ) ) { variableDayLength = ( max - min > 4 * timeUnits . month || time . getTimezoneOffset ( min ) !== time . getTimezoneOffset ( max ) ) ; } let t = minDate . getTime ( ) ; i = 1 ; while ( t < ( max as any ) ) { tickPositions . push ( t ) ; if ( interval === timeUnits . year ) { t = time . makeTime ( minYear + i * count , 0 ) ; } else if ( interval === timeUnits . month ) { t = time . makeTime ( minYear , minMonth + i * count ) ; } else if ( variableDayLength && ( interval === timeUnits . day || interval === timeUnits . week ) ) { t = time . makeTime ( minYear , minMonth , minDateDate + i * count * ( interval === timeUnits . day ? 1 : 7 ) ) ; } else if ( variableDayLength && interval === timeUnits . hour && count > 1 ) { t = time . makeTime ( minYear , minMonth , minDateDate , minHours + i * count ) ; } else { t += interval * count ; } i ++ ; } tickPositions . push ( t ) ; if ( interval <= timeUnits . hour && tickPositions . length < 10000 ) { tickPositions . forEach ( function ( t ) : void { if ( t % 1800000 === 0 && time . dateFormat ( '%H%M%S%L' , t ) === '000000000' ) { higherRanks [ t ] = 'day' ; } } ) ; } } tickPositions . info = extend < Time . TimeNormalizedObject | TimeTicksInfoObject > ( normalizedInterval , { higherRanks , totalRange : interval * count } ) as TimeTicksInfoObject ; return tickPositions ; } private function param { number } range param { number } timestamp param { number } startOfWeek param { Highcharts . Dictionary < string > } dateTimeLabelFormats return { string } public getDateFormat ( range , timestamp , startOfWeek , dateTimeLabelFormats ) { const dateStr = this . dateFormat ( '%m-%d %H:%M:%S.%L' , timestamp ) , blank = '01-01 00:00:00.000' , strpos = { millisecond : 15 , second : 12 , minute : 9 , hour : 6 , day : 3 } as Record < string , number > ; let format , n , lastN = 'millisecond' ; for ( n in timeUnits ) { if ( range === timeUnits . week && + this . dateFormat ( '%w' , timestamp ) === startOfWeek && dateStr . substr ( 6 ) === blank . substr ( 6 ) ) { n = 'week' ; break ; } if ( timeUnits [ n ] > range ) { n = lastN ; break ; } if ( strpos [ n ] && dateStr . substr ( strpos [ n ] ) !== blank . substr ( strpos [ n ] ) ) { break ; } if ( n !== 'week' ) { lastN = n ; } } if ( n ) { format = this . resolveDTLFormat ( dateTimeLabelFormats [ n ] ) . main as any ; } return format ; } } namespace Time { export interface TimeOptions { Date ? : any ; getTimezoneOffset ? : Function ; timezone ? : string ; timezoneOffset ? : number ; useUTC ? : boolean ; moment ? : any ; } export interface TimeFormatCallbackFunction { ( timestamp ) : string ; } export interface TimeNormalizedObject { count : number ; unitRange : number ; } export type TimeUnitValue = ( 'Date' | 'Day' | 'FullYear' | 'Hours' | 'Milliseconds' | 'Minutes' | 'Month' | 'Seconds' ) ; } export default Time ; interface name type { number } name type { number } callback Highcharts . TimeFormatCallbackFunction param { number } timestamp return { string } interface extends global . Array < number > name type { Highcharts . TimeTicksInfoObject | undefined } callback Highcharts . TimezoneOffsetCallbackFunction param { number } timestamp return { number } type { Function } since apioption '' ;