Skip to content

Commit

Permalink
Fixes #151.
Browse files Browse the repository at this point in the history
- Simplify and improve datetime, date, and time parsing
- Add support for backfillTimezones and inferTimezoneFromDatestamps
- Add tests
  • Loading branch information
mceachen committed Jul 20, 2023
1 parent d298de5 commit 4b401d1
Show file tree
Hide file tree
Showing 11 changed files with 1,094 additions and 762 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
{
"typescript.tsdk": "./node_modules/typescript/lib",
"cSpell.words": [
"creat",
"Degrouped",
"exiftool's",
"modif",
"noexif"
],
"cSpell.ignoreWords": [
Expand Down
9 changes: 9 additions & 0 deletions src/DateTime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,12 @@ export function toExifString(d: DateOrTime): Maybe<string> {
return d?.toExifString?.()
}
}

export function hms(
d: DateTime,
opts?: { includeMilliseconds?: boolean }
): string {
return d.toFormat(
"HH:mm:ss" + (opts?.includeMilliseconds === true ? ".SSS" : "")
)
}
2 changes: 2 additions & 0 deletions src/DefaultExifToolOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ export const DefaultExifToolOptions: Omit<
],
includeImageDataMD5: false,
defaultVideosToUTC: true,
backfillTimezones: false, // to retain prior behavior
inferTimezoneFromDatestamps: false, // to retain prior behavior
geoTz: geoTz,
isIgnorableError: isIgnorableWarning,
})
8 changes: 8 additions & 0 deletions src/ExifDate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ import { blank, pad2, toS } from "./String"
* Encodes an ExifDate
*/
export class ExifDate {
static from(exifOrIso: string): Maybe<ExifDate> {
return (
// in order of strictness:
this.fromExifStrict(exifOrIso) ??
this.fromISO(exifOrIso) ??
this.fromExifLoose(exifOrIso)
)
}
static fromISO(text: string): Maybe<ExifDate> {
return this.fromDateTime(DateTime.fromISO(text), text)
}
Expand Down
41 changes: 40 additions & 1 deletion src/ExifDateTime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
Zone,
ZoneOptions,
} from "luxon"
import { dateTimeToExif } from "./DateTime"
import { MinuteMs, dateTimeToExif } from "./DateTime"
import { Maybe, denull } from "./Maybe"
import { omit } from "./Object"
import { blank, notBlank, toS } from "./String"
Expand All @@ -29,6 +29,18 @@ const TimeFmts = [
export class ExifDateTime {
#dt?: DateTime

static from(
exifOrIso: string,
defaultZone?: Maybe<string>
): Maybe<ExifDateTime> {
return (
// in order of strictness:
this.fromExifStrict(exifOrIso, defaultZone) ??
this.fromISO(exifOrIso, defaultZone) ??
this.fromExifLoose(exifOrIso, defaultZone)
)
}

static fromISO(
iso: string,
defaultZone?: Maybe<string>
Expand Down Expand Up @@ -381,6 +393,33 @@ export class ExifDateTime {
)
}

maybeMatchZone(
target: ExifDateTime,
maxDeltaMs = 14 * MinuteMs
): Maybe<ExifDateTime> {
if (!target.hasZone) return
return (
this.setZone(target.zone, { keepLocalTime: false })?.ifClose(
target,
maxDeltaMs
) ??
this.setZone(target.zone, { keepLocalTime: true })?.ifClose(
target,
maxDeltaMs
) ??
this.setZone("UTC", { keepLocalTime: true })?.ifClose(target, maxDeltaMs)
)
}

private ifClose(
target: ExifDateTime,
maxDeltaMs = 14 * MinuteMs
): Maybe<ExifDateTime> {
const ts = this.toMillis()
const targetTs = target.toMillis()
return Math.abs(ts - targetTs) <= maxDeltaMs ? this : undefined
}

plus(duration: DurationLike) {
let dt = this.toDateTime().plus(duration)
if (!this.hasZone) {
Expand Down
23 changes: 22 additions & 1 deletion src/ExifToolOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,31 @@ export interface ExifToolOptions
* Video file dates are assumed to be in UTC, rather than using timezone
* inference used in images. To disable this default, set this to false.
*
* @see <https://github.com/photostructure/exiftool-vendored.js/issues/113>
* @see https://github.com/photostructure/exiftool-vendored.js/issues/113
*/
defaultVideosToUTC: boolean

/**
* Should we try to backfill timezones for date-times that don't have them?
* If set to `true`, and `defaultVideosToUTC` is also `true`, we'll try
* backfilling timezones for date-times that are UTC, as well.
*
* This defaults to false to retain prior versions' behavior.
*/
backfillTimezones: boolean

/**
* We always look at TimeZone, OffsetTime, TimeZoneOffset, and GPS metadata
* to infer the timezone.
*
* If these strategies fail, can we infer a timezone from any non-UTC
* datestamp whose tag starts with "Creat" and includes an offset? (This
* means CreateDateSubSec, CreateDate, and CreationDate will be considered).
*
* This defaults to false to retain prior versions' behavior.
*/
inferTimezoneFromDatestamps: boolean

/**
* `ExifTool` has a shebang line that assumes a valid `perl` is installed at
* `/usr/bin/perl`.
Expand Down
Loading

0 comments on commit 4b401d1

Please sign in to comment.