The exiftool date-resolver path compared GPSLatitudeRef / GPSLongitudeRef against the one-letter forms "S" / "W". With ImageApi's flags, exiftool prints the word forms ("South", "West"). So every western- or southern-hemisphere photo resolved by exiftool was mirrored into the opposite hemisphere before the GPS→zone lookup.
On prod this hit 280 of the 281 date_taken_tz_source = 'gps' rows. Ohio photos resolved to roughly UTC+8 (camera_offset_minutes = +480), which made their date_utc 12–13 h off. Apollo #37 matches on true_instant, so this has to land before #37 deploys.
Fix
src/date_resolver.rs adds a gps_ref_is(value, letter) helper. It matches the first character case-insensitively, so "W", "w", "West" and " West" all count. This is the same rule exif.rs already uses for the kamadak path.
Tests
parse_payload_reads_exiftool_word_hemisphere_refs: real exiftool 12.76 output for an Ohio photo (West/North) and a Sydney photo (South/East). It fails if the old comparison is put back.
gps_ref_is_matches_letter_and_word_forms: unit test for the helper.
The full suite passes (1523 tests), and clippy and fmt are clean.
After deploy
Existing rows keep their wrong offsets until they're re-resolved. Back up the DB first, then:
Fixes #163.
## Problem
The exiftool date-resolver path compared `GPSLatitudeRef` / `GPSLongitudeRef` against the one-letter forms `"S"` / `"W"`. With ImageApi's flags, exiftool prints the word forms (`"South"`, `"West"`). So every western- or southern-hemisphere photo resolved by exiftool was mirrored into the opposite hemisphere before the GPS→zone lookup.
On prod this hit 280 of the 281 `date_taken_tz_source = 'gps'` rows. Ohio photos resolved to roughly UTC+8 (`camera_offset_minutes = +480`), which made their `date_utc` 12–13 h off. Apollo #37 matches on `true_instant`, so this has to land before #37 deploys.
## Fix
`src/date_resolver.rs` adds a `gps_ref_is(value, letter)` helper. It matches the first character case-insensitively, so `"W"`, `"w"`, `"West"` and `" West"` all count. This is the same rule `exif.rs` already uses for the kamadak path.
## Tests
- `parse_payload_reads_exiftool_word_hemisphere_refs`: real exiftool 12.76 output for an Ohio photo (`West`/`North`) and a Sydney photo (`South`/`East`). It fails if the old comparison is put back.
- `gps_ref_is_matches_letter_and_word_forms`: unit test for the helper.
The full suite passes (1523 tests), and clippy and fmt are clean.
## After deploy
Existing rows keep their wrong offsets until they're re-resolved. Back up the DB first, then:
```sql
UPDATE image_exif
SET date_utc = NULL, camera_offset_minutes = NULL, date_taken_tz_source = NULL
WHERE date_taken_tz_source = 'gps';
```
The drain picks them up again within a tick or two. The test server needs the same reset.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The exiftool branch matched GPSLatitudeRef / GPSLongitudeRef with an
exact one-letter compare ("S" / "W"), but exiftool's print conversion
(which parse_gps_dms relies on) renders them as "South" / "West". The
flags never set, so every western longitude and southern latitude
reached the camera-offset cascade positive and the GPS step looked up
the mirrored point: northeast Ohio became China, offset UTC+8. On prod,
all 280 western-hemisphere `gps`-sourced rows carry +480, putting their
date_utc 12-13 h off.
gps_ref_is matches the first letter case-insensitively, the same rule
as exif::extract_gps_coordinate (whose kamadak path was already
correct; the stored gps_latitude / gps_longitude columns are unaffected).
Tests use exiftool's real output strings ("West" / "South", verified
against exiftool 12.76 with the resolver's -j -q -G1 flags), including
a southern-hemisphere case; the new payload test fails on the old
compare. The existing test fed "W", which exiftool doesn't emit by
default, so it couldn't catch this.
Existing rows need a re-resolve after deploy; see #163 for the reset.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes #163.
Problem
The exiftool date-resolver path compared
GPSLatitudeRef/GPSLongitudeRefagainst the one-letter forms"S"/"W". With ImageApi's flags, exiftool prints the word forms ("South","West"). So every western- or southern-hemisphere photo resolved by exiftool was mirrored into the opposite hemisphere before the GPS→zone lookup.On prod this hit 280 of the 281
date_taken_tz_source = 'gps'rows. Ohio photos resolved to roughly UTC+8 (camera_offset_minutes = +480), which made theirdate_utc12–13 h off. Apollo #37 matches ontrue_instant, so this has to land before #37 deploys.Fix
src/date_resolver.rsadds agps_ref_is(value, letter)helper. It matches the first character case-insensitively, so"W","w","West"and" West"all count. This is the same ruleexif.rsalready uses for the kamadak path.Tests
parse_payload_reads_exiftool_word_hemisphere_refs: real exiftool 12.76 output for an Ohio photo (West/North) and a Sydney photo (South/East). It fails if the old comparison is put back.gps_ref_is_matches_letter_and_word_forms: unit test for the helper.The full suite passes (1523 tests), and clippy and fmt are clean.
After deploy
Existing rows keep their wrong offsets until they're re-resolved. Back up the DB first, then:
The drain picks them up again within a tick or two. The test server needs the same reset.
🤖 Generated with Claude Code
The exiftool branch matched GPSLatitudeRef / GPSLongitudeRef with an exact one-letter compare ("S" / "W"), but exiftool's print conversion (which parse_gps_dms relies on) renders them as "South" / "West". The flags never set, so every western longitude and southern latitude reached the camera-offset cascade positive and the GPS step looked up the mirrored point: northeast Ohio became China, offset UTC+8. On prod, all 280 western-hemisphere `gps`-sourced rows carry +480, putting their date_utc 12-13 h off. gps_ref_is matches the first letter case-insensitively, the same rule as exif::extract_gps_coordinate (whose kamadak path was already correct; the stored gps_latitude / gps_longitude columns are unaffected). Tests use exiftool's real output strings ("West" / "South", verified against exiftool 12.76 with the resolver's -j -q -G1 flags), including a southern-hemisphere case; the new payload test fails on the old compare. The existing test fed "W", which exiftool doesn't emit by default, so it couldn't catch this. Existing rows need a re-resolve after deploy; see #163 for the reset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>ac4f0e458cto5b6ffd7040