// FileTime returns the best guess of the file's creation time (or modtime). // If the file doesn't have its own metadata indication the creation time (such as in EXIF), // FileTime uses the modification time from the file system. // It there was a valid EXIF but an error while trying to get a date from it, // it logs the error and tries the other methods. func FileTime(f io.ReaderAt) (time.Time, error) { var ct time.Time defaultTime := func() (time.Time, error) { if osf, ok := f.(*os.File); ok { fi, err := osf.Stat() if err != nil { return ct, fmt.Errorf("Failed to find a modtime: stat: %v", err) } return fi.ModTime(), nil } return ct, errors.New("All methods failed to find a creation time or modtime.") } size, ok := findSize(f) if !ok { size = 256 << 10 // enough to get the EXIF } r := io.NewSectionReader(f, 0, size) var tiffErr error ex, err := exif.Decode(r) if err != nil { tiffErr = err if exif.IsShortReadTagValueError(err) { return ct, io.ErrUnexpectedEOF } if exif.IsCriticalError(err) || exif.IsExifError(err) { return defaultTime() } } ct, err = ex.DateTime() if err != nil { return defaultTime() } // If the EXIF file only had local timezone, but it did have // GPS, then lookup the timezone and correct the time. if ct.Location() == time.Local { if exif.IsGPSError(tiffErr) { log.Printf("Invalid EXIF GPS data: %v", tiffErr) return ct, nil } if lat, long, err := ex.LatLong(); err == nil { if loc := lookupLocation(latlong.LookupZoneName(lat, long)); loc != nil { if t, err := exifDateTimeInLocation(ex, loc); err == nil { return t, nil } } } else if !exif.IsTagNotPresentError(err) { log.Printf("Invalid EXIF GPS data: %v", err) } } return ct, nil }
func showEXIF(file string) { f, err := os.Open(file) if err != nil { panic(err.Error()) } defer f.Close() ex, err := exif.Decode(f) if err != nil { if exif.IsCriticalError(err) { log.Fatalf("exif.Decode, critical error: %v", err) } log.Printf("exif.Decode, warning: %v", err) } fmt.Printf("%v\n", ex) if exif.IsExifError(err) { // the error happened while decoding the EXIF sub-IFD, so as DateTime is // part of it, we have to assume (until there's a better "decode effort" // strategy in goexif) that it's not usable. return } ct, err := ex.DateTime() fmt.Printf("exif.DateTime = %v, %v\n", ct, err) }