Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

potentially wrong handling of GTFS Time values? #11

Open
derhuerst opened this issue Nov 25, 2021 · 0 comments
Open

potentially wrong handling of GTFS Time values? #11

derhuerst opened this issue Nov 25, 2021 · 0 comments

Comments

@derhuerst
Copy link

derhuerst commented Nov 25, 2021

GTFS Time is not defined relative to midnight, but relative to noon - 12h. While that makes "writing" GTFS feeds easier, it makes processing a lot harder.

Expected functionality

As explained in my note about GTFS Time values, with the Europe/Berlin time zone (+1h standard time to +2 DST shift occurs at 2021-03-28T02:00+01:00), I expect

  • the departure_time of 00:30 of a trip running on 2021-03-28 to happen at 1616884200/2021-03-28T00:30+02:00, not at 1616887800/2021-03-28T00:30+01:00;
  • the departure_time of 06:30 of a trip running on 2021-03-28 to happen at 1616905800/2021-03-28T06:30+02:00, not at 1616909400/2021-03-28T06:30+01:00.

Describe the bug

I'm not familiar with this code base, but it seems that fastgtfs is affected by this problem on those days that the DST <-> standard time switch occurs on.

I'm not sure how that actually manifests in fastgtfs's output, but I assume that wrong delays will be calculated, or that realtime data can't be matched against static data.

I tried to find some places in the code base:

  • fastgtfs/src/gtfs_data.rs

    Lines 113 to 127 in f77cd57

    .filter(|t| {
    t.stop_times_id == stop_times_id
    && self.is_trip_active_on_time(t, min_time, None)
    && t.start_time + trips_duration >= min_time.since_midnight() as i64
    })
    .find_map(|trip| {
    // this returns the first for which the content is a Some result.
    inxes_for_stop
    .iter()
    .filter(|&&inx| {
    stop_times[inx].time + trip.start_time > min_time.since_midnight() as i64
    })
    .map(|&inx| (trip, inx))
    .next()
    })
  • fastgtfs/src/gtfs_data.rs

    Lines 164 to 169 in f77cd57

    /// returns the number of seconds since midnight this trip departs and arrives.
    pub fn get_trip_departure_arrival_times(&self, trip: &Trip) -> (i64, i64) {
    let stop_times = self.get_stop_times(trip.stop_times_id);
    let trip_duration = stop_times.stop_times.last().unwrap().time;
    (trip.start_time, trip.start_time + trip_duration)
    }
  • fastgtfs/src/gtfs_data.rs

    Lines 182 to 194 in f77cd57

    let seconds_in_h = 60 * 60;
    let within_seconds = within_seconds.unwrap_or(24 * seconds_in_h);
    let target_time = time.since_midnight() as i64;
    // It starts after our window.
    if trip.start_time > target_time + within_seconds {
    return false;
    }
    let (_, arrival_time) = self.get_trip_departure_arrival_times(trip);
    // It finishes before our window.
    if arrival_time < target_time {
    return false;
    }
  • fastgtfs/src/gtfs_data.rs

    Lines 319 to 326 in f77cd57

    let stop_times = &self.get_stop_times(trip.stop_times_id).stop_times;
    let upper_time = GtfsTime::new_from_timestamp(date.timestamp + within_sec);
    for &inx in stop_indexes {
    let time = date.new_replacing_time(stop_times[inx].time + trip.start_time);
    if date <= time && time <= upper_time {
    return Some((trip.trip_id, inx));
    }
    }
  • fastgtfs/src/gtfs_data.rs

    Lines 453 to 464 in f77cd57

    pub fn new_from_midnight(time: i64) -> GtfsTime {
    let ts = SystemTime::now()
    .duration_since(SystemTime::UNIX_EPOCH)
    .unwrap()
    .as_secs() as i64;
    let sec_since_midnight = Utc.timestamp(ts as i64, 0).num_seconds_from_midnight() as i64;
    let last_midnight = ts - sec_since_midnight;
    GtfsTime {
    timestamp: last_midnight + time,
    }
    }
  • fastgtfs/src/gtfs_data.rs

    Lines 479 to 487 in f77cd57

    pub fn from_date(yyyymmdd: &str) -> GtfsTime {
    let date = NaiveDate::parse_from_str(yyyymmdd, "%Y%m%d")
    .expect(&format!("Invalid date: {}", yyyymmdd));
    let date = Utc
    .from_utc_date(&date)
    .and_time(NaiveTime::from_hms(0, 0, 0))
    .unwrap();
    GtfsTime::new_from_timestamp(date.timestamp())
    }
  • fastgtfs/src/gtfs_data.rs

    Lines 501 to 518 in f77cd57

    pub fn is_same_day(&self, other: &GtfsTime) -> bool {
    self.date_time().num_days_from_ce() == other.date_time().num_days_from_ce()
    }
    pub fn day_of_week(&self) -> u32 {
    self.date_time().weekday().num_days_from_monday()
    }
    pub fn h(&self) -> u32 {
    self.date_time().hour()
    }
    pub fn m(&self) -> u32 {
    self.date_time().minute()
    }
    pub fn s(&self) -> u32 {
    self.date_time().second()
    }
    pub fn since_midnight(&self) -> u64 {
    self.date_time().num_seconds_from_midnight() as u64
    }
  • // seconds after the initial_point
    let att_time = seconds_since_midnight - self.time_at_shape_point_seconds[start_point];
    let delta_time_ = self.time_at_shape_point_seconds[start_point + 1]
    - self.time_at_shape_point_seconds[start_point]
    + 1;

related: google/transit#15

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant