UNPKG

exiftool-vendored

Version:
171 lines 5.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ExifDate = void 0; const luxon_1 = require("luxon"); const DateTime_1 = require("./DateTime"); const Maybe_1 = require("./Maybe"); const String_1 = require("./String"); const StrictExifRE = /^\d{1,4}:\d{1,2}:\d{1,2}|\d{1,4}-\d{1,2}-\d{1,2}$/; const YearMonthRE = /^\d{1,4}[:-]\d{1,2}$/; const YearOnlyRE = /^\d{1,4}$/; const LooseExifRE = /^\S+\s+\S+\s+\S+$/; /** * Encodes an ExifDate */ class ExifDate { year; month; day; rawValue; static from(exifOrIso) { if (typeof exifOrIso === "number") { return this.fromYear(exifOrIso); } return ( // in order of strictness: this.fromExifStrict(exifOrIso) ?? this.fromYearMonth(exifOrIso) ?? this.fromYear(exifOrIso) ?? this.fromISO(exifOrIso) ?? this.fromExifLoose(exifOrIso)); } static fromISO(text) { return StrictExifRE.test((0, String_1.toS)(text).trim()) ? this.fromDateTime(luxon_1.DateTime.fromISO(text), text) : undefined; } static fromPatterns(text, fmts) { if ((0, String_1.blank)(text)) return; text = (0, String_1.toS)(text).trim(); for (const fmt of fmts) { const dt = luxon_1.DateTime.fromFormat(text, fmt); if ((0, DateTime_1.validDateTime)(dt)) { return this.fromDateTime(dt, text); } } return; } // These are all formats I've seen in the wild from exiftool's output. // More iterations might make sense, like "d MMM, y" or "MMM d, y", but I // want to be constrained in what I consider a valid date to lessen the // chance of misinterpreting a given value. static fromExifStrict(text) { return StrictExifRE.test((0, String_1.toS)(text).trim()) ? this.fromPatterns(text, ["y:MM:dd", "y-MM-dd", "y:M:d"]) : undefined; } static fromYearMonth(text) { const textStr = (0, String_1.toS)(text).trim(); if (!YearMonthRE.test(textStr)) return undefined; for (const fmt of ["y:MM", "y-MM", "y:M", "y-M"]) { const dt = luxon_1.DateTime.fromFormat(textStr, fmt); if ((0, DateTime_1.validDateTime)(dt)) { return new ExifDate(dt.year, dt.month, undefined, textStr); } } return undefined; } static fromYear(yearValue) { const textStr = (0, String_1.toS)(yearValue).trim(); if (YearOnlyRE.test(textStr)) { const year = parseInt(textStr, 10); if (!isNaN(year) && year > 0 && year <= 9999) { return new ExifDate(year, undefined, undefined, textStr); } } return undefined; } static fromExifLoose(text) { // Unfortunately, Luxon parses "00" and "01" as _today_. So if we don't // three non-blank strings parts, reject. return LooseExifRE.test((0, String_1.toS)(text).trim()) ? this.fromPatterns(text, ["MMM d y", "MMMM d y"]) : undefined; } static fromEXIF(text) { return (0, Maybe_1.firstDefinedThunk)([ () => this.fromExifStrict(text), () => this.fromExifLoose(text), ]); } static fromDateTime(dt, rawValue) { return (0, DateTime_1.validDateTime)(dt) ? new ExifDate(dt.year, dt.month, dt.day, rawValue) : undefined; } constructor(year, // full year (probably 2019-ish, but maybe Japanese 30-ish). See https://ericasadun.com/2018/12/25/iso-8601-yyyy-yyyy-and-why-your-year-may-be-wrong/ month, // 1-12, (no crazy 0-11 nonsense from Date!) day, // 1-31 rawValue) { this.year = year; this.month = month; this.day = day; this.rawValue = rawValue; } toDate() { return new Date(this.year, (this.month ?? 1) - 1, this.day ?? 1); } /** * @param deltaMs defaults to 12 hours, so toMillis() is in the middle of the day. * * @return the epoch milliseconds for this day in UTC, plus `deltaMs` milliseconds. */ toMillis(deltaMs = 12 * DateTime_1.HourMs) { return this.toDate().getTime() + deltaMs; } toISOString() { return this.toString("-"); } toExifString() { return this.toString(":"); } toString(sep = "-") { if (this.month == null) { return `${this.year}`; } if (this.day == null) { return `${this.year}${sep}${(0, String_1.pad2)(this.month).join("")}`; } return `${this.year}${sep}${(0, String_1.pad2)(this.month, this.day).join(sep)}`; } toJSON() { return { _ctor: "ExifDate", year: this.year, month: this.month, day: this.day, rawValue: this.rawValue, }; } static fromJSON(json) { return new ExifDate(json.year, json.month, json.day, json.rawValue); } /** * @returns true if this is a partial date (year-only or year-month) */ isPartial() { return this.month == null || this.day == null; } /** * @returns true if this is a year-only date */ isYearOnly() { return this.month == null; } /** * @returns true if this is a year-month date (no day) */ isYearMonth() { return this.month != null && this.day == null; } /** * @returns true if this is a full date (year, month, and day) */ isFullDate() { return this.month != null && this.day != null; } } exports.ExifDate = ExifDate; //# sourceMappingURL=ExifDate.js.map