depot/go/trains/darwin/darwindb/tsutil.go

74 lines
2 KiB
Go

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))
}