News:

Simutrans Wiki Manual
The official on-line manual for Simutrans. Read and contribute.

Line Scheduling for simutrans standard

Started by THLeaderH, April 29, 2019, 12:51:38 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

THLeaderH

Today, I post a patch that realizes line scheduling in simutrans standard. It is needless to say that this feature is brought from simutrans extended.

Standard and extended have different design philosophy. Standard provides relatively simple and stable gameplay, while Extended realizes sophisticated simulation and more reality. Many players, including me, prefer the standard, but there are so many voices that desire the line scheduling feature of simutrans extended. So, I brought this feature and I'd like to have a discussion about it.

The attached patch contains minimum functions to do a line scheduling in simutrans. It does not have any advanced scheduling feature such as time measurement, departure slot per a line, and "not enough trains" alert in the extended. The functions are basically same as those of extended, but there are two different points.

  • Schedule is managed with a new time unit, although I haven't named this new time unit. In the figure below, one month is divided into 1440. The divisor is a configurable parameter "spacing_shift_divisor". With this time unit, players can plan a train schedule with much simpler calculation compared to extended, which defines one month as 6 hours and some minutes.

  • Delay tolerance feature is added. In simutrans-extended, delay is not allowed at all. Even if the delay is only a single second, the train is forced to wait until the next period. My version has a parameter called "delay tolerance" and players can specify how long the delay is allowed. This realizes more flexible scheduling. In the figure below, the duration of one month is 1440. There are 6 times when convoys are allowed to depart. Spacing shift is 25, and delay is allowed up to 50.


Unfortunately, the attached patch is based on r8745 although the latest version of nightly trunk is r8755. This is due to the de-sync problem between svn repository and the git mirror. This patch might cause some conflicts when it is merged to r8755, because there were some big changes such as multi-tile city buildings and code maintenance between r8745 and r8755. If necessary, I'll post a patch that is based on r8755, referencing the svn repository.

Leartin

Quote from: THLeaderH on April 29, 2019, 12:51:38 PM
Schedule is managed with a new time unit, although I haven't named this new time unit. In the figure below, one month is divided into 1440.

I think there are two ways to go with this. On the one hand, one could use arbitrary additional units - but if so, I'd make sure those are always of the same real-time length (at same gamespeed) and uneffected by bits_per_month. This would be due to vehicle movement being always the same as well, changing bits_per_month should not affect them, therefore not affect schedules either.

On the other hand, why use arbitrary additional units when there are already time units in the game? If time is displayed as days and hours like in the screenshot, use days and hours for the schedule. If it's hours and minutes, use hours and minutes for schedules - and so on.

Ideally, though - I would like to see units of fixed real-time length that do not themself change with bits_per_month, but which are converted for display into the correct amount of the chosen display method (show_month). So if you set up a schedule where every 10 days a train moves out and then increase bits_per_month by one, the schedule would work the same in real time by having a five day rythm now, or if you decrease bits_per_month by one instead, it would be shown as a 20-day-rythm.


THLeaderH

I think it is a good idea to use real-time length for schedule to make schedule independent of bit_per_month. Ticks, the internal time unit of the game engine, can be a reasonable choice for this. In practice, 1000 ticks (1000 ms) should be 1 unit in schedule, considering the resolution of time scheduling. Spacing_shift_divisor becomes period_length of the schedule.

Using time units in the game such as days and hours might be difficult because of tiny space of the schedule window. I don't come up with a reasonable input style if days and hours in the game are used as the time unit of scheduling.

I think it's enough to display real-length time as the time in schedule because it's easy for players to treat time in real-length seconds rather than in days and hours in the game when players plan the line schedule.

DrSuperGood

Quote from: THLeaderH on April 29, 2019, 03:44:11 PM
I think it is a good idea to use real-time length for schedule to make schedule independent of bit_per_month. Ticks, the internal time unit of the game engine, can be a reasonable choice for this. In practice, 1000 ticks (1000 ms) should be 1 unit in schedule, considering the resolution of time scheduling. Spacing_shift_divisor becomes period_length of the schedule.

Using time units in the game such as days and hours might be difficult because of tiny space of the schedule window. I don't come up with a reasonable input style if days and hours in the game are used as the time unit of scheduling.

I think it's enough to display real-length time as the time in schedule because it's easy for players to treat time in real-length seconds rather than in days and hours in the game when players plan the line schedule.
Maybe allow the time input to be flexible? For example in months, hours, minutes, seconds or ticks. One would have to use a text field for this. Some examples of inputs are below.

0.1M -> 10 convoys per game month
5m -> a convoy every 5 game minutes
0.1h -> 10 convoys per game hour
10s -> a convoy every 10 seconds.
25736u -> a convoy approximately every 25,736 internal time units (~game milliseconds?).
25t -> a convoy every 25 ticks (25 update cycles).
5m 30s -> a convoy every 5 minutes and 30 seconds or 330 seconds.

I am not sure how user friendly this would be.

If using seconds it is important to elaborate that these are "game seconds" and not real time seconds. The physical duration of a game second varies with game speed.

THLeaderH

IMHO, values should be set with a number input. With a text field, increment buttons is not available. Also, we have to validate user's input every time. Input errors and error messages will be annoying for users too.

QuoteIf using seconds it is important to elaborate that these are "game seconds" and not real time seconds. The physical duration of a game second varies with game speed.
Yes. This should be a reasonable choice as a time unit of the line scheduling.

Dwachs

Can you explain, what spacing/shift/delay means?

There is already an artificial time of day, see the "3:22 pm" in your screenshot. Why not use this? (Or adjust it, if the scaling does not fit)
Parsley, sage, rosemary, and maggikraut.

Leartin

Quote from: Dwachs on April 30, 2019, 07:02:59 AM
There is already an artificial time of day, see the "3:22 pm" in your screenshot. Why not use this? (Or adjust it, if the scaling does not fit)
I can think of two reasons:
A) It's dependent on show_month what's displayed there. There is also a setting where each month has 24h with no days shown. So it either has to have the same flexibility, or some display styles need to go.
B) Schedules based on these time units would be functionally different based on bits_per_month, and bits_per_month should not make any functional difference.

THLeaderH

Quote from: Dwachs on April 30, 2019, 07:02:59 AM
Can you explain, what spacing/shift/delay means?

Let me explain the meanings of spacing, shift and delay tolerance with the second image attached to the first post.


In this schedule, spacing is set 6. Assuming the length of one month as 1440 (=24hours*60mins), convoys are allowed to depart at every 240 (=1440/6). Since the spacing shift is 25, convoys are allowed to depart at the following times.

  • 25 (=240*0 + 25)
  • 265 (=240*1 + 25)
  • 505 (=240*2 + 25)
  • 745 (=240*3 + 25)
  • 985 (=240*4 + 25)
  • 1225 (=240*5 + 25)

In the schedule, delay tolerance is 50. This means a departure can be delayed for up to 50. If the convoy arrives at stop a at 280, the convoy departs stop a immediately because the delay from time 265 is 280-265=15, which is less than delay tolerance 50. If the arrival time is 400, delay is 400-265=135, which is greater than 50, then the convoy waits for the next departure time, 505.


As for the reason for not using existing time units, Leartin's comment is to the point. There are several show_month style. If we use these time units, we have to support all show_month style in the tiny schedule window. DrSuperGood suggested a method to deal with this problem using a text field, but I think number inputs should be used for the scheduling as I put it before.

Dwachs

What is the meaning of [  * ] in the schedule window?

I suggest to add a line below the settings, which shows the scheduled departures. I.e.

Scheduled departures at 25, 265, 505, ...


How does this interact with 'Minimum load' and 'month wait time'? What if the convoy if fully loaded then it should leave regardless of schedule(?)
Parsley, sage, rosemary, and maggikraut.

THLeaderH

[ *] indicates that wait_for_time is set for this entry. simutrans-extended does the same thing.

Showing scheduled departures can be nice, but if the spacing value is large, such as more than 10, all departures cannot be displayed at a same time. Displaying only the next departure time would be reasonable.

To understand the interaction with minimum_load and maximum_wait_time, please refer the code below.

bool can_go;
sint64 go_on_ticks = 0;
if(  schedule->get_current_entry().wait_for_time  &&  schedule->get_spacing()>0  ) {
// consider spacing
// subtract wait_lock (time) from spacing_shift
const sint32 spacing_shift = schedule->get_current_entry().spacing_shift * welt->ticks_per_world_month / welt->get_settings().get_spacing_shift_divisor() - time;
const sint32 spacing = welt->ticks_per_world_month / schedule->get_spacing();
const uint32 delay_tolerance = schedule->get_current_entry().delay_tolerance * welt->ticks_per_world_month / welt->get_settings().get_spacing_shift_divisor();
go_on_ticks = ((arrived_time - delay_tolerance - spacing_shift) / spacing + 1) * spacing + spacing_shift;
can_go = welt->get_ticks() >= go_on_ticks;
can_go |= (loading_limit > 0  &&  loading_level >= loading_limit);
} else {
can_go = loading_level >= loading_limit;
}
can_go |= no_load;
can_go |= (loading_limit > 0  &&  schedule->get_current_entry().waiting_time_shift > 0  &&  welt->get_ticks() - arrived_time > (welt->ticks_per_world_month >> (16 - schedule->get_current_entry().waiting_time_shift)) );  // maximum_wait_time condition


OR is taken for each condition. When any of these conditions, spacing, minimum_loading, and max_wait_time, convoys are allowed to depart.

THLeaderH

#10
While trying to make schedules independent from bit_per_month, I faced with a difficulty to do this. In my current implementation, the "spacing" parameter means how many times convoys are allowed to depart. This is affected by bit_per_month changes.

A possible solution for this problem is holding the number of departures per a month on bit_per_month=20 basis. For example, if bit_per_month is 19 and user set "spacing" 3, the value is held as 6 internally because the internal value is bit_per_month=20 basis. However, if bit_per_month is 21 and a user set spacing 15, the internal spacing will be 7.5 and this is no longer integer. Internal value problem can be solved by making bit_per_month basis larger, but if a user changes bit_per_month to 20 from 21, the actual "spacing" will be 7.5 and this cannot be displayed because it's not integer.

Another solution is specifying the interval between the departures instead of the number of departures in a month. For example, assuming 2^20 ticks as 1440, setting "spacing" 700 means the interval is 700 and therefore 1440/700 = 2.06 convoys per a month are allowed to depart. In this case, the departure time varies with the month like 0 -> 700 -> 1400 -> 660 -> 1360 -> 620 -> ... How can we define the time 0 for the schedule?

To be honest, I am wondering whether we really have to make schedule independent from bits_per_month, since bits_per_month is a parameter that affects wide range of simutrans behavior and it is rarely changed after a game starts.

prissi

The thing with scheduling is, that it is actually reducing the effectiveness of a transport network, since it artifcially clamp down throughput. For that reasons similar patches has been denied in the past (e.g. the convoi spacing patches). Furthermore the dialoge is way too complicated for a casual player, I fear.

Something like

Depart at
   Minimum load %%%
   After dd days and hh:mm waiting (instead of 1/n of a month)
   At hh:mm every zz days (always counted from beginning of the year)

may be still understandable. Also with setting waiting time short enough, the tolerance is not really needed.

Leartin

Quote from: prissi on May 01, 2019, 03:23:52 PM
The thing with scheduling is, that it is actually reducing the effectiveness of a transport network, since it artifcially clamp down throughput. For that reasons similar patches has been denied in the past (e.g. the convoi spacing patches).
That's true for a single line/vehicle, but does it hold true for a network?

Think of it as a bucket brigade. Of course each individual is clamped down, because there is a rhythm to it and everyone performs the same task, even if they could do more. Yet it's more effective than everyone carrying their own bucket at their unclamped, full potential.
Since the schedules of different lines can be adjusted to each other, I think you can manage some things. For example, you might be able to save in platforms if you know trains won't arrive at the same time. You can save station extensions if trains arrive at similar times, such that what one brings, the other carries away immediatly. Even the "regional and express train in same direction"-problem can be at least improved.
And the best part: Even if I'm wrong, it would not matter, as long as nobody can be sure about it. As long as there is a chance that schedules help optimizing a network, people will try to do it, and tinkering around is half the fun.


As for how to display it: What if it's a seperate dialog or a completely hidden area? "Scheduled Departures" as a simple button to click, that opens a new dialog/area with all the scheduling options. Therefore, all the user sees is a button that tells him that schedules are a thing, but it does not distract them too much. They can open it, decide whether it looks too complicated for them, and proceed with or without them.
If this was the case, space would not be an issue. Therefore, one could show a list of all departures, based on show_month-settings - if this could change in real time while settings are adjusted, both spacing and shift become self-evident. It would also help in case someone wants to have a schedule in each station, if you could open several of those dialogs to compare them with each other. (Not sure, but if I use schedules, I think I would want them in every station along the line)
Additionally, it might allow for a manual schedule - which could be completely pointless for effective gameplay, but might be a gift to model-railway-players that seek to recreate real lines.

THLeaderH

Quote from: Leartin on May 02, 2019, 09:05:36 AM
As for how to display it: What if it's a seperate dialog or a completely hidden area? "Scheduled Departures" as a simple button to click, that opens a new dialog/area with all the scheduling options. Therefore, all the user sees is a button that tells him that schedules are a thing, but it does not distract them too much. They can open it, decide whether it looks too complicated for them, and proceed with or without them.
If this was the case, space would not be an issue. Therefore, one could show a list of all departures, based on show_month-settings - if this could change in real time while settings are adjusted, both spacing and shift become self-evident. It would also help in case someone wants to have a schedule in each station, if you could open several of those dialogs to compare them with each other. (Not sure, but if I use schedules, I think I would want them in every station along the line)

I think hiding time schedule settings reasonable for casual players. So, how about make this like the two images below?


There is a "Time Schedule" button in the conventional scheduling window. A player who wants to set departure time for this schedule clicks this button and opens the time schedule window.


The time schedule window is like this. A player can specify the frequency per a month (spacing), wait_for_time, spacing shift, and delay tolerance. Next departure slots and the deadlines for the next departure slot are displayed for each entry, using in-game time units.

I think casual players do not get confused and advanced players are satisfied with this way.

Leartin

For completions sake, a mockup of what I meant: A dialog for each stop where you can actually see the departures over the month, as displaying them should allow the player to get a better grasp on what's going on.

THLeaderH

Although assigning one window to one entry enables displaying all departure times in a month, I think it would be bothersome when players set departure time for many schedule entries since players have to open the time schedule window many times.

And, could you tell me the meaning of "use manual timetable"? Is it a button to specify a departure time that will be used only once?

Leartin

#16
With a manual timetable, you would disable the automatic spacing and instead define each departure time manually.

Practical use could be if someone wants to mix two lines in parallel direction. Eg. four times of the month, Line 1 goes from A to B, and twice Line 1b goes from A to B and continues to C. You'd want Line 1 and Line1b to be evenly spaced together, which can't be done automatically - hence an option to do it manually.

Players who seek to recreate a real-life network might be able to use the real-life timetable for their trains, if they use adequat bits_per_month and show_month settings. Real-life timetables are not regular, so you'd need to set each entry manually.



I don't know how flexible the dialog system is and what you can do with it. You are right that opening and closing many dialogs could be tedious, but perhaps there are different solutions:
- open the timed schedule dialog by ctrl-click on the stop in the line dialog
- use the timed schedule button not to open a dialog for the current station, but to toggle whether the timed schedule dialog should open upon clicking on a stop in the schedule.
- have but one timed schedule dialog which always shows the stop you click on in the other dialog

Of course your proposal is more efficient to use as long as you know how to use it.

Vladki

The example you mentioned with lines a-b and a-b-c cen be perfectly done with automatic schedule. Set both at 2 departures per month and set different offsets for them.

Leartin

#18
Quote from: Vladki on May 03, 2019, 09:15:09 AM
The example you mentioned with lines a-b and a-b-c cen be perfectly done with automatic schedule. Set both at 2 departures per month and set different offsets for them.
Maybe I said it unclearly, but Line 1b was not included in Line 1. So A-B is supposed to see 6 trains, and you can't automatically set four departures that leave space for two more.
Though this is more an excuse, since it's not benefitial enough to warrant the extra work needed. It's for model railway players, and if someone can make use of it elsewhere, it's just a bonus.



So I realize I just assumed something, and I'm not sure if that's how it works. I assumed that the departure times are simply the only times a train is allowed to leave. Is that it, or is there also a restriction that for each time slot, only one train is allowed to leave the station?
Basically, if you go with a 1440-tick-month and set four departures per month, but the tolerance to 360, would that be like having no schedule at all (since trains can leave any time due to tolerance) or would it still make sure that there is only one train per quarter of the month? (I never played with Extended so I don't know how it works, sorry if it's obvious to everyone else)

Vladki

Ah I have overlooked that one line was supposed to be 2x a month and the other 4x times a month. That would be more tricky but still possible (setting one to 6x a month and letting it miss two departure slots, which will be occupied by the other line.)

Leartin

Quote from: Vladki on May 03, 2019, 11:31:31 AM
Ah I have overlooked that one line was supposed to be 2x a month and the other 4x times a month. That would be more tricky but still possible (setting one to 6x a month and letting it miss two departure slots, which will be occupied by the other line.)
You sure can do that, or you use three lines total, each with a shift of a third of the month. While setting it manually might feel better in these cases, I won't fight that it's not really needed for gameplay.

THLeaderH

I understand and support Leartin's idea. There should be at most one timed schedule dialog and it shows the stop which a player click in the conventional schedule dialogue. The amount of steps to set a time schedule in this method is almost same as in simutrans-extended approach, since simutrans-extended requires selecting an entry to set spacing and spacing shift. Leartin's idea enables us setting a time schedule whose interval is not constant thanks to manual timetable feature. Though this can be realized using multiple line schedules, non-constant interval schedule occurs very frequently in an actual gameplay. And I think this should be able to be handled with a single line time schedule.

If there is no objection to his idea, I would like to start the implementation. How do you think?

Vladki

I'd like to see the tolerance of missed time slot in extended too

THLeaderH

About the change of bits_per_month...

There is a difficulty described in this post for timetable to follow the change of bits_per_month. The change of bits_per_month also breaks manual timetable because the length of a month changes . Is it acceptable not following the change of bits_per_month? If a player change bits_per_month, timetable schedule will break, however, I believe players rarely change that after they start a game.

Dwachs

Imho, do not worry about bit-per-month changes. Who knows what else would break if this changes during a running game.
Parsley, sage, rosemary, and maggikraut.

Vladki

Did anyone try what will changing the bit per month do with timetables in extended?

I think it would be very unusual to change bpm in developed game.

TurfIt

IMHO, a schedules purpose is to affect/control vehicle movement. Vehicle movement is independent of months, and hence bits_per_month. The reason for a vehicle to move, go pick up some cargo, is also independent from months. Cargo generation and vehicle movement both operate on the same timescale - realtime.  So, any implementation of scheduling that ends up dependent on bit_per_month is flawed....
While changing this in an established game might not be common, there's no reason to purposely break existing functionality.

Quote from: THLeaderH on May 01, 2019, 11:50:57 AM
Another solution is specifying the interval between the departures instead of the number of departures in a month. For example, assuming 2^20 ticks as 1440, setting "spacing" 700 means the interval is 700 and therefore 1440/700 = 2.06 convoys per a month are allowed to depart. In this case, the departure time varies with the month like 0 -> 700 -> 1400 -> 660 -> 1360 -> 620 -> ... How can we define the time 0 for the schedule?
ms between departures is sensible. If the allowed interval is restricted to powers of 2, the GUI can easily translate to a departures / month scheme (or months / departure possibly...) for any bits per month setting.


Quote from: THLeaderH on April 30, 2019, 09:53:07 AM
To understand the interaction with minimum_load and maximum_wait_time, please refer the code below.
This code cannot work, similar was previously removed. See: https://forum.simutrans.com/index.php/topic,13450.0.html
Adds/subtracts/multiplies/divides on a mixture of sint32 and uint32, all put in sint64 compared with a uint32 that can and does rollover, nope.




Leartin

Quote from: TurfIt on May 15, 2019, 08:40:59 PM
IMHO, a schedules purpose is to affect/control vehicle movement. Vehicle movement is independent of months, and hence bits_per_month. The reason for a vehicle to move, go pick up some cargo, is also independent from months. Cargo generation and vehicle movement both operate on the same timescale - realtime.  So, any implementation of scheduling that ends up dependent on bit_per_month is flawed....

True, but a schedules purpose is also to affect/control movement of vehicles relative to each other, which can best be coordinated by using an universal cycle, rather than individual cycle lengths. If you were to merely state a real-time between departures without such an universal cycle, the "offset" would be meaningless, as there is nothing to offset from, and it would be somewhat hard to coordinate schedules.
One could introduce an universal cycle based on real time rather than length of months, but if you were to do that, you'd have to make an arbitrary decision of how long that cycle would be, and you can be certain that you can't choose a length everyone would like, so eventually someone will come up with the genius idea to create a setting to let the player choose how long the real-time-cycles ought to be. Besides, the game would have to somehow display those cycles somewhat prominenlty, most likely next to the in-game-time, despite them being completely pointless for anyone not using schedules.

prissi

The display can be always in months/hours units, but internally using ms or ticks is indeed sensible. Using ticks internally would easily allow for departures every two months, like for synchronising long distance shipping lines.

Vladki

If you use ticks or real time, what will be the reference time 0?

prissi

The reference will be always tick 0, of course. Because the departure every 2 month will be translated in departure e.g. every 1440 ticks. When the bits_per_month is changed (for instance by 2), the schedule will be departure every 1/2 month. Also if the old 3 day 24h a month display is activated, it would be instead depart every 3 days.

That would also take care of february, which is the same length in ticks than January, despite being three days shorter. The schedule would be probably display as departure every 15th (which is internally save as every xxx ticks with an offset of yyy).

Vladki

And how does the tick 0 sync in network games or between saves?

What is tick 0? Is it the moment when the game was created? Loaded?

Leartin

Say a cycle 2^22 ticks long, independent of the bits_per_month setting.
If you happen to play with 22 bits per month, it syncs up perfectly
If you happen to play with 20 bits per month, you set the schedule for four months at once.
If you happen to play with 24 bits per month, you can only set the schedule for a quarter of a month, and the other quarters will be repetition.

Tick 0 could be something like the first tick of the first month of year 0. That would mean with 20 or 21 bits per month, tick 0 would be (beside others) the beginning of each year, with 19 bits per month, it would be the beginning of each even year, with 18 bits per month, it would be every fourth year, and the gap doubles from there. This would be consistent for network games, and can be grasped by a player.


As far as using such a system internally, sure. However, one could be extra clever about it.
> The ticks don't sync up to displayed time nicely. This would not matter if the player could actually operate at tick precision and choose a value between 0 and 4194303, but that sort of precision seems too much when practically, it's probably enough to go with seconds. I suggest a time unit consisting of 728 ticks. Of this time unit, 5760 would make up a cycle. If that cycle lines up with the month, each unit would be displayed as 7 minutes and 30 seconds. Therefore, at bits_per_month=21, you can use quarter hours to set your schedule, and at bits_per_month=20, you still use full hours. It's pleasent down to 17bpm and 8h precision, though I wonder if such short bpms are used.
Of course it does not line up that nicely in reality, using 5760 units of 728 ticks length does not fill all 22bits, but rather leave 1024 ticks unaccounted. Those are just the last bits in which no schedule happens. The imprecision you get from that is about a second, it hardly matters in practice.
A train schedules for time.unit 5759 would be displayed as "30th day, 23:52(:30)", but it would actually depart at tick 4192552, which in a 30-day month would be "30th day, 23:42". Really insignificant, considering we also have 31-day-months, at which the same train would depart on the 31st, but we surely don't want the displayed schedule to shift likewise.

> Even if the cycle has a fixed length internally, that might not need to be shown to the player. I think it would still make more sense for them to say "I want 3 trains per month" rather than "I want 12 trains over the course of a cycle that is 4 months long". This option should be unchanged. If you play with bpm 23, you simply can only use even numbers for the number of trains per month, since it's the same cycle twice, and divisible by 4 in bpm 24. However, this would not go the other way, with quarter-trains-per-month in bpm 20. Likewise, under normal circumstances a manual timetable would always be planned for a month, and if a cycle contains several months, the others are simple repeats. Some kind of "Use monthly schedule" setting which is on by default, and needs to be turned off to allow time units that reach in the next month, while simultanously turning the month-cycle off. Essentially, from the players perspective, everything is set up using in-game time values and monthly cycles, while in the shadows, it's converted to ticks on a fixed cycle length.

prissi

I see rather the need to add also months to a schedule. Departure every second month at xx:yy. And voila, all these problems are gone. And the trouble with this only appears if one tinkers with bits_per_month after starting a game.

Leartin

Quote from: prissi on May 27, 2019, 12:22:08 PM
Departure every second month at xx:yy. And voila, all these problems are gone. And the trouble with this only appears if one tinkers with bits_per_month after starting a game.

Yes, sure, that was the idea in the first place, before Turfit suggested otherwise. But that does not solve everything, we still need to talk about precision, conversion, and how it is saved.

1) -> If you let the player set a time down to the minute, and want the train to actually leave at that time, you need very high precision. There are 43200 minutes in a month, after all, so that's the least amount of ticks per month to do it for real, even though that's not actually required.
2) -> If you let the player set a time down to the minute, but the train only needs to leave around that time, not precisely, you can go down to 2890 ticks and have the train leave 15 minutes late (which is not relevant to gameplay). But if so, you need to store the actual time the player set, if only to display it back to them, otherwise it becomes really infuriating. [EG: The graphic program GIMP does everything in pixel measurements. If you want to set your canvas in millimeters, it will always convert to the nearest value possible with full pixels - eg. 99,84mm instead of 100mm. I know why, but it's inconvenient. Photoshop shows the entered value of 100mm. I'm sure internally it does the same thing, but it doesn't bother me with it.]
3) -> If you let the player set a time via using ticks, they are restricted to 15min steps, but at least there is no suggestion that it can be set any better. Though if ticks have a constant length no matter the bits_per_month setting, the percieved in-game precision changes with the bits_per_month setting - 30min-steps, 1h-steps, 2h-steps, 4h-steps,...