Instructions for Building and Using
Bill Seymour’s Amtrak Timetable Generator

as of 2022-12-31


Contents:


Introduction

This paper provides instructions for building and using an open-source C++ program that generates rudimentary timetables for Amtrak trains.

The program was deliberately designed to be quick to set up and easy to use.  The quick-and-easy tradeoff is that it can generate only timetables for single trains, or for westbound/eastbound pairs of trains; and it’s not good at generating timetables for trains that split enroute.  It can do the latter, but it takes more work on the part of the user.

A few examples of the generated timetables are shown in Appendix A.

If you’d like something fancier (written in Python, not C++), check this out.

Tip o’ the hat to Dixieland Software for knowing all the trains’ schedules. 😁

Also, juckins.net has much prettier PDF timetables of the sort that Amtrak used to publish.


The code

In general, all the code is written in C++ and is distributed under the Boost Software License.  (This is not part of Boost, the author just likes their open-source license.)  The only exception is atksked.html, a trivial bit of HTML that the author has put in the public domain.


The supplied files


Building the generator

If compiling C++ programs is a mystery to you, see Appendix D.

You’ll need a C++ implementation that conforms at least to C++11.  Pretty much any moderately recent GCC will work just fine for POSIX operating systems, and it’s free.  Microsoft Visual C++ from around 2015 or so should work OK for Windows.  (IIRC, there’s a free version of the Microsoft compiler and standard library that’s good enough if all you want to do is write console apps, which is what this program is; but this writer can’t remember what Microsoft calls it.)

Just put station-codes.inc in some directory where #include with quotes can find it (probably the same directory where you put make-timetable.cpp), then compile the program from a command line.  You won’t need any fancy makefile, and a GUI build tool will just get in the way.


Instructions for use

You need to do two things.  First, download one or more trains’ schedules from Dixieland Software, then run the timetable generator as described below.


Getting the raw data

First, get the schedule for each train for which you want to generate a timetable using the URL:
http://dixielandsoftware.net/cgi-bin/getschedule.pl?seltrain=the-train-number

Or if you’d prefer, you can use the following little HTML page to get the data.

<html>
<head>
<title>Amtrak Train Schedules</title>
<!--
by Bill Seymour, 2022-12-30
This file is in the public domain.
-->
</head>
<body>
<center>
<h2>Get an Amtrak Train Schedule</h2>
<form name="form" method=GET
      action="http://dixielandsoftware.net/cgi-bin/getschedule.pl">
Train number:&nbsp;&nbsp;<input type=text name="seltrain" size=4 maxlength=4>
<p><input type=submit value="Submit">
</form>
</center>
</body>
</html>

For example, the URL:

http://dixielandsoftware.net/cgi-bin/getschedule.pl?seltrain=302
will load your browser with something that looks like:
* Schedule For Train 302.           Formatted Data
* Lincoln Service  (PDF Schedule)
* +---------------- Station Code
* |    +----------- Schedule Arrival Day  
* |    |  +-------- Schedule Arrival Time
* |    |  |     +----- Schedule Departure Day
* |    |  |     |  +-- Schedule Departure Time 
* |    |  |     |  |     +------------- Actual Arrival Time
* |    |  |     |  |     |     +------- Actual Departure Time
* |    |  |     |  |     |     |     +- Comments
* V    V  V     V  V     V     V     V
  STL  *  *     1  640A              CT
  ALN  *  *     1  725A              CT
  CRV  *  *     1  752A              CT
  SPI  *  *     1  832A              CT
  LCN  *  *     1  856A              CT
  BNL  *  *     1  930A              CT
  PON  *  *     1  959A              CT
  DWT  *  *     1  1017A             CT
  JOL  *  *     1  1104A             CT
  SMT  *  *     1  1129A             CT
  CHI  1  1205P *  *                 CT

Then in your browser, Edit->Select All and Edit->Copy to a text file on your hard drive.  The files can be in any directory and have any filenames you want; but it’ll be easier for you later if you put them in what will be the current working directory when you run the timetable generator, and name the files [train-number]sked.txt.  For example, save the raw data for train 302 in a file named 302sked.txt.

If you wind up with blank lines at the beginning and the end, don’t worry; the generator program will happily ignore leading and trailing blank lines in its input files.


Generating the timetable

The easiest thing to do is to just run make-timetable from a command line giving one or two train numbers as command-line arguments.

Let’s say that you’ve downloaded the raw data for trains 29, 30 and 2150 into files named 29sked.txt, 30sked.txt and 2150sked.txt, and those files are in what will be the current working directory when you run the generator program.  In that case, you can generate the first two examples shown in Appendix A with the commands

make-timetable 29 30
and
make-timetable 2150
The generated files will be in the current working directory and have the names, 29sked.html and 2150sked.html.

But you can get fancier with the filenames if you want to.

If a command-line argument is a decimal number of one to four digits, the program assumes that it’s a train number; but anything else is assumed to be the full or relative path for the input file.  For example, if you have a file named 2150.sked in the /train/schedules directory on a POSIX system, then the command

make-timetable /train/schedules/2150.sked
will do the same thing as the second command above.  (In Windows, the directory separator is CP/M’s backslash, “\”.)

The path to the output file defaults to [train-number]sked.html in the current working directory, where [train-number] is taken from the input file specified by the first, or only, argument; but you can get around that, too.  Just use the -o option (“o” for “output”) followed by the full or relative path to the file that you want the generator to create.  For example, the command

make-timetable 29 30 -o CapitolLimited.html
will also create the first example in Appendix A, but in a file named CapitolLimited.html in the current working directory.

Or instead of using the -o option followed by a file path, you can use just -s to send the generated timetable to the standard output.  This might be useful if you want to pipe the output to some other program that massages the HTML further.


Appendix A:  sample output

An example of a westbound/eastbound pair of trains:

Timetable for Trains 29 and 30,
the Capitol Limited

29🠠 Train Number 🠢30
Read DownStationRead Up
DayTimeCodeNameTime
Zone
TimeDay
116:05WASWashington - Union Station, DCET13:052
16:29RKVRockville, MD12:16
17:16HFYHarpers Ferry, WV11:31
17:45MRBMartinsburg, WV11:01
19:17
19:24
CUMCumberland, MD09:32
09:20
21:47COVConnellsville, PA06:59
23:48
23:59
PGHPittsburgh, PA05:20
05:05
201:39ALCAlliance, OH03:05
02:53
02:59
CLECleveland, OH01:54
01:45
03:29ELYElyria, OH01:15
04:02SKYSandusky, OH00:40
05:08
05:22
TOLToledo, OH23:49
23:39
1
06:36WTIWaterloo, IN22:23
07:29EKHElkhart, IN21:29
07:51SOBSouth Bend, IN21:09
08:45CHIChicago - Union Station, ILCT18:40

Note that, for daily trains, the Day column contains just a day count.



An example of a single train:

Timetable for Train 2150,
the Acela Express

2150🠠 Train Number
Read DownStation
DayTimeCodeNameTime
Zone
MoTuWeThFr08:02NYPNew York - Penn Station, NYET
08:47STMStamford, CT
10:57PVDProvidence, RI
11:24RTEWestwood - Route 128, MA
11:33BBYBoston - Back Bay, MA
11:39BOSBoston - South Station, MA

For a train that runs less often than daily, the Day column will contain the days that the train runs.



A more interesting example:

Timetable for Trains 421 and 422,
the Texas Eagle cars that run through to Los Angeles

421🠠 Train Number 🠢422
Read DownStationRead Up
DayTimeCodeNameTime
Zone
TimeDay
SuTuFr13:45CHIChicago - Union Station, ILCT13:44WeSaMo
14:40JOLJoliet, IL12:48
15:26PONPontiac, IL11:34
16:01BNLBloomington-Normal, IL11:02
16:30LCNLincoln, IL10:20
17:06SPISpringfield, IL09:51
17:38CRVCarlinville, IL09:09
18:09ALNAlton, IL08:43
19:13
19:55
STLSt. Louis, MO07:55
07:24
22:02ACDArcadia, MO04:19
23:42PBFPoplar Bluff, MO02:44
MoWeSa00:37WNRWalnut Ridge, AR01:41
03:10LRKLittle Rock, AR23:39
23:31
TuFrSu
03:55MVNMalvern, AR22:26
04:20ARKArkadelphia, AR22:02
05:09HOPHope, AR21:18
05:58TXATexarkana, AR20:43
07:50MHLMarshall, TX19:31
08:28LVWLongview, TX18:15
09:25MINMineola, TX17:15
11:30
11:50
DALDallas, TX15:40
15:20
13:25
14:10
FTWFort Worth, TX14:20
13:58
14:52CBRCleburne, TX13:00
16:00MCGMcGregor, TX11:51
16:43TPLTemple, TX11:25
17:36TAYTaylor, TX10:22
18:30AUSAustin, TX09:31
19:12SMCSan Marcos, TX08:32
MoWeSa
TuThSu
21:55
02:45
SASSan Antonio, TX07:00
04:50
TuThSu05:49DRTDel Rio, TX01:02
08:24SNDSanderson, TX22:36MoThSa
10:38ALPAlpine, TX20:45
13:22
13:47
ELPEl Paso, TXMT15:35
15:10
15:18DEMDeming, NM13:10
16:13LDBLordsburg, NM12:15
18:18BENBenson, AZMST10:15
19:45
20:35
TUSTucson, AZ09:15
08:28
21:52
22:02
MRCMaricopa, AZ06:40
06:30
WeFrMo00:49YUMYuma, AZ03:47
02:02PSNPalm Springs - North, CAPT00:36
03:54ONAOntario, CA22:54SuWeFr
04:04POSPomona, CA22:41
05:35LAXLos Angeles - Union Station, CA22:00

Creating the data to generate this one took the extra work described in Appendix B.


Appendix B:  generating more complicated timetables

Sometimes you might want to generate a timetable for a train or trains for which Dixieland Sofware will not provide the raw data that you need, at least not in a form that’s easy to use.  So how did I generate the timetable shown as the third example in Appendix A?  It took some manual intervention, but only slight modifications to the plain text schedule files using an ordinary text editor.  There was no need to get into any of the HTML, so that should be easy for non-programmers.

I first downloaded the data for train 1, the westbound Sunset Limited, and train 21, the westbound Texas Eagle. I then copied my 21sked.txt to 421sked.txt, and then appended to that the data from my 1sked.txt, but just from San Antonio to Los Angeles.  That gave me (note the two data lines for San Antonio (SAS)):

* Schedule For Train 21.           Formatted Data
* Texas Eagle  (PDF Schedule)
* +---------------- Station Code
* |    +----------- Schedule Arrival Day  
* |    |  +-------- Schedule Arrival Time
* |    |  |     +----- Schedule Departure Day
* |    |  |     |  +-- Schedule Departure Time 
* |    |  |     |  |     +------------- Actual Arrival Time
* |    |  |     |  |     |     +------- Actual Departure Time
* |    |  |     |  |     |     |     +- Comments
* V    V  V     V  V     V     V     V
  CHI  *  *     1  145P              CT
  JOL  *  *     1  240P              CT
  PON  *  *     1  326P              CT
  BNL  *  *     1  401P              CT
  LCN  *  *     1  430P              CT
  SPI  *  *     1  506P              CT
  CRV  *  *     1  538P              CT
  ALN  *  *     1  609P              CT
  STL  1  713P  1  755P              CT
  ACD  *  *     1  1002P             CT
  PBF  *  *     1  1142P             CT
  WNR  *  *     2  1237A             CT
  LRK  *  *     2  310A              CT
  MVN  *  *     2  355A              CT
  ARK  *  *     2  420A              CT
  HOP  *  *     2  509A              CT
  TXA  *  *     2  558A              CT
  MHL  *  *     2  750A              CT
  LVW  *  *     2  828A              CT
  MIN  *  *     2  925A              CT
  DAL  2  1130A 2  1150A             CT
  FTW  2  125P  2  210P              CT
  CBR  *  *     2  252P              CT
  MCG  *  *     2  400P              CT
  TPL  *  *     2  443P              CT
  TAY  *  *     2  536P              CT
  AUS  *  *     2  630P              CT
  SMC  *  *     2  712P              CT
  SAS  2  955P  *  *                 CT
  SAS  2  1205A 2  245A              CT
  DRT  *  *     2  549A              CT
  SND  *  *     2  824A              CT
  ALP  *  *     2  1038A             CT
  ELP  2  122P  2  147P              MT
  DEM  *  *     2  318P              MT
  LDB  *  *     2  413P              MT
  BEN  *  *     2  618P              MST
  TUS  2  745P  2  835P              MST
  MRC  2  952P  2  1002P             MST
  YUM  *  *     3  1249A             MST
  PSN  *  *     3  202A              PT
  ONA  *  *     3  354A              PT
  POS  *  *     3  404A              PT
  LAX  3  535A  *  *                 PT
I then changed the train number to 421 and the train name to “Texas Eagle cars that run through to Los Angeles”, combined the two entries for SAS, adjusted the arrival and departure days accordingly, and appended the days of operation to the first data line.  (The through cars to Los Angeles depart Chicago on Sunday, Tuesday and Friday.)  That gave me (note the single entry for SAS with train 21’s arrival time and train 1’s departure time):
* Schedule For Train 421.           Formatted Data
* Texas Eagle cars that run through to Los Angeles  (PDF Schedule)
* +---------------- Station Code
* |    +----------- Schedule Arrival Day  
* |    |  +-------- Schedule Arrival Time
* |    |  |     +----- Schedule Departure Day
* |    |  |     |  +-- Schedule Departure Time 
* |    |  |     |  |     +------------- Actual Arrival Time
* |    |  |     |  |     |     +------- Actual Departure Time
* |    |  |     |  |     |     |     +- Comments
* V    V  V     V  V     V     V     V
  CHI  *  *     1  145P              CT SuTuFr
  JOL  *  *     1  240P              CT
  PON  *  *     1  326P              CT
  BNL  *  *     1  401P              CT
  LCN  *  *     1  430P              CT
  SPI  *  *     1  506P              CT
  CRV  *  *     1  538P              CT
  ALN  *  *     1  609P              CT
  STL  1  713P  1  755P              CT
  ACD  *  *     1  1002P             CT
  PBF  *  *     1  1142P             CT
  WNR  *  *     2  1237A             CT
  LRK  *  *     2  310A              CT
  MVN  *  *     2  355A              CT
  ARK  *  *     2  420A              CT
  HOP  *  *     2  509A              CT
  TXA  *  *     2  558A              CT
  MHL  *  *     2  750A              CT
  LVW  *  *     2  828A              CT
  MIN  *  *     2  925A              CT
  DAL  2  1130A 2  1150A             CT
  FTW  2  125P  2  210P              CT
  CBR  *  *     2  252P              CT
  MCG  *  *     2  400P              CT
  TPL  *  *     2  443P              CT
  TAY  *  *     2  536P              CT
  AUS  *  *     2  630P              CT
  SMC  *  *     2  712P              CT
  SAS  2  955P  3  245A              CT
  DRT  *  *     3  549A              CT
  SND  *  *     3  824A              CT
  ALP  *  *     3  1038A             CT
  ELP  3  122P  3  147P              MT
  DEM  *  *     3  318P              MT
  LDB  *  *     3  413P              MT
  BEN  *  *     3  618P              MST
  TUS  3  745P  3  835P              MST
  MRC  3  952P  3  1002P             MST
  YUM  *  *     4  1249A             MST
  PSN  *  *     4  202A              PT
  ONA  *  *     4  354A              PT
  POS  *  *     4  404A              PT
  LAX  4  535A  *  *                 PT

I then did the same thing with 2sked.txt and 22sked.txt to make 422sked.txt, except that the data for train 2 from Los Angeles to San Antonio was put at the beginning, not the end, and the days of operation were already there on the Los Angeles line.

I now had 421sked.txt and 422sked.txt which I used to generate the timetable just as I would for any other pair of trains.

Because Dixieland Software provides raw data only between Spokane and Portland for the Portland section of the Empire Builder, and only between Boston and Rensselaer for the Boston section of the Lake Shore Limited, I used basically the same method to generate timetables for trains 27/28 and 449/448.


As another example, I also wanted to create a timetable for train 21 westbound just to St. Louis and train 302 eastbound to Chicago.  Unfortunately, the timetable generator is picky about pairs of trains stopping at exactly the same stations.  To make that work, I copied 21sked.txt to 321sked.txt (321 and 322 were older train numbers for set-out coaches that ran just between Chicago and St. Louis), made the train number and train name changes, deleted all the data after St. Louis (including the St. Louis departure day and time), and added stops at Summit and Dwight, but with neither arrival nor departure times (because the Texas Eagle doesn’t stop at those two stations).  That gave me:

* Schedule For Train 321.           Formatted Data
* Texas Eagle (Chicago-St. Louis only)  (PDF Schedule)
* +---------------- Station Code
* |    +----------- Schedule Arrival Day  
* |    |  +-------- Schedule Arrival Time
* |    |  |     +----- Schedule Departure Day
* |    |  |     |  +-- Schedule Departure Time 
* |    |  |     |  |     +------------- Actual Arrival Time
* |    |  |     |  |     |     +------- Actual Departure Time
* |    |  |     |  |     |     |     +- Comments
* V    V  V     V  V     V     V     V
  CHI  *  *     1  145P              CT
  SMT  *  *     1  *                 CT
  JOL  *  *     1  240P              CT
  DWT  *  *     1  *                 CT
  PON  *  *     1  326P              CT
  BNL  *  *     1  401P              CT
  LCN  *  *     1  430P              CT
  SPI  *  *     1  506P              CT
  CRV  *  *     1  538P              CT
  ALN  *  *     1  609P              CT
  STL  1  713P  *  *                 CT

I then ran the command, make-timetable 321 302 -o 321-302sked.html”, to get:

Timetable for Trains 321 and 302,
the Texas Eagle (Chicago-St. Louis only)
and Lincoln Service

321🠠 Train Number 🠢302
Read DownStationRead Up
DayTimeCodeNameTime
Zone
TimeDay
113:45CHIChicago - Union Station, ILCT12:051
 SMTSummit, IL11:29
14:40JOLJoliet, IL11:04
 DWTDwight, IL10:17
15:26PONPontiac, IL09:59
16:01BNLBloomington-Normal, IL09:30
16:30LCNLincoln, IL08:56
17:06SPISpringfield, IL08:32
17:38CRVCarlinville, IL07:52
18:09ALNAlton, IL07:25
19:13STLSt. Louis, MO06:40

(The timetable generator has no problem when the left and right trains have different names, and it’s happy to just leave a time cell empty when there’s neither an arrival nor a departure time, but fixing the “gotta be all the same stops” issue is coming Real Soon Now.)


Appendix C:  if Amtrak’s station codes change

You’ll probably never need to do this, but just in case…

First, get the current list of Amtrak stations from https://juckins.net/amtrak_status/archive/html/stations.php; then in your browser, highlight just the code/name pairs and copy them to a plain text file on your hard drive.  (Or if you think it’s easier, you could Edit->Select All and Edit->Copy into some text editor and then delete all the lines at the beginning and end except for the code/name pairs.)

Then compile make-sta-codes.cpp and run it, redirecting the station list you got from juckins.net to the standard input, and redirecting the standard output to station-codes.inc.  When that’s done, recompile make-timetable.cpp.

All this program does is to read lines that have the form, “code[horizontal tab]station name”, sort them by station code, and reformat them to “{"code","station name"},” to be #included in an array initializer.

If you care, the actual code in make-timetable.cpp is just
struct sta_codes
{
    const char* code;
    const char* name;
};
static const sta_codes stations[] =
{
    #include "station-codes.inc"
};


Appendix D:  build instructions for non-geeks

If you already know how to compile C++ programs, and that’s probably most folks who are running on some Linux platform, chances are that you already know all that I’m about to say.

If you’re a non-geek who’s using a Mac, you might already have what you need.  Just put the make-timetable.cpp and station-codes.inc files in whatever directory to want to use for these source files, open a bash shell window, cd to the directory you chose, and try

g++ make-timetable.cpp
If that works, you will have created a file named a.out.  Just mv a.out to a file named make-timetable (with no extension) in some directory that’s in your PATH environment variable, and you’re done.

If that doesn’t work, you’ll need to download and install the latest and greatest GCC.  If you don’t know what I’m talking about, that’s OK; somebody at your local Apple store, or any other computer repair shop that works on Macs, should be able to install GCC for you.

If you’re running Windows, you’ll need to download and install Microsoft Visual C++.  Again, there will probably be somebody at your local computer repair shop who knows how to do that.  All you need is the version that lacks all the libraries that you need to create Windows programs since you’ll only be creating a console app.  IIRC, that version is free (but YMMV).

The Windows command to compile the program is

cl /EHsc /W4 make-timetable.cpp
If the compiler has been installed correctly, that will run without any errors or warnings and create two files, make-timetable.exe and make-timetable.obj.  Move the .exe file to some directory in your PATH environment variable.  You can just delete the .obj file.


All suggestions and corrections will be welcome; all flames will be amusing.  Mail to was@pobox.com.