Skip to content

Commit 3ef1d69

Browse files
committed
BUG some date time exif tags are not correctly parsed
Fixes #727
1 parent 2e585a7 commit 3ef1d69

File tree

2 files changed

+48
-31
lines changed

2 files changed

+48
-31
lines changed

internal/exif/direct.go

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -172,41 +172,21 @@ func readDateTime(x *exif.Exif, dateTag exif.FieldName, subSecTag exif.FieldName
172172
if err == nil {
173173
subSec += "000"
174174
date = date + "." + subSec[:3]
175-
return time.ParseInLocation("2006:01:02 15:04:05.000", date, local)
176175
}
177-
return time.ParseInLocation("2006:01:02 15:04:05", date, local)
176+
return parseExifTime(date, local)
178177
}
179178

180-
/*
181-
// readGPSTimeStamp extract the date from the GPS data
182-
183-
func readGPSTimeStamp(x *exif.Exif, _ *time.Location) (time.Time, error) {
184-
tag, err := getTagSting(x, exif.GPSDateStamp)
185-
if err == nil {
186-
var tags *tiff.Tag
187-
tags, err = x.Get(exif.GPSTimeStamp)
188-
if err == nil {
189-
tag = tag + " " + fmt.Sprintf("%02d:%02d:%02dZ", ratToInt(tags, 0), ratToInt(tags, 1), ratToInt(tags, 2))
190-
t, err := time.ParseInLocation("2006:01:02 15:04:05Z", tag, time.UTC)
191-
if err == nil {
192-
return t, nil
193-
}
194-
}
195-
}
196-
return time.Time{}, err
179+
func parseExifTime(date string, local *time.Location) (time.Time, error) {
180+
var year, month, day, hour, min, sec, milli int
181+
date = strings.ReplaceAll(date, "-", ":")
182+
date = strings.ReplaceAll(date, "/", ":")
183+
fmt.Sscanf(date, "%d:%d:%d %d:%d:%d.%d", &year, &month, &day, &hour, &min, &sec, &milli)
184+
if year < 1900 || month == 0 || day == 0 {
185+
return time.Time{}, fmt.Errorf("invalid date format")
197186
}
198-
199-
func ratToInt(t *tiff.Tag, i int) int {
200-
n, d, err := t.Rat2(i)
201-
if err != nil {
202-
return 0
203-
}
204-
if d == 1 {
205-
return int(n)
206-
}
207-
return int(float64(n) / float64(d))
208-
}
209-
*/
187+
d := time.Date(year, time.Month(month), day, hour, min, sec, milli*int(time.Millisecond), local)
188+
return d, nil
189+
}
210190

211191
func getTagSting(x *exif.Exif, tagName exif.FieldName) (string, error) {
212192
t, err := x.Get(tagName)

internal/exif/direct_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,43 @@ func Test_MetadataFromDirectRead(t *testing.T) {
8181
}
8282
}
8383

84+
func Test_parseExifTime(t *testing.T) {
85+
tests := []struct {
86+
name string
87+
date string
88+
location *time.Location
89+
want time.Time
90+
wantErr bool
91+
}{
92+
{
93+
name: "valid date with different separators in local timezone",
94+
date: "2023-10-06 08:30:00",
95+
location: time.Local,
96+
want: time.Date(2023, 10, 6, 8, 30, 0, 0, time.Local),
97+
wantErr: false,
98+
},
99+
{
100+
name: "valid date with milliseconds in local timezone",
101+
date: "2023-10-06 08:30:00.123",
102+
location: time.Local,
103+
want: time.Date(2023, 10, 6, 8, 30, 0, int(123*time.Millisecond), time.Local),
104+
wantErr: false,
105+
},
106+
}
107+
for _, tt := range tests {
108+
t.Run(tt.name, func(t *testing.T) {
109+
got, err := parseExifTime(tt.date, tt.location)
110+
if (err != nil) != tt.wantErr {
111+
t.Errorf("parseExifTime() error = %v, wantErr %v", err, tt.wantErr)
112+
return
113+
}
114+
if !tt.want.IsZero() && !got.Equal(tt.want) {
115+
t.Errorf("parseExifTime() = %v, want %v", got, tt.want)
116+
}
117+
})
118+
}
119+
}
120+
84121
func floatEquals(a, b, epsilon float64) bool {
85122
return (a-b) < epsilon && (b-a) < epsilon
86123
}

0 commit comments

Comments
 (0)