RhetTbull / photos_time_warp

Batch adjust the date, time, or timezone of photos in Apple Photos from the Mac command line.
MIT License
12 stars 1 forks source link

--exiftool gets timezones wrong in image file #7

Closed Jmuccigr closed 2 years ago

Jmuccigr commented 3 years ago

I have an image that I took in Turkey. Photos thinks it's from one timezone west of that, since I imported it in Italy. (I get that by looking at "Adjust Date and Time".) exiftool reports this:

Modify Date                     : 2019:10:17 12:17:31
Date/Time Original              : 2019:10:17 12:17:31
Create Date                     : 2019:10:17 12:17:31

You can see that there's no TZ info. I'd like to fix that by simply adding a TZ. The time is correct for that TZ, that is, I took the photo at 12:17 in Turkey.

I duplicated the image to have something to test on. Photos puts the duplicate file into my current TZ of New York, which seems a bit odd to me, but whatever. The displayed time is 6 hours earlier than the one in the file, or 6:17, so it seems to be internally tracking the file's original TZ or at least using it to set a new time for the duplicate.

If I run exiftool directly on this duplicate image file: exiftool '-OffsetTimeOriginal=+03:00', I get this:

Modify Date                     : 2019:10:17 12:17:31
Date/Time Original              : 2019:10:17 12:17:31
Create Date                     : 2019:10:17 12:17:31
Date/Time Original              : 2019:10:17 12:17:31+03:00

So just the TZ bit gets added. Perfect. Photos doesn't know about this of course, so nothing changes there.

If I use photos_time_warp to do the update: photos_time_warp -V --timezone +0300 --exiftool.

Photos now updates both the TZ and the time it displays for the photo to match this shift. Because it's an 7-hour difference, Photos shows the time as 13:17. If I run exiftool on the file, I get this:

Modify Date                     : 2019:10:17 12:17:31
Date/Time Original              : 2019:10:17 06:17:31
Create Date                     : 2019:10:17 06:17:31
Date Created                    : 2019:10:17
Date/Time Original              : 2019:10:17 06:17:31+03:00
Date/Time Created               : 2019:10:17 06:17:31+03:00

There are two new tags in addition to the modified Date/Time Created, but what's off is the time. The TZ is there correctly, but instead of leaving the rest of the time alone, photos_time_warp has used the displayed time in Photos to replace it. That's not right. Note too that Photos thinks this photo was taken at 1317 in GMT+3, which is not what the exif says.

I suspect that this might be as simple as not setting the time when it's not included in the command, but it may be trickier than that.

RhetTbull commented 3 years ago

You're right that --exiftool updates both date/time and timezone. The intent was to use one bit of code to keep the image file the same as the Photos database regardless of what changed in Photos. It looks like the exif update code is using the old time. I'll take a look this weekend.

RhetTbull commented 3 years ago

I've replicated this. My intent for --exiftool is for it to mirror whatever the settings in Photos are so it needs to always update the date/time/timezone -- e..g the user may have updated date or time manually or the exif file might be missing date/time even if you used photos_time_warp just to set the timezone. I need to figure out how to get the time from Photos into the correct format for exiftool.

RhetTbull commented 3 years ago

I still need to do some testing but I think this is fixed in v0.0.8

Jmuccigr commented 3 years ago

OK, so before I run the command:

exif time: 17:33
Original TZ in exif: <missing>
Original time in Photos: 11.33
Original TZ in Photos: NY

And after:

exiftime: 18:33
New TZ in exif: +3
New time in Photos: 18:33 (correctly adjusted by 7 hours)
New TZ in Photos: Baghdad (correctly GMT+3)

So this seems to be working now, in that the times match in exif and Photos. Thanks.

However...because Photos imposes its own TZ on photos when it imports them (thanks for --inspect!), the final times end up being incorrect because Photos makes the appropriate adjustment when the TZ is changed and then this propagates to the exif data. But this isn't always desired behavior. In my case, for example, the problem is that I've got a bunch of photos with no TZ and that I imported in a different TZ from the original one, which I imagine is a common vacation scenario. In this case I'd like the photos to keep their original time and just get a TZ. Right now I'd need to both shift the time and change the TZ, so the resulting file keeps the same (correct) time in the new TZ as those two actions offset each other. Instead I just want a TZ without any change in time, because my camera had the right time, just no TZ.

An example: here is what I see when I use the --inspect option on one of my Turkey photos, taken at 17:34 Turkey time, and imported into Photos in Rome:

filename, uuid, photo time (local), photo time, timezone offset, timezone name
IMG_7661.JPG, 5764A0D1-6D03-4450-9E76-A83C794D65E9, 2019-10-17T11:34:12-04:00, 2019-10-17T17:34:12+02:00, +0200, GMT+0200

The exif data is like the "before" example above: time, but no TZ. You can see that Photos has put the Rome TZ in there (+2), but has left the original 17:34 time alone. When the TZ gets shifted, Photos shifts the time along with it and then that gets propagated to the exif.

Instead the original time needs to remain. So perhaps provide an option that does this by restoring the original Photos time after the TZ is changed? I'm not sure this shouldn't be the default when only TZ is changed and not time, to be honest, but either way, having the option would be good.

RhetTbull commented 3 years ago

Photos won't allow a photo to exist in the database without a timezone so as you've noted, it adds the current timezone when importing. And this is why I hate dealing with anything related to timezones--gives me a headache every time! 😄 Thanks for the example -- this makes sense. I can fix the --exiftool option so it only modifies the timezone if only timezone is adjusted which is the proper behavior for your example. The original design was "make --exiftool mirror Photos" but that's not right for this (likely common) use case.

RhetTbull commented 3 years ago

I've updated the exiftool code so it updates only OffsetTimeOriginal if only the offset changed. This produces the behavior you expected in your example. But, I'm not confident photos_time_warp is doing the 'right thing' for the photo in Photos. (More below on this)

Photo has no OffsetTimeOriginal:

⇡34% [I] ➜ exiftool -AllDates -OffsetTimeOriginal '/Users/rhet/Pictures/Test-10.15.7.photoslibrary/originals/0/0F592CB0-1E54-4B8C-859A-5FF0ED6045FE.jpeg'
Date/Time Original              : 2021:09:01 12:00:00
Create Date                     : 2021:09:01 12:00:00
Modify Date                     : 2021:09:01 12:00:00

Computer time zone changed to Rome (GMT+0200) and imported into Photos:

⇡35% [I] ➜ photos_time_warp --inspect
filename, uuid, photo time (local), photo time, timezone offset, timezone name
test.jpg, 0F592CB0-1E54-4B8C-859A-5FF0ED6045FE, 2021:09:01 12:00:00+0200, 2021:09:01 12:00:00+0200, +0200, Europe/Rome

Computer time zone changed to New York time (GMT-0400):

⇡35% [I] ➜ photos_time_warp --inspect
filename, uuid, photo time (local), photo time, timezone offset, timezone name
test.jpg, 0F592CB0-1E54-4B8C-859A-5FF0ED6045FE, 2021:09:01 06:00:00-0400, 2021:09:01 12:00:00+0200, +0200, Europe/Rome

photos_time_warp used to change the offset:

⇡37% [I] ➜ photos_time_warp -V --timezone +0300 --exiftool
exiftool path: /usr/local/bin/exiftool
Processing 1 photo
Updated timezone for photo test.jpg (0F592CB0-1E54-4B8C-859A-5FF0ED6045FE) from Europe/Rome, offset=7200 to GMT+0300, offset=10800
Updating EXIF data for test.jpg (0F592CB0-1E54-4B8C-859A-5FF0ED6045FE)
Writing EXIF data with exiftool to /Users/rhet/Pictures/Test-10.15.7.photoslibrary/originals/0/0F592CB0-1E54-4B8C-859A-5FF0ED6045FE.jpeg
Done.
⇡38% [I] ➜ photos_time_warp --inspect
filename, uuid, photo time (local), photo time, timezone offset, timezone name
test.jpg, 0F592CB0-1E54-4B8C-859A-5FF0ED6045FE, 2021:09:01 06:00:00-0400, 2021:09:01 13:00:00+0300, +0300, GMT+0300
⇡38% [I] ➜ exiftool -AllDates -OffsetTimeOriginal '/Users/rhet/Pictures/Test-10.15.7.photoslibrary/originals/0/0F592CB0-1E54-4B8C-859A-5FF0ED6045FE.jpeg'
Date/Time Original              : 2021:09:01 12:00:00
Create Date                     : 2021:09:01 12:00:00
Modify Date                     : 2021:09:01 12:00:00
Offset Time Original            : +03:00

You'll notice above that in the EXIF for the original file, only the offset was changed. But Photos changed the actual time of the photo to +1 hour because the time zone was moved from GMT+0200 to GMT+0300. This is the same behavior you get if you manually change the time zone in the Get Info dialog for the photo in Photos. Photos will not permit a photo to not have a timezone so it assigns the local timezone when the photo is imported (in this case Rome, GMT+0200). But when you change the timezone, Photos assumes the current time is the correct one and adjusts the time for the new timezone. In your example, this is not the correct behavior so you'd have to also adjust the time by -1 hour when doing this in Photos.

You could do this in photos_time_warp like this:

Use photos_time_warp to fix the timezone offset and also adjust time accordingly:

[I] ➜ photos_time_warp -V --timezone +0300 --time-delta "-1 hour" --exiftool
exiftool path: /usr/local/bin/exiftool
Processing 1 photo
Updated date/time for photo test.jpg (79DAAA1D-A808-480A-B827-211328A6D919) from: 2021-09-01 06:00:00 to 2021-09-01 05:00:00
Updated timezone for photo test.jpg (79DAAA1D-A808-480A-B827-211328A6D919) from Europe/Rome, offset=7200 to GMT+0300, offset=10800
Updating EXIF data for test.jpg (79DAAA1D-A808-480A-B827-211328A6D919)
Writing EXIF data with exiftool to /Users/rhet/Pictures/Test-10.15.7.photoslibrary/originals/7/79DAAA1D-A808-480A-B827-211328A6D919.jpeg
Done.
[I] ➜ photos_time_warp --inspect
filename, uuid, photo time (local), photo time, timezone offset, timezone name
test.jpg, 79DAAA1D-A808-480A-B827-211328A6D919, 2021:09:01 05:00:00-0400, 2021:09:01 12:00:00+0300, +0300, GMT+0300
[I] ➜ exiftool -AllDates -OffsetTimeOriginal /Users/rhet/Pictures/Test-10.15.7.photoslibrary/originals/7/79DAAA1D-A808-480A-B827-211328A6D919.jpeg
Date/Time Original              : 2021:09:01 12:00:00
Create Date                     : 2021:09:01 12:00:00
Modify Date                     : 2021:09:01 12:00:00
Offset Time Original            : +03:00

But this requires you to have to do the mental math to adjust the offset for each photo based on import timezone and actual timezone. Perhaps photos_time_warp should have a --offset-only or --auto-adjust option that automatically adjusts the time in Photos to match the original EXIF time but in the new timezone? @Jmuccigr I'm happy for any thoughts you might have on this as user of photos_time_warp.

RhetTbull commented 3 years ago

See version 0.0.9 for the exiftool fix referenced above.

Jmuccigr commented 3 years ago

I'm now assuming the example you gave is with the new behavior.

Photos will not permit a photo to not have a timezone so it assigns the local timezone when the photo is imported (in this case Rome, GMT+0200). But when you change the timezone, Photos assumes the current time is the correct one and adjusts the time for the new timezone.

Yes, I agree on how Photos works, i.e., when you change the TZ, it changes the time. This was causing the exif also to be wrong, but you seem to have fixed that, if I understand things correctly. The result is that now the exif data and the Photos data (potentially) disagree. ("Potentially" because it may be that there are situations where they wouldn't, e.g., when you add the current TZ to a photo imported in that same TZ.)

But this requires you to have to do the mental math to adjust the offset for each photo based on import timezone and actual timezone. Perhaps photos_time_warp should have a --offset-only or --auto-adjust option that automatically adjusts the time in Photos to match the original EXIF time but in the new timezone?

Yes, exactly what I'm after. When the command would change the TZ and not the time, keep the original exif time. My suggestion for the option would be --keep-exif-time.

Again, I'm not sure of all the use cases here, but it seems to me that "I'm back from vacation and my camera recorded the time, but not the zone" is likely a very common one, so that this behavior should perhaps be the default. Explicitly: if the exif data lacks a TZ and the user wants to change the TZ and not the time, then keep the original exif time with the new TZ. I could be wrong about this, so it's not a big deal to me. Another possible way to handle this would be to throw up a warning if the exif data lack a TZ, so that the user is aware of the issue.

RhetTbull commented 3 years ago

I'm now assuming the example you gave is with the new behavior.

Yes, the current version will not adjust the exif time if all you changed is the TZ. But this can lead to cases where Photos and the original image file have different time stamps.

I view the exiftool feature as an "additional feature" and not the primary purpose of this tool so for default behavior, I'm most interested in having the tool do the "right thing" in the case where the user updates info in Photos and provide an option for alternate behavior.

My usual rule of thumb for these kinds of tools (I've written several tools for Photos) is to default to "do what Photos does" as that's the case of least surprise. However, in this case I'm not sure I agree that Photos' default behavior is "right". If as you stated, "I'm back from vacation and my camera recorded the time, but not the zone" is a common use case, then the "right" behavior is to fix the TZ while preserving the time in Photos and the exif, keeping everything in sync.

Perhaps the --offset feature should automatically change the time in Photos so a photo taken at 12:00 in GMT+0300 but imported in GMT+0200 still shows as 12:00 when adjusted to GMT+0300 using --offset 0300 (e.g. adjust the photo's time by new_offset - old_offset seconds).

If this was a default behavior, I could have an option that caused photos_time_warp to adjust the time (maybe --auto-adjust or --offset-adjust) when the TZ is changed (preserving the same actual time but adjusted for the new TZ).

Jmuccigr commented 3 years ago

Yes, the current version will not adjust the exif time if all you changed is the TZ. But this can lead to cases where Photos and the original image file have different time stamps.

Exactly. And that is very bad.

This could get very complicated, but I think it boils down to handling these scenarios for imported photos:

  1. My camera had its clock set right, but it didn't know about TZ and so I want to just add that TZ to the file's exif and make sure Photos has the same info.
  2. I forgot to reset my camera's clock and timezone, so just change the timezone and let the time get adjusted appropriately. (Photos default behavior.)

I can imagine all sorts of permutations on this, but I think those can be handled with an option to leave the original time alone.

For example, in my scenario, I took the photos in TZ x, imported them in TZ y, and now am working in Photos in TZ z. If the time was correct on my camera, I just change the TZ and leave the original time. If the time was wrong, I can first correct it without changing the TZ (I assume that photos_time_warp doesn't impose a TZ on the file when none is indicated) and then change the TZ, leaving the time alone.

Addendum/Rant I find Photos a great app to import and organize my photos with. It's infuriating to me that it will reload GPS data, but not time data, nor will it push either to the original file. That means all the work that goes into setting location or time will be preserved only if I stay within Photos. I can use an AppleScript to update the exif data, but Photos won't reload date/time info, so that's nearly pointless.

RhetTbull commented 3 years ago

@all-contributors please add @Jmuccigr for bug, ideas

allcontributors[bot] commented 3 years ago

@RhetTbull

I've put up a pull request to add @Jmuccigr! :tada:

RhetTbull commented 3 years ago

In v0.0.11 I've made a major change to how --timezone operates and added a new --match-time feature. I've also changed the --exiftool behavior so it always updates the time, even if only timezone is set. However, it now updates the time to the "correct" time depending on whether --match-time was used. The rationale for this is it's better to maintain consistency between exif and Photos than not.

--timezone now adjusts the time to represent the same time but in the new TZ, exactly as Photos does now. Thus the default matches Photos. So if the old time was 12:00 GMT+01:00" and you set --timezone 0200, the time is adjusted by 1 hour to 13:00 GMT+02:00 (the equivalent time in the new timezone) just as Photos does.

--match-time tells the script to match the old time but in the new timezone. So for the previous example, --timezone 0200 --match-time changes the time so that the new time is 12:00 GMT+02:00, that is, the timezone changed but the clock time matches the previous time. This is the behavior you wanted for your use case so you should now use --match-time.