Skip to content

Using HRDF timetables together with GTFS-RT

When using GTFS-RT, it is assumed that a static GTFS file is being used as the basis.

The Open Data Platform provides one.

But many operators prefer the (more powerful) HRDF format.

In HRDF the following journey fields form a unique key:

  • “Journey number”
  • “Management”
  • “Option”

This is found in the “*Z line of the file “FPLAN”.

In GTFS (and GTFS-RT) this is the “Trip_ID” in the “trips.txt” file. The routes (in “routes.txt”) and trips are numbered automatically. This means that they are not stable either between GTFS versions.

If the actual timetable is to originate from HRDF and its algorithms are configured for this, they must still import the GTFS Static into the database and produce a matching.

The following procedure is recommended:

Import the current GTFS Static into your database

Import the current GTFS Static into a database (e.g. using https://github.com/cbick/gtfs_SQL_importer). A simple SQL script is an example.

drop table GTFS_agency;
drop table GTFS_calendar;
drop table GTFS_calendar_dates;
drop table GTFS_routes;
drop table GTFS_stops;
drop table GTFS_stop_times;
drop table GTFS_trips;


create table GTFS_agency(agency_id TEXT,agency_name TEXT,agency_url TEXT,
                    agency_timezone TEXT,agency_lang TEXT, agency_phone TEXT);
create table GTFS_calendar(service_id TEXT,monday NUMERIC, tuesday NUMERIC, wednesday NUMERIC, thursday NUMERIC, friday NUMERIC, saturday NUMERIC, sunday NUMERIC,start_date NUMERIC,end_date NUMERIC);
create table GTFS_calendar_dates(service_id TEXT,date NUMERIC,exception_type NUMERIC);
create table GTFS_routes(route_id TEXT,agency_id TEXT,route_short_name TEXT,
                    route_long_name TEXT,route_type NUMERIC
                    );
-- create table shapes(shape_id TEXT,shape_pt_lat REAL,shape_pt_lon REAL, shape_pt_sequence NUMERIC);
create table GTFS_stops(stop_id TEXT,stop_name TEXT,
                   stop_lat REAL,stop_lon REAL, location_type TEXT,parent_station TEXT
                   );
create table GTFS_stop_times(trip_id TEXT,arrival_time TEXT,departure_time TEXT,
                        stop_id TEXT,stop_sequence NUMERIC,
                        pickup_type NUMERIC,drop_off_type NUMERIC);
create table GTFS_trips(route_id TEXT,service_id TEXT,trip_id TEXT,
                   trip_headsign TEXT,direction_id NUMERIC
                   );
.separator ','
.import GTFS_Import/agency.txt GTFS_agency
.import GTFS_Import/calendar.txt GTFS_calendar
.import GTFS_Import/calendar_dates.txt GTFS_calendar_dates
.import GTFS_Import/routes.txt GTFS_routes
-- .import GTFS_Import/shapes.txt shapes
.import GTFS_Import/stops.txt GTFS_stops
.import GTFS_Import/stop_times.txt GTFS_stop_times
.import GTFS_Import/trips.txt GTFS_trips
delete from GTFS_agency where agency_id like 'agency_id';
delete from GTFS_calendar_dates where service_id like 'service_id';
delete from GTFS_routes where route_id like 'route_id';
-- delete from shapes where shape_id like 'shape_id';
delete from GTFS_stops where stop_id like 'stop_id';
delete from GTFS_stop_times where trip_id like 'trip_id';
delete from GTFS_trips where route_id like 'route_id';

You must understand the structure of GTFS: https://developers.google.com/transit/gtfs/reference/

Import the necessary files from HRDF to a database

You must import data from different files from HRDF. The structure is described here: https://opentransportdata.swiss/wp-content/uploads/2016/10/hrdf.pdf

From “FPLAN”:

*Z Zeile
1-2 *Z
4-8 INT32 Fahrtnummer
10-15 CHAR Verwaltung
19-21 INT16 Variante

* G Zeile
1-2 *G
4-6 CHAR Verkehrsmittel bzw. Gattung
8-14 INT32 optional Haltestelle, ab der die Gattung gilt
16-22 INT32 optional Haltestellennummer, bis zu der die Gattung gilt
24-29 INT32 optional Abfahrtszeitpunkt
31-36 INT32 optional Ankunftszeitpunkt

* L Zeile
1-2 *L
4-11 CHAR Liniennummer

*I Zeilen
1-2 *I
4-5 Z0 ursprünglicher >Zug
4-5 ZN 
30-36 Infotextnummer
* R Zeile
1-2 *R
4-4 CHAR Richtungskennung

* Laufwegzeilen
1-7 Haltestellenummer
30-35 -INT32 Ankunftszeit an der Haltestelle
37-42 INT32 Abfahrts ab Haltestelle
*/

The traffic periods must also be integrated (“BITFELD” file). You need this to determine the days of operation.

Data is required from the “INFOTEXT” file to identify the correct train numbers in the event of failures. If the train number changes (in the case of failures), the original train number is saved in the “Infotext” field in “INFOTEXT”. This means that the value “Z0” in HRDF must still be correctly referenced.

Through-services must also be imported. Through-services are two journeys which are made by the same train. Through-services are contained in the “DURCHBI” file.

10480 000881 8587086 10481 000881 000000 8587086    % 
10486 000881 8587086 10487 000881 000000 8587086    % 
10502 000801 8507867 10501 000801 000000 8507867    % Unterseen, Spital Interlaken
10502 000801 8507867 90501 000801 000000 8507867    % Unterseen, Spital Interlaken
10504 000801 8507867 10503 000801 000000 8507867    % Unterseen, Spital Interlaken
10504 000801 8507867 90505 000801 000000 8507867    % Unterseen, Spital Interlaken
10510 000801 8507867 10509 000801 000000 8507867    % Unterseen, Spital Interlaken
10512 000801 8507867 10511 000801 000000 8507867    % Unterseen, Spital Interlaken
10514 000801 8507867 10513 000801 000000 8507867    % Unterseen, Spital Interlaken
10516 000801 8507867 10515 000801 000000 8507867    % Unterseen, Spital Interlaken
10518 000801 8507867 10517 000801 000000 8507867    % Unterseen, Spital Interlaken
10520 000037 8500063 10528 000037 000525 8500063    %  00063 50505T R 50505T R 25:28 - 25:28  25:28 - 25:28
10520 000801 8507867 10519 000801 000000 8507867    % Unterseen, Spital Interlaken
10522 000773 8594188 07059 000773 000000 8594188    % 
10522 000801 8507867 10521 000801 000000 8507867    % Unterseen, Spital Interlaken
10523 000773 8594188 04839 000773 000000 8594188    % 
10524 000801 8507867 10523 000801 000000 8507867    % Unterseen, Spital Interlaken
10526 000773 8590892 10418 000773 000000 8590892    % 
10526 000801 8507867 10525 000801 000000 8507867    % Unterseen, Spital Interlaken
10528 000801 8507867 10527 000801 000000 8507867    % Unterseen, Spital Interlaken
10530 000801 8507867 10529 000801 000000 8507867    % Unterseen, Spital Interlaken
10532 000801 8507867 10531 000801 000000 8507867    % Unterseen, Spital Interlaken
10534 000801 8507867 10533 000801 000000 8507867    % Unterseen, Spital Interlaken
10536 000801 8507867 10535 000801 000000 8507867    % Unterseen, Spital Interlaken
10538 000801 8507867 10537 000801 000000 8507867    % Unterseen, Spital Interlaken
10540 000801 8507867 10539 000801 000000 8507867    % Unterseen, Spital Interlaken
10542 000801 8507867 10541 000801 000000 8507867    % Unterseen, Spital Interlaken
10544 000801 8507867 10543 000801 000000 8507867    % Unterseen, Spital Interlaken
10548 000801 8507867 10549 000801 000000 8507867    % Unterseen, Spital Interlaken
10550 000801 8507867 10551 000801 000000 8507867    % Unterseen, Spital Interlaken
10552 000801 8507867 10553 000801 000000 8507867    % Unterseen, Spital Interlaken
10554 000801 8507867 10555 000801 000000 8507867    % Unterseen, Spital Interlaken
10560 000801 8507867 10559 000801 000000 8507867    % Unterseen, Spital Interlaken
10562 000801 8507867 10561 000801 000000 8507867    % Unterseen, Spital Interlaken
10605 000841 8588626 28023 000841 000000 8588626    %  88626 60110E R 60528E R 07:03 - 07:06  07:04 - 07:15
10607 000841 8588626 28033 000841 000000 8588626    %  88626 60110E R 60528E R 08:03 - 08:06  08:04 - 08:15
10625 000841 8588626 28123 000841 000010 8588626    %  88626 60110E R 60528E R 17:12 - 17:15  17:13 - 17:15
10627 000841 8588626 28133 000841 000010 8588626    %  88626 60110E R 60528E R 18:12 - 18:15  18:13 - 18:15
10629 000841 8588626 28143 000841 000010 8588626    %  88626 60110E R 60528E R 19:12 - 19:15  19:13 - 19:15
10653 03____ 8015187 10357 03____ 090720 8015187    %

In GTFS the through-services are already joined together to form the trip. Therefore, Trip A and Trip B, which are linked in HRDF via DURCHBI, are already in GTFS as A->B. The following elements should feature in the record as a minimum:

  • Journey number
  • Management
  • Option
  • Start location
  • Destination location
  • Start time
  • Destination time
  • Line
  • Direction
  • Operation period
  • Z0
  • ZN

Matching data

You can now match the records via:

  • Start location
  • Start time
  • Destination location
  • Destination time
  • Direction
  • Day of operation

Matching can also be carried out using the travel distance, in which case the day of operation can be discarded. Matching via the travel distance matches the exact route.

Please note:

  • There are more trips in GTFS than journeys in HRDF.
  • Cross-border trains are truncated at the border station on the Open Data Platform. If you have obtained the timetables from another source, this may be different.
  • You can determine the start/destination location also from the travel distance from “FPLAN”.Matching can be carried out statically or dynamically, depending on what your application requires. In any case, you must include the relevant day as this is the only way to ensure that they can identify the relevant trip and the relevant HRDF-FPLAN-Entry uniquely. Example:
  • You can do this using, for instance, a getTripfromHRDF function (Journey ID, Management, Version, Day of operation).
  • You can create a getHRDFfromTrip(trip_id, day of operation) function.
  • You create for each day of operation a view/table of the trips and their mapping to HRDF (NB: In the worst-case scenario, 130,000 journeys x 400 days)