import { DateTime , ToISOTimeOptions , Zone } from "luxon" ; import { dateTimeToExif } from "./DateTime" ; import { denull , first , firstDefinedThunk , map , Maybe } from "./Maybe" ; import { blank , notBlank , toS } from "./String" ; import { offsetMinutesToZoneName , UnsetZone , UnsetZoneOffsetMinutes , } from "./Timezones" ; /**
 * Encodes an ExifDateTime with an optional tz offset in minutes.
 */ export class ExifDateTime { static fromISO ( iso , zone ? , rawValue ? ) { if ( blank ( iso ) || null != iso . match ( /^\d+$/ ) ) return undefined ; return this . fromDateTime ( DateTime . fromISO ( iso , { setZone : true , zone : zone ?? UnsetZone , } ) , rawValue ?? iso ) ; } param text param defaultZone static fromEXIF ( text , defaultZone ? ) { if ( blank ( text ) ) return undefined ; return firstDefinedThunk ( [ ( ) => this . fromExifStrict ( text , defaultZone ) , ( ) => this . fromISO ( text , defaultZone ) , ( ) => this . fromExifLoose ( text , defaultZone ) , ] ) ; } private static fromPatterns ( text , fmts ) { const s = toS ( text ) . trim ( ) ; const inputs = [ s ] ; if ( null == s . match ( /[.\d\s](utc|z)$/i ) ) { const noTza = s . replace ( / [a-z]{2,5}$/i , "" ) ; if ( noTza !== s ) inputs . push ( noTza ) ; } return first ( inputs , ( input ) => first ( fmts , ( { fmt , zone } ) => map ( DateTime . fromFormat ( input , fmt , { setZone : true , zone : zone ?? UnsetZone , } ) , ( dt ) => this . fromDateTime ( dt , s ) ) ) ) ; } static fromExifStrict ( text , zone ? ) { if ( blank ( text ) ) return undefined ; return this . fromPatterns ( text , [ { fmt : "y:M:d H:m:s.uZZ" } , { fmt : "y:M:d H:m:sZZ" } , { fmt : "y:M:d H:m:s.u'Z'" , zone : "utc" } , { fmt : "y:M:d H:m:s'Z'" , zone : "utc" } , { fmt : "y:M:d H:m:s.u" , zone } , { fmt : "y:M:d H:m:s" , zone } , { fmt : "y-M-d'T'H:m:s.uZZ" } , { fmt : "y-M-d'T'H:m:sZZ" } , { fmt : "y-M-d'T'H:m:s.u'Z'" , zone : "utc" } , { fmt : "y-M-d'T'H:m:s'Z'" , zone : "utc" } , { fmt : "y-M-d'T'H:m:s.u" , zone } , { fmt : "y-M-d'T'H:m:s" , zone } , ] ) ; } static fromExifLoose ( text , defaultZone ? ) { if ( blank ( text ) ) return undefined ; const zone = notBlank ( defaultZone ) ? defaultZone : UnsetZone ; return this . fromPatterns ( text , [ { fmt : "MMM d y H:m:sZZZ" } , { fmt : "MMM d y H:m:s" , zone } , { fmt : "MMM d y, H:m:sZZZ" } , { fmt : "MMM d y, H:m:s" , zone } , { fmt : "ccc MMM d H:m:s yZZ" } , { fmt : "ccc MMM d H:m:s y" , zone } , ] ) ; } static fromDateTime ( dt , rawValue ? ) { if ( dt == null || ! dt . isValid || dt . toMillis ( ) === 0 || dt . year === 0 || dt . year === 1 ) { return undefined ; } return new ExifDateTime ( dt . year , dt . month , dt . day , dt . hour , dt . minute , dt . second , dt . millisecond , dt . offset === UnsetZoneOffsetMinutes ? undefined : dt . offset , rawValue , dt . zone ?. name === UnsetZone . name ? undefined : dt . zoneName ) ; } constructor ( readonly year , readonly month , readonly day , readonly hour , readonly minute , readonly second , readonly millisecond ? , readonly tzoffsetMinutes ? , readonly rawValue ? , readonly zoneName ? ) { } get millis ( ) { return this . millisecond ; } get hasZone ( ) { return notBlank ( this . zone ) ; } get zone ( ) { return this . zoneName ?? offsetMinutesToZoneName ( this . tzoffsetMinutes ) ; } toDateTime ( ) { return DateTime . fromObject ( { year : this . year , month : this . month , day : this . day , hour : this . hour , minute : this . minute , second : this . second , millisecond : this . millisecond , } , { zone : this . zone , } ) ; } toDate ( ) { return this . toDateTime ( ) . toJSDate ( ) ; } toISOString ( options = { } ) { return denull ( this . toDateTime ( ) . toISO ( { suppressMilliseconds : options . suppressMilliseconds ?? this . millisecond == null , includeOffset : this . hasZone && options . includeOffset !== false , } ) ) ; } toExifString ( ) { return dateTimeToExif ( this . toDateTime ( ) ) ; } toString ( ) { return this . toISOString ( ) ; } get isValid ( ) { return this . toDateTime ( ) . isValid ; } toJSON ( ) { return { _ctor : "ExifDateTime" , year : this . year , month : this . month , day : this . day , hour : this . hour , minute : this . minute , second : this . second , millisecond : this . millisecond , tzoffsetMinutes : this . tzoffsetMinutes , rawValue : this . rawValue , zoneName : this . zoneName , } ; } static fromJSON ( json ) { return new ExifDateTime ( json . year , json . month , json . day , json . hour , json . minute , json . second , json . millisecond , json . tzoffsetMinutes , json . rawValue , json . zoneName ) ; } }