From 4a595db3f53f23032ad0db5efededf74727fe7f1 Mon Sep 17 00:00:00 2001 From: Varun Patil Date: Sun, 1 Oct 2023 09:34:48 -0700 Subject: [PATCH] metadata: fix display of dates without tz info Signed-off-by: Varun Patil --- src/components/Metadata.vue | 57 +++++++++++++++---------------- src/components/modal/EditDate.vue | 14 ++------ src/services/utils/date.ts | 15 ++++++++ 3 files changed, 45 insertions(+), 41 deletions(-) diff --git a/src/components/Metadata.vue b/src/components/Metadata.vue index fd3e64eb..72d72993 100644 --- a/src/components/Metadata.vue +++ b/src/components/Metadata.vue @@ -208,41 +208,40 @@ export default defineComponent({ /** Date taken info */ dateOriginal(): DateTime | null { - const epoch = this.exif.DateTimeEpoch || this.baseInfo.datetaken; - let date = DateTime.fromSeconds(epoch); - if (!epoch || !date.isValid) return null; + // Try to get timezone info + let dateWithTz: DateTime | null = null; + const valid = () => dateWithTz?.isValid; - // The fallback to datetaken can be eventually removed - // and then this can be discarded - if (this.exif.DateTimeEpoch) { - const tzOffset = this.exif.OffsetTimeOriginal || this.exif.OffsetTime; // e.g. -05:00 - const tzId = this.exif.LocationTZID; // e.g. America/New_York + // If we have an actual epoch, we can shift the date to the correct timezone + if (!valid() && this.exif.DateTimeEpoch) { + const date = DateTime.fromSeconds(this.exif.DateTimeEpoch); + if (date.isValid) { + const tzOffset = this.exif.OffsetTimeOriginal || this.exif.OffsetTime; // e.g. -05:00 + const tzId = this.exif.LocationTZID; // e.g. America/New_York - let dateWithTz: DateTime | undefined = undefined; + // Use timezone offset if available + if (!valid() && tzOffset) { + dateWithTz = date.setZone('UTC' + tzOffset); + } - // If no timezone info is available, we will show the local time only - // In this case, everything happens in UTC - if (!tzOffset && !tzId) { - dateWithTz = date.setZone('UTC'); - } - - // Use timezone offset if available - if (!dateWithTz?.isValid && tzOffset) { - dateWithTz = date.setZone('UTC' + tzOffset); - } - - // Fall back to tzId - if (!dateWithTz?.isValid && tzId) { - dateWithTz = date.setZone(tzId); - } - - // Use the timezone only if the date is valid - if (dateWithTz?.isValid) { - date = dateWithTz; + // Fall back to tzId + if (!valid() && tzId) { + dateWithTz = date.setZone(tzId); + } } } - return date; + // If tz info is unavailable / wrong, we will show the local time only + // In this case, use the datetaken instead, which is guaranteed to be local, shifted to UTC + if (!valid() && this.baseInfo.datetaken) { + const date = DateTime.fromSeconds(this.baseInfo.datetaken); + if (date.isValid) { + dateWithTz = date.setZone('UTC'); + } + } + + // Return only if we found a valid date + return valid() ? dateWithTz : null; }, dateOriginalStr(): string | null { diff --git a/src/components/modal/EditDate.vue b/src/components/modal/EditDate.vue index 3a18110b..2863404c 100644 --- a/src/components/modal/EditDate.vue +++ b/src/components/modal/EditDate.vue @@ -253,14 +253,14 @@ export default defineComponent({ } if (this.sortedPhotos.length === 1) { - return this.getExifFormat(this.date); + return utils.getExifDateStr(this.date); } // Interpolate date const dT = this.date.getTime(); const doT = this.origDateNewest.getTime(); const offset = ((photo.datetaken ?? 0) * 1000 || doT) - doT; - return this.getExifFormat(new Date(dT + offset * this.scaleFactor)); + return utils.getExifDateStr(new Date(dT + offset * this.scaleFactor)); }, newestChange(time = false) { @@ -292,16 +292,6 @@ export default defineComponent({ this.oldestDirty = true; }, - getExifFormat(date: Date) { - const year = date.getUTCFullYear().toString().padStart(4, '0'); - const month = (date.getUTCMonth() + 1).toString().padStart(2, '0'); - const day = date.getUTCDate().toString().padStart(2, '0'); - const hour = date.getUTCHours().toString().padStart(2, '0'); - const minute = date.getUTCMinutes().toString().padStart(2, '0'); - const second = date.getUTCSeconds().toString().padStart(2, '0'); - return `${year}:${month}:${day} ${hour}:${minute}:${second}`; - }, - makeDate(yearS: string, monthS: string, dayS: string, hourS: string, minuteS: string, secondS: string) { const date = new Date(); const year = parseInt(yearS, 10); diff --git a/src/services/utils/date.ts b/src/services/utils/date.ts index e5429a4a..d84e06a3 100644 --- a/src/services/utils/date.ts +++ b/src/services/utils/date.ts @@ -54,6 +54,21 @@ export function getMonthDateStr(date: Date) { }); } +/** + * Get the EXIF date string from a datetaken object + * @param date The datetaken value from photo metadata (UTC relative date) + * @returns YYYY:MM:DD HH:MM:SS + */ +export function getExifDateStr(date: Date) { + const year = date.getUTCFullYear().toString().padStart(4, '0'); + const month = (date.getUTCMonth() + 1).toString().padStart(2, '0'); + const day = date.getUTCDate().toString().padStart(2, '0'); + const hour = date.getUTCHours().toString().padStart(2, '0'); + const minute = date.getUTCMinutes().toString().padStart(2, '0'); + const second = date.getUTCSeconds().toString().padStart(2, '0'); + return `${year}:${month}:${day} ${hour}:${minute}:${second}`; +} + /** Get text like "5 years ago" from a date */ export function getFromNowStr(date: Date) { // Get fromNow in correct locale