type PartialInterval = { start : Date | undefined ; end : Date | undefined ; } ; param { number } year returns export function getDstTransitions ( year ) { const result = { start : undefined , end : undefined } ; const transitions = getTzOffsetTransitions ( year ) ; for ( let i = 0 ; i < transitions . length ; i ++ ) { const t = transitions [ i ] ; const month = t . date . getMonth ( ) ; if ( month > 0 && month < 11 ) { if ( t . type === 'forward' ) result . start = t . date ; if ( t . type === 'back' && ! result . end ) result . end = t . date ; } } return result ; } function isValidDate ( date ) { return date instanceof Date && ! isNaN ( date . getTime ( ) ) ; } const MINUTE = 1000 * 60 ; function firstTickInLocalDay ( date ) { const dateNumber = date . getDate ( ) ; let prev = date ; let d = date ; do { prev = d ; d = new Date ( d . getTime ( ) - MINUTE ) ; } while ( dateNumber === d . getDate ( ) ) ; return prev ; } function fiveMinutesLater ( date ) { return new Date ( date . getTime ( ) + 5 * MINUTE ) ; } function oneDayLater ( date ) { const d = new Date ( date ) ; d . setDate ( d . getDate ( ) + 1 ) ; return firstTickInLocalDay ( d ) ; } function previousTickTimezoneOffset ( date ) { const d = new Date ( date . getTime ( ) - 1 ) ; return d . getTimezoneOffset ( ) ; } param { number } year returns export function getTzOffsetTransitions ( year ) { let date = firstTickInLocalDay ( new Date ( year , 0 , 1 ) ) ; if ( ! isValidDate ( date ) ) { throw new Error ( 'Invalid Date' ) ; } let baseTzOffset = previousTickTimezoneOffset ( date ) ; const transitions = [ ] ; do { let tzOffset = date . getTimezoneOffset ( ) ; if ( baseTzOffset !== tzOffset ) { if ( tzOffset !== previousTickTimezoneOffset ( date ) ) { transitions . push ( { date : date , type : tzOffset < baseTzOffset ? 'forward' : 'back' , before : - baseTzOffset , after : - tzOffset } ) ; baseTzOffset = tzOffset ; } else { let transitionDate = new Date ( date . getTime ( ) ) ; transitionDate . setDate ( transitionDate . getDate ( ) - 1 ) ; const dayNumber = transitionDate . getDate ( ) ; while ( isValidDate ( transitionDate ) && transitionDate . getDate ( ) === dayNumber ) { tzOffset = transitionDate . getTimezoneOffset ( ) ; if ( baseTzOffset !== tzOffset ) { transitions . push ( { date : transitionDate , type : tzOffset < baseTzOffset ? 'forward' : 'back' , before : - baseTzOffset , after : - tzOffset } ) ; baseTzOffset = tzOffset ; break ; } transitionDate = fiveMinutesLater ( transitionDate ) ; } } } date = oneDayLater ( date ) ; } while ( date . getFullYear ( ) === year ) ; return transitions ; }