const millisecond = 1 , second = 1000 * millisecond , minute = 60 * second , hour = 60 * minute , day = 24 * hour , week = 7 * day ; const microsecond = millisecond / 1000 , nanosecond = microsecond / 1000 ; const unitMap = { "ns" : nanosecond , "us" : microsecond , "µs" : microsecond , "μs" : microsecond , "ms" : millisecond , "s" : second , "m" : minute , "h" : hour , "d" : day , "w" : week } ; export type DurationLike = Duration | string | number ; export type DateLike = Date | number ; export class Duration { private _milliseconds : number ; constructor ( value ? ) { if ( value instanceof Duration ) { this . _milliseconds = value . valueOf ( ) ; return ; } switch ( typeof value ) { case "number" : if ( ! isFinite ( value ) ) { throw new Error ( `invalid duration: ${ value }` ) ; } this . _milliseconds = value ; break ; case "string" : this . _milliseconds = Duration . parse ( value ) . valueOf ( ) ; break ; case "undefined" : this . _milliseconds = 0 ; break ; default : throw new Error ( `invalid duration: ${ value }` ) ; } } static millisecond = new Duration ( millisecond ) ; static second = new Duration ( second ) ; static minute = new Duration ( minute ) ; static hour = new Duration ( hour ) ; static day = new Duration ( day ) ; static week = new Duration ( week ) ; static microseconds ( us ) { let ms = Math . floor ( us / 1000 ) ; return new Duration ( ms ) ; } static nanoseconds = function ( ns ) : Duration { let ms = Math . floor ( ns / 1000000 ) ; return new Duration ( ms ) ; } ; static milliseconds ( milliseconds ) { return new Duration ( milliseconds * millisecond ) ; } static seconds ( seconds ) { return new Duration ( seconds * second ) ; } static minutes ( minutes ) { return new Duration ( minutes * minute ) ; } static hours ( hours ) { return new Duration ( hours * hour ) ; } static days ( days ) { return new Duration ( days * day ) ; } static weeks ( weeks ) { return new Duration ( weeks * week ) ; } nanoseconds ( ) { return Math . floor ( this . _milliseconds / nanosecond ) ; } microseconds ( ) { return Math . floor ( this . _milliseconds / microsecond ) ; } milliseconds ( ) { return this . _milliseconds ; } seconds ( ) { return Math . floor ( this . _milliseconds / second ) ; } minutes ( ) { return Math . floor ( this . _milliseconds / minute ) ; } hours ( ) { return Math . floor ( this . _milliseconds / hour ) ; } days ( ) { return Math . floor ( this . _milliseconds / day ) ; } weeks ( ) { return Math . floor ( this . _milliseconds / week ) ; } toString ( ) { let str = "" , milliseconds = Math . abs ( this . _milliseconds ) , sign = this . _milliseconds < 0 ? "-" : "" ; if ( milliseconds === 0 ) { return "0" ; } let hours = Math . floor ( milliseconds / hour ) ; if ( hours !== 0 ) { milliseconds -= hour * hours ; str += hours . toString ( ) + "h" ; } let minutes = Math . floor ( milliseconds / minute ) ; if ( minutes !== 0 ) { milliseconds -= minute * minutes ; str += minutes . toString ( ) + "m" ; } let seconds = Math . floor ( milliseconds / second ) ; if ( seconds !== 0 ) { milliseconds -= second * seconds ; str += seconds . toString ( ) + "s" ; } if ( milliseconds !== 0 ) { str += milliseconds . toString ( ) + "ms" ; } return sign + str ; } valueOf ( ) { return this . _milliseconds ; } abs ( ) { return new Duration ( Math . abs ( this . _milliseconds ) ) ; } static parse ( duration ) { if ( duration === "0" || duration === "+0" || duration === "-0" ) { return new Duration ( 0 ) ; } let regex = /([\-\+\d\.]+)([a-zµμ]+)/g , total = 0 , count = 0 , sign = duration [ 0 ] === '-' ? - 1 : 1 , value ; while ( true ) { let match = regex . exec ( duration ) ; if ( ! match ) { break ; } let unit = match [ 2 ] as string ; value = Math . abs ( parseFloat ( match [ 1 ] ) ) ; count ++ ; if ( isNaN ( value ) ) { throw new Error ( `invalid duration: "${ duration }"` ) ; } if ( typeof unitMap [ unit ] === "undefined" ) { throw new Error ( `invalid duration: "${ duration }": bad unit ${ unit }` ) ; } total += value * unitMap [ unit ] ; } if ( count === 0 ) { throw new Error ( `invalid duration: "${ duration }"` ) ; } return new Duration ( Math . floor ( total ) * sign ) ; } static valueOf ( duration ) { return new Duration ( duration ) . valueOf ( ) ; } truncate ( duration ) { let ms = Duration . valueOf ( duration ) ; return new Duration ( ms * Math . round ( this . _milliseconds / ms ) ) ; } isGreaterThan ( duration ) { return this . valueOf ( ) > Duration . valueOf ( duration ) ; } isLessThan ( duration ) { return this . valueOf ( ) < Duration . valueOf ( duration ) ; } isEqualTo ( duration ) { return this . valueOf ( ) === Duration . valueOf ( duration ) ; } after ( date ) { return new Date ( date . valueOf ( ) + this . _milliseconds ) ; } static since ( date ) { return new Duration ( new Date ( ) . valueOf ( ) - date . valueOf ( ) ) ; } static until ( date ) { return new Duration ( date . valueOf ( ) - new Date ( ) . valueOf ( ) ) ; } static between ( a , b ) { return new Duration ( b . valueOf ( ) - a . valueOf ( ) ) ; } static add ( a , b ) { return new Duration ( Duration . valueOf ( a ) + Duration . valueOf ( b ) ) ; } static subtract ( a , b ) { return new Duration ( Duration . valueOf ( a ) - Duration . valueOf ( b ) ) ; } static multiply ( a , b ) { return new Duration ( Duration . valueOf ( a ) * Duration . valueOf ( b ) ) ; } static divide ( a , b ) { return Duration . valueOf ( a ) / Duration . valueOf ( b ) ; } } export default Duration ;