Skip to content

Files with no zone in their metadata are shown in UTC instead of TZ #1147

Description

@TommyChums

Description

When a file's metadata doesn't say what time zone it was taken in, Gallery shows it in UTC, even when the server's TZ is set. West of UTC, that moves evening photos to the next day in the timeline and the viewer.

Two paths in getDates() in server/src/services/metadata.service.ts do this:

  1. Files with no date in their metadata, such as WhatsApp images and videos (WhatsApp strips EXIF). getDates() falls back to the earliest file timestamp. earliestDate comes from DateTime.fromMillis(), so it is already in the server's zone. But dateTimeOriginal = localDateTime = earliestDate then stores it as a plain instant, so the local time is lost. timeZone stays null, and the web and mobile apps show the UTC time.
  2. Videos with no zone in their metadata, such as Android camera videos recorded with location off. exiftool reads QuickTime times as UTC (defaultVideosToUTC: true) and reports zone: "UTC" with zoneSource: "defaultVideosToUTC". getDates() takes that as the real zone, so the video is shown in UTC.

The environment variable docs say TZ "is used by exiftool as a fallback in case the timezone cannot be determined from the image metadata". Neither path uses it.

This is separate from #607 and #608, which recover the zone for photos that have a capture time but no offset. Neither case above reaches that code.

To reproduce

  1. Set TZ=America/Port_of_Spain (UTC−4) on the server.
  2. From the Android app, upload a WhatsApp image that arrived after 20:00 local time. IMG-20260924-WA0016.jpg arrived at 21:07 on 24 Sep. It shows as Fri, Sep 25, 2026 • 1:07 AM GMT+00:00, and the timeline puts it under 25 Sep.
  3. Upload a camera video recorded with location off. 20260924_165743.mp4 was recorded at 16:57 local time and shows as 20:57 GMT+00:00.

Expected

When the file doesn't carry a zone, use the server's TZ, as documented. The image should show 24 Sep, 9:07 PM GMT−04:00, and the video 4:57 PM GMT−04:00.

Gallery version

v5.7.0 (server and Android app)

Platform

Server

Logs or screenshots

# asset_exif / asset rows after upload, TZ=America/Port_of_Spain
originalFileName        | timeZone | localDateTime (UTC) | dateTimeOriginal
IMG-20260924-WA0016.jpg | (null)   | 2026-09-25 01:07:27 | 2026-09-25 01:07:27+00
VID-20260924-WA0025.mp4 | UTC      | 2026-09-25 00:49:43 | 2026-09-25 00:49:43+00
20260924_165743.mp4     | UTC      | 2026-09-24 20:57:57 | 2026-09-24 20:57:57+00

# Luxon inside the server container: the fallback already has the right local time
$ node -e "... DateTime.fromMillis(Date.parse('2026-09-25T01:07:27Z')).toISO()"
2026-09-24T21:07:27.000-04:00

Additional context

A possible fix in getDates():

// exiftool assumed UTC only to parse the QuickTime timestamp. The instant is
// right but the zone is unknown, so show it in the server's zone.
if (exifTags.zoneSource === 'defaultVideosToUTC') {
  timeZone = DateTime.local().zoneName;
}

// ...

if (!localDateTime || !dateTimeOriginal) {
  const earliestDate = DateTime.fromMillis(/* unchanged */); // already in the server's zone
  dateTimeOriginal = earliestDate;
  localDateTime = earliestDate.setZone('UTC', { keepLocalTime: true });
  timeZone ??= earliestDate.zoneName;
}

When TZ is unset the server's zone is UTC, so those installs see the same times as today.

Workaround for assets already affected: select them, choose Edit date and time, turn on Edit date and time by offset, leave the offset at 0, and pick the correct time zone. That keeps the instant and fixes the displayed day.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions