/* stopFlightLog() - called every time the system shifts from "flying" state to "taxiing" state (or directly to stopped, though that should not happen). Updates the end values for the startup record. Appends the stop point airport to the 'route' list, so if the aircraft makes multiple stops without powering off the system this will indicate all of them. */ func stopFlightLog(fullstop bool) { // gps coordinates at startup flightlog.end_lat = float64(mySituation.Lat) flightlog.end_lng = float64(mySituation.Lng) // time, timezone, localtime flightlog.end_timestamp = stratuxClock.RealTime.Unix() flightlog.end_tz = latlong.LookupZoneName(float64(mySituation.Lat), float64(mySituation.Lng)) loc, err := time.LoadLocation(flightlog.end_tz) if err == nil { flightlog.end_localtime = mySituation.GPSTime.In(loc).String() } // airport code and name apt, err := findAirport(float64(mySituation.Lat), float64(mySituation.Lng)) if err == nil { flightlog.end_airport_id = apt.faaId flightlog.end_airport_name = apt.name flightlog.route = flightlog.route + " => " + apt.faaId if fullstop == false { flightlog.route = flightlog.route + " (t/g)" } } //create a landing record in the event log table if fullstop == false { addFlightEvent("Landing (T/G)") } else { addFlightEvent("Landing") } // update the database entry dataUpdateChan <- true }
/* startFlightLog() - called once per startup when the GPS has a valid timestamp and position to tag the beginning of the 'session'. Updates the startup record with the initial place / time values. */ func startFlightLog() { // gps coordinates at startup flightlog.start_lat = float64(mySituation.Lat) flightlog.start_lng = float64(mySituation.Lng) flightlog.start_alt = mySituation.Alt flightlog.max_alt = mySituation.Alt // time, timezone, localtime flightlog.start_timestamp = (stratuxClock.RealTime.UnixNano() / 1000000) flightlog.start_tz = latlong.LookupZoneName(float64(mySituation.Lat), float64(mySituation.Lng)) loc, err := time.LoadLocation(flightlog.start_tz) if err == nil { flightlog.start_localtime = stratuxClock.RealTime.In(loc).String() } // airport code and name apt, err := findAirport(float64(mySituation.Lat), float64(mySituation.Lng)) if err == nil { flightlog.start_airport_id = apt.faaId flightlog.start_airport_name = apt.name flightlog.route = apt.faaId } // update the database entry dataUpdateChan <- true }
// 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 getLocalTimeZone(lat fit.Latitude, lng fit.Longitude) (*time.Location, error) { if lat.Invalid() || lng.Invalid() { return nil, errNoGeoDataAvailable } ltz := latlong.LookupZoneName(lat.Degrees(), lng.Degrees()) if ltz == "" { return nil, errors.New("found no timezone for provided geographical data") } location, err := time.LoadLocation(ltz) if err != nil { return nil, fmt.Errorf("error loading location for zone name %q: %v", ltz, err) } return location, nil }
func (we *wrapperEvents) UnmarshalJSON(data []byte) error { var events []model.Event if err := json.Unmarshal(data, &events); err != nil { return err } if len(events) > 0 { // get all datetime for event within venue timezone for i, event := range events { tz := latlong.LookupZoneName(float64(event.Venue.Latitude), float64(event.Venue.Longitude)) loc, err := time.LoadLocation(tz) if err != nil { continue } events[i].Datetime.Time = time.Date(event.Datetime.Time.Year(), event.Datetime.Time.Month(), event.Datetime.Time.Day(), event.Datetime.Time.Hour(), event.Datetime.Time.Minute(), event.Datetime.Time.Second(), event.Datetime.Time.Nanosecond(), loc) } } we.events = events return nil }
/* append a flight event record to the 'events' table in the database */ func addFlightEvent(event string) { var myEvent FlightEvent myEvent.event = event myEvent.lat = float64(mySituation.Lat) myEvent.lng = float64(mySituation.Lng) timezone := latlong.LookupZoneName(float64(mySituation.Lat), float64(mySituation.Lng)) loc, err := time.LoadLocation(timezone) if err == nil { lt := stratuxClock.RealTime.In(loc) myEvent.localtime = lt.Format("15:04:05 MST") } apt, err := findAirport(float64(mySituation.Lat), float64(mySituation.Lng)) if err == nil { myEvent.airport_id = apt.faaId myEvent.airport_name = apt.name } myEvent.timestamp = stratuxClock.RealTime.Unix() dataLogChan <- DataLogRow{tbl: "events", data: myEvent} }
func getAlbumPhotos(api flickrAPI, id string, gotPhoto chan struct{}) SetOfRefOfRemotePhoto { response := struct { flickrCall Photoset struct { Photo []struct { DateTaken string `json:"datetaken"` Id string `json:"id"` Title string `json:"title"` Tags string `json:"tags"` ThumbURL string `json:"url_t"` ThumbWidth interface{} `json:"width_t"` ThumbHeight interface{} `json:"height_t"` SmallURL string `json:"url_s"` SmallWidth interface{} `json:"width_s"` SmallHeight interface{} `json:"height_s"` Latitude interface{} `json:"latitude"` Longitude interface{} `json:"longitude"` MediumURL string `json:"url_m"` MediumWidth interface{} `json:"width_m"` MediumHeight interface{} `json:"height_m"` LargeURL string `json:"url_l"` LargeWidth interface{} `json:"width_l"` LargeHeight interface{} `json:"height_l"` OriginalURL string `json:"url_o"` OriginalWidth interface{} `json:"width_o"` OriginalHeight interface{} `json:"height_o"` } `json:"photo"` } `json:"photoset"` }{} // TODO: Implement paging. This call returns a maximum of 500 pictures in each response. err := api.Call("flickr.photosets.getPhotos", &response, &map[string]string{ "photoset_id": id, "user_id": user.Id(), "extras": "date_taken,geo,tags,url_t,url_s,url_m,url_l,url_o", }) d.Chk.NoError(err) store := ds.Store() photos := NewSetOfRefOfRemotePhoto() for _, p := range response.Photoset.Photo { photo := RemotePhotoDef{ Id: p.Id, Title: p.Title, Tags: getTags(p.Tags), }.New() lat, lon := deFlickr(p.Latitude), deFlickr(p.Longitude) // Flickr doesn't give timezone information (in fairness, neither does EXIF), so try to figure it out from the geolocation data. This is imperfect because it won't give us daylight savings. If there is no geolocation data then assume the location is PST - it's better than GMT. zone := "America/Los_Angeles" if lat != 0.0 && lon != 0.0 { if z := latlong.LookupZoneName(lat, lon); z != "" { zone = z } } location, err := time.LoadLocation(zone) d.Chk.NoError(err) // DateTaken is the MySQL DATETIME format. if t, err := time.ParseInLocation("2006-01-02 15:04:05", p.DateTaken, location); err == nil { photo = photo.SetDate(DateDef{t.Unix() * 1e3}.New()) } else { fmt.Printf("Error parsing date \"%s\": %s\n", p.DateTaken, err) } sizes := NewMapOfSizeToString() sizes = addSize(sizes, p.ThumbURL, p.ThumbWidth, p.ThumbHeight) sizes = addSize(sizes, p.SmallURL, p.SmallWidth, p.SmallHeight) sizes = addSize(sizes, p.MediumURL, p.MediumWidth, p.MediumHeight) sizes = addSize(sizes, p.LargeURL, p.LargeWidth, p.LargeHeight) sizes = addSize(sizes, p.OriginalURL, p.OriginalWidth, p.OriginalHeight) photo = photo.SetSizes(sizes) if lat != 0.0 && lon != 0.0 { photo = photo.SetGeoposition(GeopositionDef{float32(lat), float32(lon)}.New()) } // TODO: Write photos in batches. photos = photos.Insert(store.WriteValue(photo).(RefOfRemotePhoto)) gotPhoto <- struct{}{} } return photos }