package darwindb import ( "fmt" "time" "hg.lukegb.com/lukegb/depot/go/trains/darwin" ) // secondsify adds :00 onto the end of a string if it's HH:MM formatted, otherwise does nothing. func secondsify(ts string) string { if len(ts) == 5 { // xx:xx (no seconds) return ts + ":00" } return ts } // startTime takes a train and ascertains its "start time". func startTime(s *darwin.Schedule) (time.Time, error) { // We assume these are sensibly sorted by Darwin. if len(s.CallingPoints) == 0 { return time.Time{}, fmt.Errorf("no calling points") } cp := s.CallingPoints[0] var ts string tsCandidates := []string{cp.WTD, cp.PTD, cp.WTP, cp.WTA, cp.PTA} for _, tsc := range tsCandidates { if tsc != "" { ts = tsc } } if ts == "" { return time.Time{}, fmt.Errorf("failed to find a suitable timestamp in first calling point") } ts = fmt.Sprintf("%v %v", s.SSD, secondsify(ts)) t, err := time.ParseInLocation("2006-01-02 15:04:05", ts, darwin.London) if err != nil { return time.Time{}, fmt.Errorf("parsing start time %q: %w", ts, err) } return t, nil } // timeToTimestamp takes a string HH:MM and places it appropriately given the approximate 'start time' of the train. func timeToTimestamp(ts string, startTime time.Time) *time.Time { if ts == "" { return nil } ts = secondsify(ts) t, err := time.ParseInLocation("2006-01-02 15:04:05", startTime.Format("2006-01-02 ")+ts, darwin.London) if err != nil { return nil } // Follow Darwin rules for determining time skips // https://wiki.openraildata.com/index.php/Darwin:Schedule_Element#Ordering difference := t.Sub(startTime) switch { case difference > -6*time.Hour && difference < 18*time.Hour: return &t case difference <= -6*time.Hour: // e.g. 08:00 start time, 01:00 time "now" (-7 hrs) -- add a day t = t.AddDate(0, 0, 1) return &t case difference >= 18*time.Hour: // e.g. 01:00 start time, 22:00 time "now" (+18 hrs) -- sub a day t = t.AddDate(0, 0, -1) return &t } panic(fmt.Sprintf("unhandled difference %v", difference)) }