On Calendars and Calendar_Dates

A recurring question on the transit-developers list regards how calendaring (which trips are in effect on a given day) works in GTFS. It is a little opaque at first, but in the end it’s rather simple. This post aims to solve that by walking through a few examples.

The two relevant files within the GTFS are calendar.txt and calendar_dates.txt. Each of these files references service_id, an “ID that uniquely identifies a set of dates when service is available for one or more routes” Every trip in trips.txt has a service_id, and that’s what is used to tie calendars and calendar dates to trips.

Below the fold are a number of examples, ranging from simple to more complex. These can all be mixed and matched if necessary.

1. One service_id runs every day
The following service runs every day from year 2014 to 2024.
In calendar.txt:
service_id,monday,tuesday,wednesday,thursday,friday,saturday,sunday,start_date,end_date
everyday,1,1,1,1,1,1,1,20140101,20240101

2. A different service_id for Saturday and Sunday, in addition to a regular weekday schedule.
In calendar.txt:
service_id,monday,tuesday,wednesday,thursday,friday,saturday,sunday,start_date,end_date
weekday,1,1,1,1,1,0,0,20140101,20240101
saturday,0,0,0,0,0,1,0,20140101,20240101
saturday,0,0,0,0,0,0,1,20140101,20240101

3. Sunday schedule on a holiday
This situation introduces calendar_dates.txt, which provides exceptions to the regular schedule. In this case, New Year’s Day is added as a Sunday schedule (exception_type 1), with the existing weekday schedule cancelled out (exception_type 2).
In calendar.txt:
service_id,monday,tuesday,wednesday,thursday,friday,saturday,sunday,start_date,end_date
weekday,1,1,1,1,1,0,0,20140101,20240101
saturday,0,0,0,0,0,1,0,20140101,20240101
saturday,0,0,0,0,0,0,1,20140101,20240101

In calendar_dates.txt:
service_id,date,exception_type
weekday,20140101,2
sunday,20140101,1

4. A new schedule on a holiday
What if there was a completely different schedule on New Years day (e.g. extra service after midnight)? That also goes in calendar_dates.txt. Remember to include the trips in your trips.txt!

In calendar.txt:

service_id,monday,tuesday,wednesday,thursday,friday,saturday,sunday,start_date,end_date
weekday,1,1,1,1,1,0,0,20140101,20240101
saturday,0,0,0,0,0,1,0,20140101,20240101
saturday,0,0,0,0,0,0,1,20140101,20240101

In calendar_dates.txt:
service_id,date,exception_type
weekday,20140101,2
newyears,20140101,1

5. Adding supplimental service
Additional service might be run on certain days (e.g. sports events), but the regular schedule remains the same.  These additional trips would be defined in the trips.txt file.

In calendar.txt:
service_id,monday,tuesday,wednesday,thursday,friday,saturday,sunday,start_date,end_date
weekday,1,1,1,1,1,0,0,20140101,20240101
saturday,0,0,0,0,0,1,0,20140101,20240101
saturday,0,0,0,0,0,0,1,20140101,20240101

In calendar_dates.txt:
service_id,date,exception_type
weekday,20140101,2
newyears,20140101,1

6. Bonus: service beginning before midnight, but assigned to the following day.

This is a not unheard of occurrance. Here’s a bit from AC Transit’s GTFS. You’ll notice that there is… Saturday service on Friday?!?
service_id,monday,tuesday,wednesday,thursday,friday,saturday,sunday,start_date,end_date
1412WR-D2-Saturday-01,0,0,0,0,0,1,0,20141213,20150228
1412WR-D2-Saturday-01 -1,0,0,0,0,1,0,0,20141212,20150227

The reason is that there is a trip that begins before midnight, but continues on the next day. It’s likely part of the Saturday schedule for operational purposes, but GTFS has a different model for how days work. Let’s take a look at how this works by what’s in that service_id.

$ grep "1412WR-D2-Saturday-01 -1" trips.txt
800-114,3954673-1412WR-D2-Saturday-01,1412WR-D2-Saturday-01 -1,800 TRANSBAY,1,574037,8000207
800-114,3954722-1412WR-D2-Saturday-01,1412WR-D2-Saturday-01 -1,800 TRANSBAY,1,574040,8000205

And then what’s in the stop_times for this trip:
$ grep 3954673-1412WR-D2-Saturday-01 stop_times.txt | grep ,1,
3954673-1412WR-D2-Saturday-01,1006360,23:55:00,24:01:00,1,,

The trip arrives at the first stop at 23:55 (perhaps to guarantee a connection for other riders arriving at the same stop on another route), but does not leave until 24:01 (or 00:01).