EXIF Nonsense

tl;dr

My Canon’s internal clock was not set correctly when I went on vacation and I used exiftool (link) to fix the timestamps with this command:

exiftool -overwrite_original_in_place -AllDates+='0:0:0 5:48:17' '-TimeZone*=+2:00' filtered_canon_copy_no_video
exiftool -overwrite_original_in_place '-FileModifyDate<DateTimeOriginal' -globaltimeshift "-0:0:0 6:0:0" filtered_canon_copy_no_video

The first one shifts the dates to the correct time, and sets the timezone tag. The second one sets the file’s modification date to 6 hours before the date taken so that the macOS file system correctly lists it.




I went on vacation, and unfortunately, my Canon’s internal clock wasn’t quite accurate.

I’m always wrestling with this camera about daylight savings time, using it so sparingly that I have to switch it back nearly every time.

On top of this, it was 6 hours of timezone off when I went to Europe.

All I really want is a unix timestamp for these photos, which I can display later as “6pm” with some javascript, knowing that it means 6pm in CEST, but the timestamps need to be fixed for anything else to happen.


Step One: Find the correct time

I just took a photo of time.gov. I plan to adjust every photo’s exif date in some automated fashion, given that there are 2,277 photos that need to have their timestamp fixed.


Step Two: Unix timestamps? How do jpegs store their EXIF data?

EXIF data doesn't require timezones. It was never required, and there are now many ways to denote the timezone in EXIF data.

As for the second question? I think it’s a rabbit hole that is frankly, irrelevant if I use this library.


Step Three: exiftool

It’s neat. Running the command shows you the (extensive) documentation. There’s a built in flag called “globalTimeShift”!

Side note: Timezone false hope?

Asking exiftool to show you all the timestamps in the file (with -time:all)

Asking for exiftool -time:all IMG_7343.JPG (from my camera) gives me a timezone and it’s offset. Is it just my computer system’s local timezone, or was it from the photo? This was the output.

> exiftool -time:all IMG_7343.JPG 

File Modification Date/Time     : 2025:06:18 01:13:04-04:00
File Access Date/Time           : 2025:07:12 21:48:53-04:00
File Inode Change Date/Time     : 2025:07:12 21:48:52-04:00
Modify Date                     : 2025:06:18 07:13:04
Date/Time Original              : 2025:06:18 07:13:04
Create Date                     : 2025:06:18 07:13:04
Time Zone                       : -05:00
Time Zone City                  : New York
Daylight Savings                : Off
Sub Sec Time                    : 00
Sub Sec Time Original           : 00
Sub Sec Time Digitized          : 00
Create Date                     : 2025:06:18 07:13:04.00
Date/Time Original              : 2025:06:18 07:13:04.00
Modify Date                     : 2025:06:18 07:13:04.00

Asking for exiftool -time:all IMG_0569.JPG (from my phone) gives me a GPS time stamp because it’s geotagged. It flips between my phone’s local time and GMT. The offset from GMT is specified in “Offset Time”, just like the proposal suggested! Neat!

> exiftool -time:all IMG_0569.JPG 

File Modification Date/Time     : 2025:05:20 22:44:21-04:00
File Access Date/Time           : 2025:07:12 21:47:56-04:00
File Inode Change Date/Time     : 2025:06:11 02:44:57-04:00
Modify Date                     : 2025:05:20 22:43:19
Date/Time Original              : 2025:05:20 22:43:19
Create Date                     : 2025:05:20 22:43:19
Offset Time                     : -04:00
Offset Time Original            : -04:00
Offset Time Digitized           : -04:00
Sub Sec Time Original           : 582
Sub Sec Time Digitized          : 582
GPS Time Stamp                  : 02:43:07
GPS Date Stamp                  : 2025:05:21
Profile Date Time               : 2022:01:01 00:00:00
Create Date                     : 2025:05:20 22:43:19.582-04:00
Date/Time Original              : 2025:05:20 22:43:19.582-04:00
Modify Date                     : 2025:05:20 22:43:19-04:00
GPS Date/Time                   : 2025:05:21 02:43:07Z

Comparing my phone’s metadata from the cameras shows that yes, the camera did actually add a time zone to the exif data, but the lack of standards makes this process very camera-specific.


Actually finding the offset I need

Looking at the exif for the photo of time.gov:

> exiftool -time:all timestamp_correction_baseline.JPG 

File Modification Date/Time     : 2025:07:12 18:29:04-04:00
File Access Date/Time           : 2025:07:12 21:04:07-04:00
File Inode Change Date/Time     : 2025:07:12 18:18:44-04:00
Modify Date                     : 2025:07:12 18:29:03
Date/Time Original              : 2025:07:12 18:29:03
Create Date                     : 2025:07:12 18:29:03
Time Zone                       : -05:00
Time Zone City                  : New York
Daylight Savings                : Off
Sub Sec Time                    : 46
Sub Sec Time Original           : 46
Sub Sec Time Digitized          : 46
Create Date                     : 2025:07:12 18:29:03.46
Date/Time Original              : 2025:07:12 18:29:03.46
Modify Date                     : 2025:07:12 18:29:03.46

I’m going to ignore all the time zones at the moment, and focus on getting the values I need to align it to the correct time, and worry about the time zone later.

UTC was 22:17:20 in the photo.

(-5, EST) makes it 17:17:20, but one forgets that it’s currently Daylight Savings. Thank GOD that

(-4, EDT) makes it 18:17:20

Camera: 18:29:03
Truth:  18:17:20
Diff:   00:11:43

So, the camera is fast by 11 minutes and 43 seconds.


Which exiftool command actually works?!

I did some of this work at a library, and the wifi disconnected so often that I had decided to just forego internet access for this work session. No internet means that it’s time to actually look at Exiftool’s built-in documentation.

It’s ridiculously good, with dozens of examples of how to use the countless flags and features that this program packs.

I’m simply searching for date in the file and trying everything that it offers.

To test these commands safely, I’ve copied some photos into a separate test directory.

exiftool documentation snippet:

    "exiftool -DateTimeOriginal-='0:0:0 1:30:0' dir"
         Adjust original date/time of all images in directory "dir" by
         subtracting one hour and 30 minutes. (This is equivalent to
         "-DateTimeOriginal-=1.5". See Image::ExifTool::Shift.pl for
         details.)

    "exiftool -createdate+=3 -modifydate+=3 a.jpg b.jpg"
         Add 3 hours to the CreateDate and ModifyDate timestamps of two
         images.

These don’t work. It simply sets all the timestamps to the current time.

exiftool documentation snippet:

    "ShiftTime"

    Shifts EXIF-formatted date/time string by a specified amount. Start with
    a leading minus sign to shift backwards in time. See
    Image::ExifTool::Shift.pl for details about shift syntax. For example,
    to shift a date/time value back by one year:

        exiftool -p '${createdate;ShiftTime("-1:0:0 0")}' a.jpg

This displays what I want it to do (in the console’s output), but I don’t need the dates echoed back to me, I need them applied to the file.

exiftool documentation snippet:

    -globalTimeShift *SHIFT*
         Shift all formatted date/time values by the specified amount when
         reading. Does not apply to unformatted (-n) output. *SHIFT* takes
         the same form as the date/time shift when writing (see
         Image::ExifTool::Shift.pl for details), with a negative shift being
         indicated with a minus sign ("-") at the start of the *SHIFT*
         string. For example:

             # return all date/times, shifted back by 1 hour
             exiftool -globalTimeShift -1 -time:all a.jpg

             # set the file name from the shifted CreateDate (-1 day) for
             # all images in a directory
             exiftool "-filename<createdate" -globaltimeshift "-0:0:1 0:0:0" \
                 -d %Y%m%d-%H%M%S.%%e dir

This was promising, but, I can’t figure out how to find Shift.pl to clarify these notes. None of the examples adjust the original dates.

exiftool '-FileModifyDate<DateTimeOriginal' dir

Finally, this command gets me somewhere. The changes applied from other commands finally become visible in the file browser with this!

exiftool -FileModifyDate-='0:0:0 0:11:43' filtered_test_corrected

Works! I suppose macos only cares about “FileModifyDate”, and ignores all the other date tags.

Progress, at last!


Trust, but verify

Sure, I ran some command that theoretically set the timestamps correctly, but I wanted a way to be a little more sure.

Luckily, I had developed a slight infatuation (article coming soon) with the train station clocks, and had a handful of photographs of them. You’d hope that a train clock is an accurace reference, given some relevant history.

So, I checked the (now maybe-fixed) timestamps on these clock photos. I know that my camera should have been off by 6 hours, because I went to a timezone with a 6 hour difference from EST, where it was previously set.

What’s intriguing is that at first glance, the camera’s timestamps have been fixed with a simple 11 minute offset?

Closer inspection revealed that 12-hour time gave me false hope - photos at 12 noon had a timestamp of just around midnight. My phone had been in 24-hour time for years, but I found out here that my laptop was still set to 12-hour time.


Ignoring that sidenote, it appears that the macOS finder app only cares about the file’s modification date.

Using this command:

exiftool -AllDates-='0:0:0 0:11:43' filtered_test_corrected

You would think that “AllDates” would modify all the date tags, right? Wrong. https://exiftool.org/forum/index.php?topic=8412.0.

Also in that link, you can “fix” this by doing

exiftool '-FileModifyDate<DateTimeOriginal' FileOrDir

Which does work!

Interestingly, doing it this way, the time zone from my computer has been applied. Exiftool warned about this, and now it’s time to fix it.

Before I do that, I can actually combine the two previous commands by doing this:

exiftool '-FileModifyDate<DateTimeOriginal' -globaltimeshift "-0:0:0 0:11:43" filtered_test_corrected

Well, not quite. That only changes the file modification timestamp. It’s actually better to do the previous command, as it modifies the original dates, and then also makes the file modification date change.

The documentation showed that you could match many tags with an *, so I tried:

exiftool '-*Date<DateTimeOriginal' -globaltimeshift "-0:0:0 0:11:43" filtered_test_corrected

Which ended up setting ALL the date tags, EXCEPT the one that it was pulling from. Yet another mess.

So, the working process so far includes:

exiftool -AllDates-='0:0:0 0:11:43' filtered_test_corrected

to set the proper metadata to the “right time” (ignoring time zones).

exiftool '-FileModifyDate<DateTimeOriginal' filtered_test_corrected

to let the operating system actually read said time correctly

and now, to fix the time zones.

exiftool '-EXIF:OffsetTime*=+02:00' filtered_test_corrected

was something suggested by https://exiftool.org/forum/index.php?topic=13170.0

but I’m honestly getting confused at this rate.


working from the top:

exiftool -AllDates-='0:0:0 0:11:43' filtered_test_corrected
exiftool -OffsetTimeOriginal+=+6:00 -OffsetTimeDigitized+=+6:00 -CreateDate+=+6:00 -DateCreated+=+6:00 -DigitalCreationTime+=+6:00 -TimeCreated+=+6:00 filtered_test_corrected
exiftool '-FileModifyDate<DateTimeOriginal' filtered_test_corrected

doesn’t work.

exiftool '-TimeZone*=+6:00' filtered_test_corrected

does set the timezone shown by exiftool’s -time:all command

but doesn’t do anything for the operating system

BUT

google photos likes this timezone tag!

from the top again

6:00:00
0:11:43
5:48:17
exiftool -AllDates+='0:0:0 5:48:17' filtered_test_corrected
exiftool '-TimeZone*=+2:00' filtered_test_corrected
exiftool '-FileModifyDate<DateTimeOriginal' -globaltimeshift "-0:0:0 6:0:0" filtered_test_corrected

I’m satisfied. The metadata seems to match the stuff that comes from my phone and glasses: the creation date is in the “local” (+2:00) time zone, and the file modification date is that date, translated for my computer’s (-4:00) time zone. Google Photos displays the local time, with the +2 timezone displayed, and it’s time to do this to the entire photo library.

exiftool -overwrite_original_in_place -AllDates+='0:0:0 5:48:17' filtered_test_corrected
exiftool -overwrite_original_in_place '-TimeZone*=+2:00' filtered_test_corrected
exiftool -overwrite_original_in_place '-FileModifyDate<DateTimeOriginal' -globaltimeshift "-0:0:0 6:0:0" filtered_test_corrected

interested in saving time, can this be one command?

exiftool -overwrite_original_in_place -AllDates+='0:0:0 5:48:17' '-TimeZone*=+2:00' '-FileModifyDate<DateTimeOriginal' -globaltimeshift "-0:0:0 6:0:0" filtered_test_corrected

forgot that the file modification date took the original DateTimeOriginal tag

exiftool -overwrite_original_in_place -AllDates+='0:0:0 5:48:17' '-TimeZone*=+2:00' '-FileModifyDate<DateTimeOriginal' -globaltimeshift "-0:0:0 5:48:17" filtered_test_corrected

tried to combine the global shift in here

exiftool -overwrite_original_in_place -AllDates+='0:0:0 5:48:17' '-TimeZone*=+2:00' '-FileModifyDate<DateTimeOriginal' -globaltimeshift "+0:0:0 5:48:17" filtered_test_corrected

global shift was negative instead of positive

I’m not messing with what works. Back to the 3 commands.

I can at LEAST incorporate the time zone command into another command.

exiftool -overwrite_original_in_place -AllDates+='0:0:0 5:48:17' '-TimeZone*=+2:00' filtered_test_corrected
exiftool -overwrite_original_in_place '-FileModifyDate<DateTimeOriginal' -globaltimeshift "-0:0:0 6:0:0" filtered_test_corrected

but I’m leaving the FileModifyDate logic the same.

Time to test this on some more images

exiftool -overwrite_original_in_place -AllDates+='0:0:0 5:48:17' '-TimeZone*=+2:00' larger_test_to_fix_timestamps
exiftool -overwrite_original_in_place '-FileModifyDate<DateTimeOriginal' -globaltimeshift "-0:0:0 6:0:0" larger_test_to_fix_timestamps

With only 101 images, this took a second or two to execute. 748MB. I’m scared that with 2,278 items, 17.19GB is a lot to just “see what happens” with.

I didn’t test on videos! I should do that.

I copied all the photos to a new folder, so any changes are “isolated”.

Final command:

exiftool -overwrite_original_in_place -AllDates+='0:0:0 5:48:17' '-TimeZone*=+2:00' filtered_canon_copy_no_video
exiftool -overwrite_original_in_place '-FileModifyDate<DateTimeOriginal' -globaltimeshift "-0:0:0 6:0:0" filtered_canon_copy_no_video

It took a while. The command doesn’t give progress while it’s running, so I checked in Activity Manager to see what was happpening. My laptop didn’t slow down noticeably, but sure enough, Perl was doing something big - 40-80% of CPU, and gigabytes of disk usage.

> exiftool -overwrite_original_in_place -AllDates+='0:0:0 5:48:17' '-TimeZone*=+2:00' filtered_canon_copy_no_video
    1 directories scanned
 2272 image files updated
 
> exiftool -overwrite_original_in_place '-FileModifyDate<DateTimeOriginal' -globaltimeshift "-0:0:0 6:0:0" filtered_canon_copy_no_video
    1 directories scanned
 2272 image files updated

Success.