News:

The Forum Rules and Guidelines
Our forum has Rules and Guidelines. Please, be kind and read them ;).

PR#504: New date format

Started by Matthew, February 16, 2022, 07:59:55 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Matthew

You have probably all heard the one about two people who were walking in the woods when they suddenly saw a dangerous bear. One of the people started running away. The other one shouted, "You can't run faster than that bear!"

The runner shouted back, "I don't have to run faster than the bear; I just have to run faster than you!"

This is a patch for a new date display format, called DATE_FMT_64_SECOND_MINUTE because it displays times based on 64 seconds/minute. That may seem ugly, even weird. I agree that it's far from ideal, but it's no worse than, and in some respects better than, the current default format (DATE_FMT_INTERNAL_MINUTE). It can't run faster than the bear, but I think it's faster than the other person.

No worse than the existing default format
This is just a date display format. If I have implemented it properly, it should not change anything about the game's internal calculations. So it should never cause desyncs and each player can choose what date format to see on their own PC. If you hate this format, just ignore it. :-P

And the current default format has one big advantage: it exists. It was created by Inkelyad in 2011 as part of Extended's timetabling feature. Although Standard has recently added timetabling, for the past decade it has been Extended's star feature; I could never go back to playing Standard without timetabling. So thank you, Inkelyad and DATE_FMT_INTERNAL_MINUTE, for the countless hours of pleasure that you have brought to many people.

But it is not without its flaws, which this patch partially remedies.

No worse than than inconsistent hour lengths
The first flaw is that DATE_FMT_INTERNAL_MINUTE displays hours with inconsistent lengths. Some hours are 24 minutes long and some hours are 60 minutes long (so each 'economic' month equals 6h24m00s on the 'short' timescale). If you think it's ugly having a minute of 64 seconds, how ugly is having an hour of 24 minutes? And how weird is having inconsistent hour lengths?

Excursus: A history of the world in hours
Actually, inconsistent hour lengths are very weird, if you look through history. Lots of calendars have inconsistent month lengths (31 days in January, 28/29 in February, etc.) because the lunar cycle and the solar cycle don't line up. An ugly date format is unavoidable because of the universe's internal calculations. :-P And it's actually quite common for hour lengths to vary. Pre-modern China, the classical Mediterranean, and rabbinical Jews all used hours that varied, so there were (for example) 12 hours of daylight and 12 hours of night, with the hour length changing with the latitude and season. But each of the day hours and night hours was consistent; they did not reduce the last hour of the day to 24 minutes when winter came! The canonical hours (prayer times) of the Christian church were not originally fixed at specific points, but as early as the 6th century AD the daytime prayers were set three hours apart, dividing the day into periods of equal length. The naval system of dog watches divides the day into 'watches' of 2 or 4 hours, but this is actually the exception that proves the rule. Navies needed to have an odd number of periods ('dog watches') in each day. So did they make one of the watches 24 minutes long? No, they divided one watch in half, so that each watch is an exact multiple of periods of equal length (2 hours). Inconsistent hour lengths are really, really weird.

And they cause real problems in gameplay.

Better than timetabling with inconsistent hour lengths
Extended's amazing timetabling feature relies on dividing the 'economic month' into 1,440 intervals. The default settings for bits_per_month (bpt) and meters_per_tile (mpt) create 23,040 seconds/month. That means each interval is 16 seconds — but DATE_FMT_INTERNAL_MINUTE uses base 60 and 16 is not a factor of 60. Everyone reading this knows that if you have two departures/month, the second one is at 3:12:00. But if you have six departures/month, what time is the last one? No cheating, do you know immediately? If you have five departures/month, what time is the fourth one? Do you know, right now? Add offsets and it gets even more complicated. If you have half-hourly departures with an offset of 3 minutes, what time is is the second departure in the second half of the month? §

The result is that trying to run a traditional railway with services of different speeds and intervals just becames a nightmare to calculate. I know, because I have tried to do it. You have to get really good at the 16 times table. Most players on Bridgewater-Brunel don't even try and run metro-style lines with 'clock face' timetables (where 'clock face' means departure times like 3:12 and 4:48!) with a single line on each stretch of track. Of course, there are good reasons for metro-style timetables, and diversity in playstyles is good. But I think the difficulty of timetabling with inconsistent hour lengths and 60-second minutes discourages people from doing anything else. And many players are unsatisfied with this. I never use the default bpt and mpt settings in single-player because of the timetabling frustrations and new Extended players often find themselves confronting the difficult bpt settings to try to remedy this. Carl's popular GB Rail Map uses its own settings for the same reason.

With DATE_FMT_64_SECONDS_MINUTE, at Extended's default settings for bpt and mpt, then each economic month has exactly 6 hours of equal length. If you have 12 departures/month with a 3-minute offset, they are at 0:03, 0:33, 1:03.... I don't need to continue the sequence because you already know how it goes from real life! It's so simple.

The quid pro quo is that you will occasionally see values of 60, 61, 62 or 63 seconds in the game. But you will see them much less often you might expect, because the shortest possible interval or offset (1440/month) is 16 seconds, which becomes exactly ¼ of a minute. So we no longer need to pay close attention to seconds when timetabling. Instead of remembering 3:12:00, 5:20:00, and all the other ugly intervals, you just need to remember that a ¼, ½, and ¾ of a minute are 16, 32, and 48 seconds. You should no longer see convoys scheduled to depart at weird times like 2:57:12 or whatever.

No loss of precision
You should no longer see convoys depart at weird times.... but you will, unfortunately. In fact, if you set 6 departures/month in the Schedule Window, the game says that the first departure is at 0:59:63, not 1:00:00. That is not a new bug introduced by this patch. That's an existing bug that is somewhat hidden by the obscurity of the inconsistent hour lengths format. I think it exists because the game's internal time unit (ticks) is not a factor of any displayed time unit (hours/minutes/seconds) on the 'short' time scale. In 2011, Neroden wrote a comment in the code saying,

Quote from: Neroden"The rest of this is much weirder: there are by default (4096 / 180) = 22.7555555... ticks per second. This also needs to be changed because it's stupid".

I couldn't agree more. But Neroden has contributed code to LibreOffice and the Linux kernel. If he couldn't fix this quickly, then it's certainly too ambitious for my first patch! Incidentally, I think that number is now outdated, as I calculate that there are now 18.204444652 ticks per second due to other changes, but I could be wrong. The ratio appears to be calculated from integer magic numbers in the code, then stored as a float, then converted back to an integer for the display calculations ??? , which leads to the loss of precision seen in the Schedule Window.

I hope one day that we can tame the bear (fix the weird time ratio), but right now it's too dangerous for a newbie like me, so this patch just tries to run faster than the other person (improve the date format). Discussion about the time/ticks ratio can be continued on this thread.

No worse at handling tenths
You also shouldn't see :61, :62 or :62 seconds in other places, such as the Timing Data and Walking Distance to Nearest Halt tabs. Again, this is not a bug in this patch. It's because the game displays these using tenths of minutes, not down to the second. I don't know why; does anyone? Computers use binary, so using a decimal calculation gives no performance benefit (I can't see any way in which tenths enables bitwise calculations using powers of 2). Because 10 is not a factor of 64, there will be some loss of precision in these tabs, but did you even know that they used tenths of minutes before you read this? :-P The new format is no worse.

No worse at handling speeds
I know James has said in the past that fixing the inconsistent hour lengths is undesirable because it changes the relationship between the 'long' and 'short' timescales. This patch doesn't. I wondered if there might be some weirdness with speeds, so that a convoy travelling for 100 km at 100 km/h wouldn't have a journey time of 1 hour. To be honest, I haven't totally got my head around all the mathematics and conversion code, but so far in-game testing shows that the distances, speeds, and journey times in Timing Data roughly match up. I get small variations (about 2%) but that might be because the displayed speeds are averaged across three journeys.

In any case, how often do players ever need to be absolutely certain that a convoy travelling for 100 km at 100 km/h travels for exactly 1 hour? All in-game vehicles (even aircraft) have acceleration and deceleration, so players don't expect convoys to always travel at their maximum speeds. Any small loss of accuracy is nothing compared to the inaccuracy of inconsistent hour lengths, in my opinion.

Worse code
As this is my first C++ patch, there are certainly things that could be done better, and quite probably outright errors. You can see the changes. Feedback is welcome, but avoid the commit history if you are an experienced coder because it will make you cry and me die of embarrassment at all the newbie errors! :-P

My biggest dilemma was how to incorporate the new format into the date printing functions, because they are marked inline. I know that inline is only a hint and compilers will often ignore it, but I am sure that it's there for good reason. On the one hand, the function could check the current date format from env_t::show_month, but then it would be longer than the 1-3 lines that the Simutrans Coding Style rules allow for inline functions, and I think it adds lots of external links to different bits of code. On the other hand, the current date format could be passed to the date printing function from the calling function, but that requires duplicating the date format check in many different source files, in violation of the reusability principle. In the end, I used both approaches depending on how many calling functions they had.

Version number missing
I think that this patch will need a new minor version number because the new date format could be stored in settings.xml. I have not included that in this PR because Ranran has recently submitted two PRs with version number increments.

Conclusion
There is a dangerous bear (there is no perfect way to display times in sensible units given Extended's default settings and magic numbers). We can't tame the bear (bring internal and display times into a better ratio, using powers of 2). But we can run faster than the other person. I think DATE_FMT_64_SECOND_MINUTE is no worse than DATE_FMT_INTERNAL_MINUTE and makes timetabling convoys much easier, so I hope that it will be incorporated. Once players have tried the new format in the nightlies, I hope you will agree that it should be the default setting in all the paksets too, which is why this post is so long. :-P

§ The answers are 5:20:00, 5:7:12, and 3:51:00. Obviously. :-P
   But in DATE_FMT_64_SECOND_MINUTE, the answers are a nice round 5:00:00 and 4:48:00 and an easy-to-calculate 3:33:00.
(Signature being tested) If you enjoy playing Simutrans, then you might also enjoy watching Japan Railway Journal
Available in English and simplified Chinese
如果您喜欢玩Simutrans的话,那么说不定就想看《日本铁路之旅》(英语也有简体中文字幕)。

jamespetts

Thank you for this contribution. This is an interesting but highly complex topic. I think that much careful consideration will be needed to chase down possible anomalies that might arise from this: it is not immediately obvious whether there will be any, especially in relation to timing and speeds. One thing that we do need to know is what happens if a client is running the new format and the server the old format, or vice versa - is this possible? Has this been tested? Does it give rise to technical problems (e.g. loss of synchronisation)? What about two different clients running different formats? Does it give rise for the potential for player confusion (if one player refers to a particular time and it is rendered differently on one client than another)?

I should be interested in the results of these tests, and also others' views on this difficult and involved topic.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Mariculous

#2
From the code, this seems to be purely a display thing.
Nothing should change economically.

Speed/distance/time will be inconsistent in that matter as there are two different hour and minute units, one based on 60s per minute (as in km/h) and one based on 64s per minute (as in the time format)

Although it might feel strange, it might indeed be a good option to accept that rather small inconsistency (one display hour will relate to 1:04 "real" hours)

Some ppl on BB already use an hourly/half-hourly, quarter-hourly wording when they actually mean 1:04, 0:32, 0:16, simply because it's easier to use.
The new display date format will line up with this.

KneeOn

Matthew, when I get a chance i'll play and see how it feels however your detailed summary does make me think this should be standard formatting. Like you, I didn't play Standard until 123.0 because of the lack of timetabling but odd lengths of hours/days was less than ideal. I like the idea of normal hour lengths!

Is there any scope that, for display purposes, seconds 60, 61, 62 and 63 could be displayed as 59 and 00 eg:

01:00:60 and 01:00:61 would show as 00:01:59
01:00:62 and 01:00:63 would show as 02:00:00

Even if internally the minutes ended up being a few extra seconds long on occasion, if everywhere the time is shown it is shown as 00 or 59 then the format is still consistent.

The game might known that the departure is 01:59:62 but in the timetable window and game clock it will show 02:00:00. Players wouldn't necessarily notice the display trick, the timetable would work and the games timing system would be even prettier and neater.

PJMack

Quote from: KneeOn on February 17, 2022, 11:04:46 AMIs there any scope that, for display purposes, seconds 60, 61, 62 and 63 could be displayed as 59 and 00 eg:
If one were to do something like this, it may be better to have the "leap seconds" be at 8,23,38, and 53 seconds so that 15, 30, and 45 seconds are always at the 1/4, 1/2, and 3/4 minute markers exactly and the duplicated numbers be as far from the quarter minute markers as possible.

Quote from: Matthew on February 16, 2022, 07:59:55 PMAs this is my first C++ patch, there are certainly things that could be done better, and quite probably outright errors. You can see the changes. Feedback is welcome, but avoid the commit history if you are an experienced coder because it will make you cry and me die of embarrassment at all the newbie errors! :-P
As the resulting code is concerned, it overall looks good.  The two if statements in sprintf_time_secs could be combined and any DBG_DEBUG calls could be removed.  I would also recommend making an new branch with all the changes applied as one commit so the history does not end up in the master branch.  When I do development on simutrans-extended or pak128.britain, I have a private copy of each that I can make changes and commit to without any risk of accidentally uploading to github, then apply the changes using cherry-picking to the copy for uploading (using the -n flag when commits need to be merged), then pushing to github after a thorough test.

Quote from: Matthew on February 16, 2022, 07:59:55 PMMy biggest dilemma was how to incorporate the new format into the date printing functions, because they are marked inline. I know that inline is only a hint and compilers will often ignore it, but I am sure that it's there for good reason. On the one hand, the function could check the current date format from env_t::show_month, but then it would be longer than the 1-3 lines that the Simutrans Coding Style rules allow for inline functions, and I think it adds lots of external links to different bits of code. On the other hand, the current date format could be passed to the date printing function from the calling function, but that requires duplicating the date format check in many different source files, in violation of the reusability principle. In the end, I used both approaches depending on how many calling functions they had.
I think that was the right call.  The 1-3 lines is a bit dated and oversimplified guidance on when to use inline functions.  One could do a dissertation on when to and when not to inline a function and there would still be grey areas and unknowns!  I believe the 12 lines you currently have in sprintf_time_secs is safe for inlining in this particular instance and I would not too hesitant to expanding it if the "leap seconds" mentioned above were to be used.

Ranran

One concern for me is that if we implement this technique of window dressing only the time notation, it would be better not to include it in show_month option.
Mixing them increases the options as patterns occur in the time and date display.
This means that your current implementation will not provide the date format for Japan or other Asian countries. This is a fact that may be overlooked by those who are more familiar with European date notation. Therefore, the feature will not be provided to Asian people without adding the more show_month option.

In other words, if we implement a way to window-dress only the time notation, it may be smarter to separate the time notation from the date-time notation.

As far as the show_month option is concerned, extended is currently useless in practically all but two formats, and may not be maintained properly.
No one may be using options other than 8 and 9 in extended...