libspacetime - mkmarstime function
Wow, what a sprint!
Part of the C date and time functions is mktime. It takes a struct tm object (which is a “broken down” time structure), and converts it into the time_t format (seconds since 1970). For libspacetime and the Darian Calendar, we need mkmarstime to track time on Mars.
In some ways, this ended up not being harder than I thought it was, and in some ways it did.
Leap Years
In the Gregorian Calendar, we have leap years every 4 years - except when the year is divisible by 100, unless divisible by 400. Yeah, it’s confusing.
The Darian Calendar, in it’s wording from the website and also Wikipedia confused me. I thought Intercalation was the length of a year, but no, it’s actually just getting the # of leap years that have passed at a given year number.
Darian Calendar rules are actually, every odd numbered year is a yeap lear, except for decades (10, 20, 30). Exception to that is if the year is divisible by 100, and again for divisible by 1000.
In the commented code, you can see how I put down my train of thought, but ended up coming to what the actual source was anyway.
Basically, you find the number of leap years, multiply by 669 days, then non-leap years, multiply by 668.
Fun fact: Glibc in its tm structures, according to POSIX specs, starts the year at 0. I believe it is because it could make those numbers fit in a smaller data structure. For us, the Darian year is 221. I guess I could maybe try to shave it down? But these are things I’ll have to decide before any release.
Months
Every month has 28 days, except for the last month in each “quarter”, which has 27.
You could calculate this, but Glibc, for the Gregorian Calendar actually has a static table that lists the amount of days since each month starts. This way it doesn’t have to do the multiplication every time.
I was doing it manually, and I was going to write out the expressions - 281, 282, etc. but it got complicated when also having to add like, 287 + (271) and I didn’t know which I was on track for. By using the example website, I got the numbers by manual conversion.
Leap Days
The table makes sense in Glibc for another reason: The leap day in the Gregorian Calendar is so early in the year, it shifts every day forward by one.
In the Darian Calendar, the leap day is actually at the end of the last month of the year. So we don’t need to store duplicate entries, or actually really worry about it for this function. (Not sure whether it is my job to handle invalid values). But basically if the current year is a leap year, we can still work as normal, and then just add on the day as requested. Nice!
The rest
Days, hours, minutes, seconds are all as normal.
The epoch
The Darian Calendar epoch actually begins in 1609. But.. the Mars Sol Date, which is unofficial but even used in NASA’s Mars24 program, has its “0” date at Dec 29 1873. So we need to subtract to make up for the difference.
If you use dates before MSD 0, you get negative mars_time_t values.
I couldn’t figure out what the epoch meant, until I realized it was just MSD 0. I also found that marsclock.com’s “midday” is actually off by about 177 seconds. But I calculated MSD 0 to be what you see in the code (I need to save characters so I can submit this), and off I went.
Testcases
Yeah, this needs tests. Even more than what I put in for this devlog (MSD 0 and Unix Epoch 0).
Unfortunately in Mars -> Earth time, I am losing about an Earth second in conversion. I’ll try to debug this now. But it causes some tests, like the epoch to be incorrect - it returns a mars_time_t of what would be unix epoch -1.
Overall thoughts
The genius of how Glibc handles the months was probably the coolest part. Most challenging, the leap year intercalation for sure.
Now, onto more test suites, and more functions.