[BUG] Files without exif offset_time attribute are assumed to contain utc date/time instead of local timezone #1071

Closed
opened 2026-02-05 00:20:33 +03:00 by OVERLORD · 7 comments
Owner

Originally created by @JayBigGuy10 on GitHub (Jul 8, 2023).

The bug

If I upload a photo taken by a device which stores the local timezone time/date directly into the exif date taken fields, and doesn't store a offset_time, the server incorrectly applies an offset.

For example a photo that I took when it was 2022/08/02 16:18 in new Zealand, appears on the server as if it was taken 13 hours later because the server believes the 2022/08/02 16:18 datetime to be UTC(+0) which needs offsetting, not the NZDST(+13) that it actually is

I have looked into various photos exif dumps and this happens with the Samsung Galaxy S9 and my OnePlus Nord (Android 10) photos from my hiking group which store local timezone, but not with the Samsung S10+, Samsung S22+ and Olympus TG-6 camera which store UTC/offset.

I guess the server will have to somehow assume that for these cases that the photos were taken in the servers current TZ?

The OS that Immich Server is running on

Docker Desktop (WSL Backend) For Windows 10

Version of Immich Server

v1.66.1

Version of Immich Mobile App

1.66.0 Build 89

Platform with the issue

  • Server
  • Web
  • Mobile

Your docker-compose.yml content

version: "3.8"

services:
  immich-server:
    container_name: immich_server
    image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
    command: [ "start.sh", "immich" ]
    volumes:
      - ${UPLOAD_LOCATION}:/usr/src/app/upload
      - C:\docker\immich\read-only:/mnt/media/read-only
    env_file:
      - .env
    depends_on:
      - redis
      - database
      - typesense
    restart: always

  immich-microservices:
    container_name: immich_microservices
    image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
    command: [ "start.sh", "microservices" ]
    volumes:
      - ${UPLOAD_LOCATION}:/usr/src/app/upload
      - C:\docker\immich\read-only:/mnt/media/read-only
    env_file:
      - .env
    depends_on:
      - redis
      - database
      - typesense
    restart: always

  immich-machine-learning:
    container_name: immich_machine_learning
    image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
    volumes:
      - model-cache:/cache
    env_file:
      - .env
    restart: always

  immich-web:
    container_name: immich_web
    image: ghcr.io/immich-app/immich-web:${IMMICH_VERSION:-release}
    env_file:
      - .env
    restart: always

  typesense:
    container_name: immich_typesense
    image: typesense/typesense:0.24.1@sha256:9bcff2b829f12074426ca044b56160ca9d777a0c488303469143dd9f8259d4dd
    environment:
      - TYPESENSE_API_KEY=${TYPESENSE_API_KEY}
      - TYPESENSE_DATA_DIR=/data
    logging:
      driver: none
    volumes:
      - tsdata:/data
    restart: always

  redis:
    container_name: immich_redis
    image: redis:6.2-alpine@sha256:70a7a5b641117670beae0d80658430853896b5ef269ccf00d1827427e3263fa3
    restart: always

  database:
    container_name: immich_postgres
    image: postgres:14-alpine@sha256:28407a9961e76f2d285dc6991e8e48893503cc3836a4755bbc2d40bcc272a441
    env_file:
      - .env
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_DB: ${DB_DATABASE_NAME}
      PG_DATA: /var/lib/postgresql/data
    volumes:
      - pgdata:/var/lib/postgresql/data
    restart: always

  immich-proxy:
    container_name: immich_proxy
    image: ghcr.io/immich-app/immich-proxy:${IMMICH_VERSION:-release}
    environment:
      # Make sure these values get passed through from the env file
      - IMMICH_SERVER_URL
      - IMMICH_WEB_URL
    ports:
      - 2283:8080
    depends_on:
      - immich-server
      - immich-web
    restart: always

volumes:
  pgdata:
  model-cache:
  tsdata:

Your .env content

DB_HOSTNAME=immich_postgres
DB_USERNAME=postgres
DB_PASSWORD=postgres
DB_DATABASE_NAME=immich
REDIS_HOSTNAME=immich_redis
UPLOAD_LOCATION=C:\docker\immich\content
TYPESENSE_API_KEY=some-random-text
PUBLIC_LOGIN_PAGE_MESSAGE=
IMMICH_WEB_URL=http://immich-web:3000
IMMICH_SERVER_URL=http://immich-server:3001
IMMICH_MACHINE_LEARNING_URL=http://immich-machine-learning:3003

Reproduction steps

1. Upload a photo taken by a device which stores the local timezone time/date into the exif date taken fields
2. Once the metadata is extracted, view the date/time of the photo

Additional information

Running the storage migration does nothing

applies to read-only image library as well as uploaded images from the web

Originally created by @JayBigGuy10 on GitHub (Jul 8, 2023). ### The bug If I upload a photo taken by a device which stores the local timezone time/date directly into the exif date taken fields, and doesn't store a offset_time, the server incorrectly applies an offset. For example a photo that I took when it was 2022/08/02 16:18 in new Zealand, appears on the server as if it was taken 13 hours later because the server believes the 2022/08/02 16:18 datetime to be UTC(+0) which needs offsetting, not the NZDST(+13) that it actually is I have looked into various photos exif dumps and this happens with the Samsung Galaxy S9 and my OnePlus Nord (Android 10) photos from my hiking group which store local timezone, but not with the Samsung S10+, Samsung S22+ and Olympus TG-6 camera which store UTC/offset. I guess the server will have to somehow assume that for these cases that the photos were taken in the servers current TZ? ### The OS that Immich Server is running on Docker Desktop (WSL Backend) For Windows 10 ### Version of Immich Server v1.66.1 ### Version of Immich Mobile App 1.66.0 Build 89 ### Platform with the issue - [X] Server - [X] Web - [X] Mobile ### Your docker-compose.yml content ```YAML version: "3.8" services: immich-server: container_name: immich_server image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release} command: [ "start.sh", "immich" ] volumes: - ${UPLOAD_LOCATION}:/usr/src/app/upload - C:\docker\immich\read-only:/mnt/media/read-only env_file: - .env depends_on: - redis - database - typesense restart: always immich-microservices: container_name: immich_microservices image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release} command: [ "start.sh", "microservices" ] volumes: - ${UPLOAD_LOCATION}:/usr/src/app/upload - C:\docker\immich\read-only:/mnt/media/read-only env_file: - .env depends_on: - redis - database - typesense restart: always immich-machine-learning: container_name: immich_machine_learning image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release} volumes: - model-cache:/cache env_file: - .env restart: always immich-web: container_name: immich_web image: ghcr.io/immich-app/immich-web:${IMMICH_VERSION:-release} env_file: - .env restart: always typesense: container_name: immich_typesense image: typesense/typesense:0.24.1@sha256:9bcff2b829f12074426ca044b56160ca9d777a0c488303469143dd9f8259d4dd environment: - TYPESENSE_API_KEY=${TYPESENSE_API_KEY} - TYPESENSE_DATA_DIR=/data logging: driver: none volumes: - tsdata:/data restart: always redis: container_name: immich_redis image: redis:6.2-alpine@sha256:70a7a5b641117670beae0d80658430853896b5ef269ccf00d1827427e3263fa3 restart: always database: container_name: immich_postgres image: postgres:14-alpine@sha256:28407a9961e76f2d285dc6991e8e48893503cc3836a4755bbc2d40bcc272a441 env_file: - .env environment: POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_USER: ${DB_USERNAME} POSTGRES_DB: ${DB_DATABASE_NAME} PG_DATA: /var/lib/postgresql/data volumes: - pgdata:/var/lib/postgresql/data restart: always immich-proxy: container_name: immich_proxy image: ghcr.io/immich-app/immich-proxy:${IMMICH_VERSION:-release} environment: # Make sure these values get passed through from the env file - IMMICH_SERVER_URL - IMMICH_WEB_URL ports: - 2283:8080 depends_on: - immich-server - immich-web restart: always volumes: pgdata: model-cache: tsdata: ``` ### Your .env content ```Shell DB_HOSTNAME=immich_postgres DB_USERNAME=postgres DB_PASSWORD=postgres DB_DATABASE_NAME=immich REDIS_HOSTNAME=immich_redis UPLOAD_LOCATION=C:\docker\immich\content TYPESENSE_API_KEY=some-random-text PUBLIC_LOGIN_PAGE_MESSAGE= IMMICH_WEB_URL=http://immich-web:3000 IMMICH_SERVER_URL=http://immich-server:3001 IMMICH_MACHINE_LEARNING_URL=http://immich-machine-learning:3003 ``` ### Reproduction steps ```bash 1. Upload a photo taken by a device which stores the local timezone time/date into the exif date taken fields 2. Once the metadata is extracted, view the date/time of the photo ``` ### Additional information Running the storage migration does nothing applies to read-only image library as well as uploaded images from the web
Author
Owner

@JayBigGuy10 commented on GitHub (Jul 8, 2023):

seems that the mobile app (1.66.0 build.89) WILL display the correct time for files that are only locally on the device (not backed up) but displays the incorrectly offset time for files that are on the server

@JayBigGuy10 commented on GitHub (Jul 8, 2023): seems that the mobile app (1.66.0 build.89) WILL display the correct time for files that are only locally on the device (not backed up) but displays the incorrectly offset time for files that are on the server
Author
Owner

@uhthomas commented on GitHub (Jul 8, 2023):

I believe this is a duplicate of https://github.com/immich-app/immich/issues/2953, let me know if you believe otherwise.

@uhthomas commented on GitHub (Jul 8, 2023): I believe this is a duplicate of https://github.com/immich-app/immich/issues/2953, let me know if you believe otherwise.
Author
Owner

@JayBigGuy10 commented on GitHub (Jul 10, 2023):

I'm not 100% sure I'm using exiftool correctly but I ran exiftool -h IMG_20221002_161817.jpg against the image I used as an example

The output does have duplicate create date tags like the issue you linked describes, but neither of them contain the time zone, the only place that it is present in the image is from the filesystem modification/access/creation dates

(I attatched the immage at the end, but I'm not sure if github preserves all the tags)

ExifTool Version Number12.64
File NameIMG_20221002_161817.jpg
Directory.
File Size2.1 MB
File Modification Date/Time2022:10:02 16:18:17+13:00
File Access Date/Time2023:07:10 11:18:56+12:00
File Creation Date/Time2023:07:10 11:17:57+12:00
File Permissions-rw-rw-rw-
File TypeJPEG
File Type Extensionjpg
MIME Typeimage/jpeg
Exif Byte OrderBig-endian (Motorola, MM)
Y Resolution72
X Resolution72
Camera Model NameAC2003
MakeOnePlus
XMP ToolkitAdobe XMP Core 5.1.0-jc003
Capture ModePhoto
Lens FacingBack
Scene Detect Result Ids[61, 0, 0]
Scene Detect Result Confidences[0.99403065, 0.0, 0.0]
Is HDR ActiveFalse
Is Night Mode ActiveFalse
Is Bokeh ActiveFalse
Y Cb Cr PositioningCentered
Exif Version0220
Aperture Value2.2
Scene TypeUnknown (0)
Exposure Compensation0
Exposure ProgramNot Defined
Color SpacesRGB
Max Aperture Value2.2
Exif Image Height2448
Brightness Value0
Date/Time Original2022:10:02 16:18:17
Flashpix Version0100
Sub Sec Time Original000702
White BalanceAuto
Interoperability IndexR98 - DCF basic file (sRGB)
Exposure ModeAuto
Exposure Time1/100
FlashOff, Did not fire
Sub Sec Time000702
F Number2.2
ISO125
Exif Image Width3264
Components ConfigurationY, Cb, Cr, -
Focal Length In 35mm Format0 mm
Sub Sec Time Digitized000702
Create Date2022:10:02 16:18:17
Shutter Speed Value1/100
Metering ModeCenter-weighted average
Focal Length1.7 mm
Scene Capture TypeStandard
Light SourceD65
Sensing MethodUnknown (0)
OrientationHorizontal (normal)
Resolution Unitinches
Modify Date2022:10:02 16:18:17
CompressionJPEG (old-style)
Thumbnail Offset1418
Thumbnail Length32044
WarningFPXR segment too small
Image Width3264
Image Height2448
Encoding ProcessBaseline DCT, Huffman coding
Bits Per Sample8
Color Components3
Y Cb Cr Sub SamplingYCbCr4:2:0 (2 2)
Aperture2.2
Shutter Speed1/100
Create Date2022:10:02 16:18:17.000702
Date/Time Original2022:10:02 16:18:17.000702
Modify Date2022:10:02 16:18:17.000702
Thumbnail Image(Binary data 32044 bytes)
Image Size3264x2448
Light Value8.6
Megapixels8.0
Focal Length1.7 mm

IMG_20221002_161817

@JayBigGuy10 commented on GitHub (Jul 10, 2023): I'm not 100% sure I'm using exiftool correctly but I ran `exiftool -h IMG_20221002_161817.jpg` against the image I used as an example The output does have duplicate `create date` tags like the issue you linked describes, but neither of them contain the time zone, the only place that it is present in the image is from the filesystem modification/access/creation dates (I attatched the immage at the end, but I'm not sure if github preserves all the tags) <table> <tr><td>ExifTool Version Number</td><td>12.64</td></tr> <tr><td>File Name</td><td>IMG_20221002_161817.jpg</td></tr> <tr><td>Directory</td><td>.</td></tr> <tr><td>File Size</td><td>2.1 MB</td></tr> <tr><td>File Modification Date/Time</td><td>2022:10:02 16:18:17+13:00</td></tr> <tr><td>File Access Date/Time</td><td>2023:07:10 11:18:56+12:00</td></tr> <tr><td>File Creation Date/Time</td><td>2023:07:10 11:17:57+12:00</td></tr> <tr><td>File Permissions</td><td>-rw-rw-rw-</td></tr> <tr><td>File Type</td><td>JPEG</td></tr> <tr><td>File Type Extension</td><td>jpg</td></tr> <tr><td>MIME Type</td><td>image/jpeg</td></tr> <tr><td>Exif Byte Order</td><td>Big-endian (Motorola, MM)</td></tr> <tr><td>Y Resolution</td><td>72</td></tr> <tr><td>X Resolution</td><td>72</td></tr> <tr><td>Camera Model Name</td><td>AC2003</td></tr> <tr><td>Make</td><td>OnePlus</td></tr> <tr><td>XMP Toolkit</td><td>Adobe XMP Core 5.1.0-jc003</td></tr> <tr><td>Capture Mode</td><td>Photo</td></tr> <tr><td>Lens Facing</td><td>Back</td></tr> <tr><td>Scene Detect Result Ids</td><td>[61, 0, 0]</td></tr> <tr><td>Scene Detect Result Confidences</td><td>[0.99403065, 0.0, 0.0]</td></tr> <tr><td>Is HDR Active</td><td>False</td></tr> <tr><td>Is Night Mode Active</td><td>False</td></tr> <tr><td>Is Bokeh Active</td><td>False</td></tr> <tr><td>Y Cb Cr Positioning</td><td>Centered</td></tr> <tr><td>Exif Version</td><td>0220</td></tr> <tr><td>Aperture Value</td><td>2.2</td></tr> <tr><td>Scene Type</td><td>Unknown (0)</td></tr> <tr><td>Exposure Compensation</td><td>0</td></tr> <tr><td>Exposure Program</td><td>Not Defined</td></tr> <tr><td>Color Space</td><td>sRGB</td></tr> <tr><td>Max Aperture Value</td><td>2.2</td></tr> <tr><td>Exif Image Height</td><td>2448</td></tr> <tr><td>Brightness Value</td><td>0</td></tr> <tr><td>Date/Time Original</td><td>2022:10:02 16:18:17</td></tr> <tr><td>Flashpix Version</td><td>0100</td></tr> <tr><td>Sub Sec Time Original</td><td>000702</td></tr> <tr><td>White Balance</td><td>Auto</td></tr> <tr><td>Interoperability Index</td><td>R98 - DCF basic file (sRGB)</td></tr> <tr><td>Exposure Mode</td><td>Auto</td></tr> <tr><td>Exposure Time</td><td>1/100</td></tr> <tr><td>Flash</td><td>Off, Did not fire</td></tr> <tr><td>Sub Sec Time</td><td>000702</td></tr> <tr><td>F Number</td><td>2.2</td></tr> <tr><td>ISO</td><td>125</td></tr> <tr><td>Exif Image Width</td><td>3264</td></tr> <tr><td>Components Configuration</td><td>Y, Cb, Cr, -</td></tr> <tr><td>Focal Length In 35mm Format</td><td>0 mm</td></tr> <tr><td>Sub Sec Time Digitized</td><td>000702</td></tr> <tr><td>Create Date</td><td>2022:10:02 16:18:17</td></tr> <tr><td>Shutter Speed Value</td><td>1/100</td></tr> <tr><td>Metering Mode</td><td>Center-weighted average</td></tr> <tr><td>Focal Length</td><td>1.7 mm</td></tr> <tr><td>Scene Capture Type</td><td>Standard</td></tr> <tr><td>Light Source</td><td>D65</td></tr> <tr><td>Sensing Method</td><td>Unknown (0)</td></tr> <tr><td>Orientation</td><td>Horizontal (normal)</td></tr> <tr><td>Resolution Unit</td><td>inches</td></tr> <tr><td>Modify Date</td><td>2022:10:02 16:18:17</td></tr> <tr><td>Compression</td><td>JPEG (old-style)</td></tr> <tr><td>Thumbnail Offset</td><td>1418</td></tr> <tr><td>Thumbnail Length</td><td>32044</td></tr> <tr><td>Warning</td><td>FPXR segment too small</td></tr> <tr><td>Image Width</td><td>3264</td></tr> <tr><td>Image Height</td><td>2448</td></tr> <tr><td>Encoding Process</td><td>Baseline DCT, Huffman coding</td></tr> <tr><td>Bits Per Sample</td><td>8</td></tr> <tr><td>Color Components</td><td>3</td></tr> <tr><td>Y Cb Cr Sub Sampling</td><td>YCbCr4:2:0 (2 2)</td></tr> <tr><td>Aperture</td><td>2.2</td></tr> <tr><td>Shutter Speed</td><td>1/100</td></tr> <tr><td>Create Date</td><td>2022:10:02 16:18:17.000702</td></tr> <tr><td>Date/Time Original</td><td>2022:10:02 16:18:17.000702</td></tr> <tr><td>Modify Date</td><td>2022:10:02 16:18:17.000702</td></tr> <tr><td>Thumbnail Image</td><td>(Binary data 32044 bytes)</td></tr> <tr><td>Image Size</td><td>3264x2448</td></tr> <tr><td>Light Value</td><td>8.6</td></tr> <tr><td>Megapixels</td><td>8.0</td></tr> <tr><td>Focal Length</td><td>1.7 mm</td></tr> </table> ![IMG_20221002_161817](https://github.com/immich-app/immich/assets/42988261/8b812d2f-0106-4238-9b53-dc0978c30ffe)
Author
Owner

@azuse commented on GitHub (Aug 1, 2023):

I think I have the same problem, my camera doesn't record a timezone info in exif, it only records a time in setting timezone, and in Immich web the time would be display as time+timezone.
For example my camera takes picture in 0:00am, the file create date would be 0:00am, but because I live in UTC+4 (or Immich server is running in UTC+4 TZ), immich would display the file create date to be 4:00am.
Only photo taken with my camera has this problem. Photo from my phone, video from my camera, they all display right time.

@azuse commented on GitHub (Aug 1, 2023): I think I have the same problem, my camera doesn't record a timezone info in exif, it only records a time in setting timezone, and in Immich web the time would be display as time+timezone. For example my camera takes picture in 0:00am, the file create date would be 0:00am, but because I live in UTC+4 (or Immich server is running in UTC+4 TZ), immich would display the file create date to be 4:00am. Only photo taken with my camera has this problem. Photo from my phone, video from my camera, they all display right time.
Author
Owner

@jrasm91 commented on GitHub (Aug 1, 2023):

Let me clarify a few things:

These apply during the metadata extraction process, which happens in the immich-microservices container:

  • If there is no timezone information in the exif data (and no gps to infer it from), it'll use the containers timezone, this can be set using the environment variable TZ=.... If that is not set, it will assume local time is UTC.
  • If a timezone can be determined, it'll get saved in asset.exifInfo.timeZone

These apply during the rendering of the asset info on the web:

  • If an asset has a timezone (value in asset.exifInfo.timeZone) it'll display the date with the associated offset.
  • If an asset has no timezone (value in asset.exifInfo.timeZone is null) it'll fallback to the local client's timezone to dynamically adjust it. If you are viewing it in Europe, the Americas, Asia the date with change depending on your location.
@jrasm91 commented on GitHub (Aug 1, 2023): Let me clarify a few things: These apply during the metadata extraction process, which happens in the `immich-microservices` container: - If there is no timezone information in the exif data (and no gps to infer it from), it'll use the _containers timezone_, this can be set using the environment variable `TZ=...`. If that is not set, it will assume local time is UTC. - If a timezone _can_ be determined, it'll get saved in `asset.exifInfo.timeZone` These apply during the rendering of the asset info on the web: - If an asset has a timezone (value in `asset.exifInfo.timeZone`) it'll display the date with the associated offset. - If an asset has no timezone (value in `asset.exifInfo.timeZone` is null) it'll fallback to the local _client's_ timezone to dynamically adjust it. If you are viewing it in Europe, the Americas, Asia the date with _change_ depending on your location.
Author
Owner

@daniele-athome commented on GitHub (Aug 2, 2023):

Let me clarify a few things:

This is important information. You should perhaps include it in the user documentation. Especially the part about the local client's timezone which sometimes doesn't work (i.e. think about Firefox privacy.resistFingerprinting which hides the time zone).

@daniele-athome commented on GitHub (Aug 2, 2023): > Let me clarify a few things: This is important information. You should perhaps include it in the user documentation. Especially the part about the local client's timezone which sometimes doesn't work (i.e. think about Firefox `privacy.resistFingerprinting` which hides the time zone).
Author
Owner

@JayBigGuy10 commented on GitHub (Aug 2, 2023):

the first bit does seem to have been documented already
https://immich.app/docs/FAQ#why-does-my-uploaded-photo-show-up-with-the-wrong-date-or-time-in-immich

was done a while ago in
https://github.com/immich-app/immich/pull/2003 to 'fix' https://github.com/immich-app/immich/issues/2000

well, whoops, guess this makes me the idiot who couldn't read the FAQ

@JayBigGuy10 commented on GitHub (Aug 2, 2023): the first bit does seem to have been documented already https://immich.app/docs/FAQ#why-does-my-uploaded-photo-show-up-with-the-wrong-date-or-time-in-immich was done a while ago in https://github.com/immich-app/immich/pull/2003 to 'fix' https://github.com/immich-app/immich/issues/2000 well, whoops, guess this makes me the idiot who couldn't read the FAQ
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: immich-app/immich#1071